tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_menu_message.html (11681B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <meta charset="utf-8">
      5  <title>Tests for the FxA Menu Message component</title>
      6  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7  <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
      8  <script
      9  src="chrome://browser/content/asrouter/components/menu-message.mjs"
     10  type="module"
     11 ></script>
     12  <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
     13  <script>
     14    const { BrowserTestUtils } = ChromeUtils.importESModule(
     15      "resource://testing-common/BrowserTestUtils.sys.mjs"
     16    );
     17 
     18    /**
     19     * Tests that the exposed properties of the component are reflected
     20     * as expected in the shadow DOM.
     21     */
     22    add_task(async function test_exposed_properties() {
     23      let message = document.createElement("menu-message");
     24      const TEST_IMAGE_URL = "chrome://activity-stream/content/data/content/assets/fox-doodle-waving-static.png";
     25      message.imageURL = TEST_IMAGE_URL;
     26      const TEST_LOGO_URL = "chrome://branding/content/about-logo.svg";
     27      message.logoURL = TEST_LOGO_URL;
     28      const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!";
     29      message.buttonText = TEST_BUTTON_TEXT;
     30      const PRIMARY_TEXT = "This is the primary text";
     31      message.primaryText = PRIMARY_TEXT;
     32      const SECONDARY_TEXT = "This is the secondary text";
     33      message.secondaryText = SECONDARY_TEXT;
     34 
     35      let content = document.getElementById("content");
     36      content.appendChild(message);
     37      await message.updateComplete;
     38 
     39      let shadow = message.shadowRoot;
     40      let image = shadow.querySelector("#illustration");
     41      is(image.src, TEST_IMAGE_URL, "The illustration img element got the expected URL");
     42 
     43      let logo = shadow.querySelector("#logo");
     44      is(logo.src, TEST_LOGO_URL, "The logo element got the expected URL");
     45 
     46      let button = shadow.querySelector("#primary-button");
     47      is(button.textContent.trim(), TEST_BUTTON_TEXT, "The primary button got the right text.");
     48 
     49      let primaryText = shadow.querySelector("#primary");
     50      is(primaryText.textContent, PRIMARY_TEXT, "The primary text was correct.");
     51 
     52      let secondaryText = shadow.querySelector("#secondary");
     53      is(secondaryText.textContent, SECONDARY_TEXT, "The secondary text was correct.");
     54 
     55      let container = shadow.querySelector("#container");
     56      is(container.getAttribute("layout"), "column", "The layout should default to 'column' when no layout is explicitly set.");
     57 
     58      const TEST_ROW_LAYOUT = "row";
     59      message.layout = TEST_ROW_LAYOUT
     60      await message.updateComplete;
     61      is(container.getAttribute("layout"), TEST_ROW_LAYOUT, "The layout attribute should update to 'row' when set.");
     62 
     63      message.remove();
     64    });
     65 
     66    /**
     67     * Tests that the buttons exposed by the component emit the expected
     68     * events.
     69     */
     70    add_task(async function test_button_properties() {
     71      let message = document.createElement("menu-message");
     72      const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!";
     73      message.buttonText = TEST_BUTTON_TEXT;
     74 
     75      let content = document.getElementById("content");
     76      content.appendChild(message);
     77      await message.updateComplete;
     78 
     79      let shadow = message.shadowRoot;
     80 
     81      let primaryEventPromise = BrowserTestUtils.waitForEvent(message, "MenuMessage:PrimaryButton");
     82      let primaryButton = shadow.querySelector("#primary-button");
     83      primaryButton.click();
     84      await primaryEventPromise;
     85      ok(true, "Got the MenuMessage:PrimaryButton event");
     86 
     87      let closeEventPromise = BrowserTestUtils.waitForEvent(message, "MenuMessage:Close");
     88      let closeButton = shadow.querySelector("#close-button");
     89      closeButton.click();
     90      await closeEventPromise;
     91      ok(true, "Got the MenuMessage:Close event");
     92 
     93      message.remove();
     94    });
     95 
     96    /**
     97     * Tests that the primary button is focused by default, and that focus
     98     * can be changed via the keyboard.
     99     */
    100    add_task(async function test_primary_button_focus() {
    101      let message = document.createElement("menu-message");
    102      const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!";
    103      message.buttonText = TEST_BUTTON_TEXT;
    104 
    105      let content = document.getElementById("content");
    106      content.appendChild(message);
    107      await message.updateComplete;
    108 
    109      message.focus();
    110 
    111      let shadow = message.shadowRoot;
    112      let primaryButton = shadow.querySelector("#primary-button");
    113      is(shadow.activeElement, primaryButton, "primary button is focused by default.");
    114 
    115      let closeButton = shadow.querySelector("#close-button");
    116      const FOCUS_CHANGING_KEYS = [
    117        "ArrowLeft",
    118        "ArrowRight",
    119        "ArrowUp",
    120        "ArrowDown",
    121      ];
    122 
    123      for (let keyName of FOCUS_CHANGING_KEYS) {
    124        synthesizeKey(`KEY_${keyName}`);
    125        // Now the close button should be focused.
    126        is(shadow.activeElement, closeButton, "Close button is now focused.");
    127 
    128        synthesizeKey(`KEY_${keyName}`);
    129        // And pressing the same key should swap focus back to the primary
    130        // button.
    131        is(shadow.activeElement, primaryButton, "primary button is now focused.");
    132      }
    133 
    134      message.remove();
    135    });
    136 
    137    /**
    138     * Tests that setting no imageURL makes it so that the image element is
    139     * not visible, and setting one makes it visible.
    140     */
    141    add_task(async function test_image_visibility() {
    142      let message = document.createElement("menu-message");
    143      const TEST_BUTTON_TEXT = "Howdy, partner! Sign up!";
    144      message.buttonText = TEST_BUTTON_TEXT;
    145 
    146      let content = document.getElementById("content");
    147      content.appendChild(message);
    148      await message.updateComplete;
    149 
    150      let illustrationContainer = message.shadowRoot.querySelector("#illustration-container");
    151      ok(isHidden(illustrationContainer), "Illustration container should be hidden.");
    152 
    153      message.imageURL = "some-image.png";
    154      await message.updateComplete;
    155      ok(!isHidden(illustrationContainer), "Illustration container should be visible.");
    156 
    157      message.remove();
    158    });
    159 
    160    async function testIllustrationOffset({
    161      layout,
    162      offsetVar,
    163      cssProperty,
    164      checkContainerOffset = false,
    165    }) {
    166      const TEST_DEFAULT_VALUE = "0px";
    167      const TEST_CONTAINER_OFFSET = "10px";
    168      const TEST_ILLUSTRATION_OFFSET = "123px";
    169      const TEST_IMAGE_URL =
    170        "chrome://activity-stream/content/data/content/assets/fox-doodle-waving-static.png";
    171 
    172      let message = document.createElement("menu-message");
    173      message.imageURL = TEST_IMAGE_URL;
    174      if (layout) {
    175        message.layout = layout;
    176      }
    177 
    178      document.getElementById("content").appendChild(message);
    179      await message.updateComplete;
    180 
    181      let illustrationContainer = message.shadowRoot.querySelector(
    182        "#illustration-container"
    183      );
    184      ok(
    185        !isHidden(illustrationContainer),
    186        "Illustration container should not be hidden."
    187      );
    188 
    189      let computedStyle = window.getComputedStyle(illustrationContainer);
    190      is(
    191        computedStyle[cssProperty],
    192        TEST_DEFAULT_VALUE,
    193        "Illustration offset should default to 0px"
    194      );
    195 
    196      message.style.setProperty(offsetVar, TEST_ILLUSTRATION_OFFSET);
    197      computedStyle = window.getComputedStyle(illustrationContainer);
    198      is(
    199        computedStyle[cssProperty],
    200        TEST_ILLUSTRATION_OFFSET,
    201        "Illustration offset should have been forwarded to the container."
    202      );
    203 
    204      if (checkContainerOffset) {
    205        const container = message.shadowRoot.querySelector("#container");
    206        let containerStyle = window.getComputedStyle(container);
    207        is(
    208          containerStyle.marginBlockEnd,
    209          TEST_DEFAULT_VALUE,
    210          "Container offset should default to 0px."
    211        );
    212        message.style.setProperty(
    213          "--container-margin-block-end-offset",
    214          TEST_CONTAINER_OFFSET
    215        );
    216        containerStyle = window.getComputedStyle(container);
    217        is(
    218          containerStyle.marginBlockEnd,
    219          TEST_CONTAINER_OFFSET,
    220          "Container offset should have been applied."
    221        );
    222      }
    223      message.remove();
    224    }
    225 
    226    /**
    227     * Tests that setting the --illustration-margin-block-start-offset forwards that
    228     * offset to the illustration container for 'column' layout.
    229     */
    230    add_task(async function test_column_layout_illustration_offset() {
    231      await testIllustrationOffset({
    232        layout: null,
    233        offsetVar: "--illustration-margin-block-start-offset",
    234        cssProperty: "marginBlockStart",
    235      });
    236    });
    237 
    238    /**
    239     * Tests that setting the --illustration-margin-block-end-offset forwards that
    240     * offset to the illustration container for 'row' layout.
    241     */
    242    add_task(async function test_row_layout_illustration_offset() {
    243      await testIllustrationOffset({
    244        layout: "row",
    245        offsetVar: "--illustration-margin-block-end-offset",
    246        cssProperty: "marginBlockEnd",
    247        checkContainerOffset: true,
    248      });
    249    });
    250 
    251    /**
    252     * Tests that the primary button supports a 'small' size and defaults to 'default'.
    253     */
    254     add_task(async function test_primary_button_size() {
    255      let message = document.createElement("menu-message");
    256      message.buttonText = "Test button";
    257      document.getElementById("content").appendChild(message);
    258      await message.updateComplete;
    259 
    260      let shadow = message.shadowRoot;
    261      let btn = shadow.querySelector("#primary-button");
    262      is(btn.getAttribute("size"), "default", "Button size defaults to 'default'.");
    263 
    264      message.primaryButtonSize = "small";
    265      await message.updateComplete;
    266      is(btn.getAttribute("size"), "small", "Button size updates to 'small'.");
    267 
    268      message.remove();
    269    });
    270 
    271    /**
    272     * Tests "simple" layout, which only displays primary text and primary button.
    273     */
    274    add_task(async function test_simple_layout() {
    275      let message = document.createElement("menu-message");
    276      message.layout = "simple";
    277      message.buttonText = "Set as default";
    278      message.primaryText = "Firefox is not your default browser";
    279      message.secondaryText = "You should not see me!";
    280      // Provide URLs to ensure images exist but are hidden by the CSS
    281      message.logoURL = "chrome://branding/content/about-logo.svg";
    282      message.imageURL =
    283        "chrome://browser/content/asrouter/assets/fox-with-devices.svg";
    284 
    285      document.getElementById("content").appendChild(message);
    286      await message.updateComplete;
    287      const shadow = message.shadowRoot;
    288      const container = shadow.querySelector("#container");
    289      is(
    290        container.getAttribute("layout"),
    291        "simple",
    292        "Layout for container is 'simple'."
    293      );
    294 
    295      const primary = shadow.querySelector("#primary");
    296      ok(!isHidden(primary), "Primary text is visible.");
    297      const btn = shadow.querySelector("#primary-button");
    298      ok(!isHidden(btn), "Primary button is visible.");
    299 
    300      const closeBtn = shadow.querySelector("#close-button");
    301      is(
    302        getComputedStyle(closeBtn).display,
    303        "none",
    304        "Close button is hidden."
    305      );
    306 
    307      const secondary = shadow.querySelector("#secondary");
    308      is(
    309        getComputedStyle(secondary).display,
    310        "none",
    311        "Secondary text is hidden."
    312      );
    313 
    314      for (const img of shadow.querySelectorAll("img")) {
    315        is(
    316          getComputedStyle(img).display,
    317          "none",
    318          "Images are hidden."
    319        );
    320      }
    321      message.remove();
    322    });
    323  </script>
    324 </head>
    325 <body>
    326 <p id="display"></p>
    327 <div id="content"></div>
    328 <pre id="test"></pre>
    329 </body>
    330 </html>