tor-browser

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

test_ext_options_ui.html (15649B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <meta charset="utf-8">
      5  <title>PageAction Test</title>
      6  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7  <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
      8  <script type="text/javascript" src="head.js"></script>
      9  <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
     10 </head>
     11 <body>
     12 
     13 <script type="text/javascript">
     14 "use strict";
     15 
     16 async function waitAboutAddonsRendered(addonId) {
     17  await ContentTaskUtils.waitForCondition(() => {
     18    return content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
     19  }, `wait Addon Item for ${addonId} to be rendered`);
     20 }
     21 
     22 async function navigateToAddonDetails(addonId) {
     23  const item = content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
     24  const rect = item.getBoundingClientRect();
     25  const x = rect.left + rect.width / 2;
     26  const y = rect.top + rect.height / 2;
     27  content.window.synthesizeMouseEvent("mousedown", x, y, {}, { toWindow: true });
     28  content.window.synthesizeMouseEvent("mouseup", x, y, {}, { toWindow: true });
     29 }
     30 
     31 async function waitAddonOptionsPage([addonId, expectedText]) {
     32  await ContentTaskUtils.waitForCondition(() => {
     33    const optionsIframe = content.document.querySelector(`#addon-options`);
     34    return optionsIframe && optionsIframe.contentDocument.readyState === "complete" &&
     35           optionsIframe.contentDocument.body.innerText.includes(expectedText);
     36  }, `wait Addon Options ${expectedText} for ${addonId} to be loaded`);
     37 
     38  const optionsIframe = content.document.querySelector(`#addon-options`);
     39 
     40  return {
     41    iframeHeight: optionsIframe.style.height,
     42    documentHeight: optionsIframe.contentDocument.documentElement.scrollHeight,
     43    bodyHeight: optionsIframe.contentDocument.body.scrollHeight,
     44  };
     45 }
     46 
     47 async function clickOnLinkInOptionsPage(selector) {
     48  const optionsIframe = content.document.querySelector(`#addon-options`);
     49  optionsIframe.contentDocument.querySelector(selector).click();
     50 }
     51 
     52 async function clickAddonOptionButton() {
     53  content.document.querySelector(`button#open-addon-options`).click();
     54 }
     55 
     56 async function navigateBack() {
     57  content.window.history.back();
     58 }
     59 
     60 function waitDOMContentLoaded(checkUrlCb) {
     61  const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
     62 
     63  return new Promise(resolve => {
     64    const listener = (event) => {
     65      if (checkUrlCb(event.target.defaultView.location.href)) {
     66        BrowserApp.deck.removeEventListener("DOMContentLoaded", listener);
     67        resolve();
     68      }
     69    };
     70 
     71    BrowserApp.deck.addEventListener("DOMContentLoaded", listener);
     72  });
     73 }
     74 
     75 function waitAboutAddonsLoaded() {
     76  return waitDOMContentLoaded(url => url === "about:addons");
     77 }
     78 
     79 function clickAddonDisable() {
     80  content.document.querySelector("#disable-btn").click();
     81 }
     82 
     83 function clickAddonEnable() {
     84  content.document.querySelector("#enable-btn").click();
     85 }
     86 
     87 add_task(async function test_options_ui_iframe_height() {
     88  const addonID = "test-options-ui@mozilla.org";
     89 
     90  const extension = ExtensionTestUtils.loadExtension({
     91    useAddonManager: "temporary",
     92    manifest: {
     93      browser_specific_settings: {
     94        gecko: {id: addonID},
     95      },
     96      name: "Options UI Extension",
     97      description: "Longer addon description",
     98      options_ui: {
     99        page: "options.html",
    100      },
    101    },
    102    files: {
    103      // An option page with the document element bigger than the body.
    104      "options.html": `<!DOCTYPE html>
    105        <html>
    106          <head>
    107            <meta charset="utf-8">
    108            <style>
    109              html { height: 500px; border: 1px solid black; }
    110              body { height: 200px; }
    111            </style>
    112          </head>
    113          <body>
    114            <h1>Options page 1</h1>
    115            <a href="options2.html">go to page 2</a>
    116          </body>
    117        </html>
    118      `,
    119      // A second option page with the body element bigger than the document.
    120      "options2.html": `<!DOCTYPE html>
    121        <html>
    122          <head>
    123            <meta charset="utf-8">
    124            <style>
    125              html { height: 200px; border: 1px solid black; }
    126              body { height: 350px; }
    127            </style>
    128          </head>
    129          <body>
    130            <h1>Options page 2</h1>
    131          </body>
    132        </html>
    133      `,
    134    },
    135  });
    136 
    137  await extension.startup();
    138 
    139  const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
    140 
    141  const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
    142 
    143  BrowserApp.addTab("about:addons", {
    144    selected: true,
    145    parentId: BrowserApp.selectedTab.id,
    146  });
    147 
    148  await onceAboutAddonsLoaded;
    149 
    150  is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
    151     "about:addons is the currently selected tab");
    152 
    153  await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [addonID], waitAboutAddonsRendered);
    154 
    155  await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [addonID], navigateToAddonDetails);
    156 
    157  const optionsSizes = await SpecialPowers.spawn(
    158    BrowserApp.selectedTab.browser, [[addonID, "Options page 1"]], waitAddonOptionsPage
    159  );
    160 
    161  ok(parseInt(optionsSizes.iframeHeight, 10) >= 500,
    162     "The addon options iframe is at least 500px");
    163 
    164  is(optionsSizes.iframeHeight, optionsSizes.documentHeight + "px",
    165     "The addon options iframe has the expected height");
    166 
    167  await SpecialPowers.spawn(BrowserApp.selectedTab.browser, ["a"], clickOnLinkInOptionsPage);
    168 
    169  const options2Sizes = await SpecialPowers.spawn(
    170    BrowserApp.selectedTab.browser, [[addonID, "Options page 2"]], waitAddonOptionsPage
    171  );
    172 
    173  // The second option page has a body bigger than the document element
    174  // and we expect the iframe to be bigger than that.
    175  ok(parseInt(options2Sizes.iframeHeight, 10) > 200,
    176     `The iframe is bigger then 200px (${options2Sizes.iframeHeight})`);
    177 
    178  // The second option page has a body smaller than the document element of the first
    179  // page and we expect the iframe to be smaller than for the previous options page.
    180  ok(parseInt(options2Sizes.iframeHeight, 10) < 500,
    181     `The iframe is smaller then 500px (${options2Sizes.iframeHeight})`);
    182 
    183  is(options2Sizes.iframeHeight, options2Sizes.documentHeight + "px",
    184     "The second addon options page has the expected height");
    185 
    186  await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [], navigateBack);
    187 
    188  const backToOptionsSizes =  await SpecialPowers.spawn(
    189    BrowserApp.selectedTab.browser, [[addonID, "Options page 1"]], waitAddonOptionsPage
    190  );
    191 
    192  // After going back to the first options page,
    193  // we expect the iframe to have the same size of the previous load.
    194  is(backToOptionsSizes.iframeHeight, optionsSizes.iframeHeight,
    195     `When navigating back, the old iframe size is restored (${backToOptionsSizes.iframeHeight})`);
    196 
    197  BrowserApp.closeTab(BrowserApp.selectedTab);
    198 
    199  await extension.unload();
    200 });
    201 
    202 add_task(async function test_options_ui_open_aboutaddons_details() {
    203  const addonID = "test-options-ui-open-addon-details@mozilla.org";
    204 
    205  function background() {
    206    browser.test.onMessage.addListener(msg => {
    207      if (msg !== "runtime.openOptionsPage") {
    208        browser.test.fail(`Received unexpected test message: ${msg}`);
    209        return;
    210      }
    211 
    212      browser.runtime.openOptionsPage();
    213    });
    214  }
    215 
    216  function optionsScript() {
    217    browser.test.sendMessage("options-page-loaded", window.location.href);
    218  }
    219 
    220  const extension = ExtensionTestUtils.loadExtension({
    221    useAddonManager: "temporary",
    222    background,
    223    manifest: {
    224      browser_specific_settings: {
    225        gecko: {id: addonID},
    226      },
    227      name: "Options UI open addon details Extension",
    228      description: "Longer addon description",
    229      options_ui: {
    230        page: "options.html",
    231      },
    232    },
    233    files: {
    234      "options.js": optionsScript,
    235      "options.html": `<!DOCTYPE html>
    236        <html>
    237          <head>
    238            <meta charset="utf-8">
    239          </head>
    240          <body>
    241            <h1>Options page</h1>
    242            <script src="options.js"><\/script>
    243          </body>
    244        </html>
    245      `,
    246    },
    247  });
    248 
    249  await extension.startup();
    250 
    251  const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
    252 
    253  const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
    254 
    255  BrowserApp.addTab("about:addons", {
    256    selected: true,
    257    parentId: BrowserApp.selectedTab.id,
    258  });
    259 
    260  await onceAboutAddonsLoaded;
    261 
    262  is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
    263     "about:addons is the currently selected tab");
    264 
    265  info("Wait runtime.openOptionsPage to open the about:addond details in the existent tab");
    266  extension.sendMessage("runtime.openOptionsPage");
    267  await extension.awaitMessage("options-page-loaded");
    268 
    269  is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
    270     "about:addons is still the currently selected tab once the options has been loaded");
    271 
    272  BrowserApp.closeTab(BrowserApp.selectedTab);
    273 
    274  await extension.unload();
    275 });
    276 
    277 add_task(async function test_options_ui_open_in_tab() {
    278  const addonID = "test-options-ui@mozilla.org";
    279 
    280  function background() {
    281    browser.test.onMessage.addListener(msg => {
    282      if (msg !== "runtime.openOptionsPage") {
    283        browser.test.fail(`Received unexpected test message: ${msg}`);
    284        return;
    285      }
    286 
    287      browser.runtime.openOptionsPage();
    288    });
    289  }
    290 
    291  function optionsScript() {
    292    browser.test.sendMessage("options-page-loaded", window.location.href);
    293  }
    294 
    295  const extension = ExtensionTestUtils.loadExtension({
    296    useAddonManager: "temporary",
    297    background,
    298    manifest: {
    299      browser_specific_settings: {
    300        gecko: {id: addonID},
    301      },
    302      name: "Options UI open_in_tab Extension",
    303      description: "Longer addon description",
    304      options_ui: {
    305        page: "options.html",
    306        open_in_tab: true,
    307      },
    308    },
    309    files: {
    310      "options.js": optionsScript,
    311      "options.html": `<!DOCTYPE html>
    312        <html>
    313          <head>
    314            <meta charset="utf-8">
    315          </head>
    316          <body>
    317            <h1>Options page</h1>
    318            <script src="options.js"><\/script>
    319          </body>
    320        </html>
    321      `,
    322    },
    323  });
    324 
    325  await extension.startup();
    326 
    327  const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
    328 
    329  const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
    330 
    331  BrowserApp.selectOrAddTab("about:addons", {
    332    selected: true,
    333    parentId: BrowserApp.selectedTab.id,
    334  });
    335 
    336  await onceAboutAddonsLoaded;
    337 
    338  const aboutAddonsTab = BrowserApp.selectedTab;
    339 
    340  is(aboutAddonsTab.currentURI.spec, "about:addons",
    341     "about:addons is the currently selected tab");
    342 
    343  await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], waitAboutAddonsRendered);
    344  await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], navigateToAddonDetails);
    345 
    346  const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
    347 
    348  info("Click the Options button in the addon details");
    349  await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonOptionButton);
    350 
    351  info("Waiting that the addon options are loaded in a new tab");
    352  await onceAddonOptionsLoaded;
    353 
    354  const addonOptionsTab = BrowserApp.selectedTab;
    355 
    356  ok(aboutAddonsTab.id !== addonOptionsTab.id,
    357     "The Addon Options page has been loaded in a new tab");
    358 
    359  let optionsURL = await extension.awaitMessage("options-page-loaded");
    360 
    361  is(addonOptionsTab.currentURI.spec, optionsURL,
    362     "Got the expected extension url opened in the addon options tab");
    363 
    364  const waitTabClosed = (nativeTab) => {
    365    return new Promise(resolve => {
    366      const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
    367      const expectedBrowser = nativeTab.browser;
    368 
    369      const tabCloseListener = (event) => {
    370        const browser = event.target;
    371        if (browser !== expectedBrowser) {
    372          return;
    373        }
    374 
    375        BrowserApp.deck.removeEventListener("TabClose", tabCloseListener);
    376        resolve();
    377      };
    378 
    379      BrowserApp.deck.addEventListener("TabClose", tabCloseListener);
    380    });
    381  };
    382 
    383  const onceOptionsTabClosed = waitTabClosed(addonOptionsTab);
    384  const onceAboutAddonsClosed = waitTabClosed(aboutAddonsTab);
    385 
    386  info("Close the opened about:addons and options tab");
    387  BrowserApp.closeTab(addonOptionsTab);
    388  BrowserApp.closeTab(aboutAddonsTab);
    389 
    390  info("Wait the tabs to be closed");
    391  await Promise.all([onceOptionsTabClosed, onceAboutAddonsClosed]);
    392 
    393  const oldSelectedTab = BrowserApp.selectedTab;
    394  info("Call runtime.openOptionsPage");
    395  extension.sendMessage("runtime.openOptionsPage");
    396 
    397  info("Wait runtime.openOptionsPage to open the options in a new tab");
    398  optionsURL = await extension.awaitMessage("options-page-loaded");
    399  is(BrowserApp.selectedTab.currentURI.spec, optionsURL,
    400     "runtime.openOptionsPage has opened the expected extension page");
    401  ok(BrowserApp.selectedTab !== oldSelectedTab,
    402     "runtime.openOptionsPage has opened a new tab");
    403 
    404  BrowserApp.closeTab(BrowserApp.selectedTab);
    405 
    406  await extension.unload();
    407 });
    408 
    409 add_task(async function test_options_ui_on_disable_and_enable() {
    410  // Temporarily disabled for races.
    411  /* eslint-disable no-unreachable */
    412  return;
    413 
    414  const addonID = "test-options-ui-disable-enable@mozilla.org";
    415 
    416  function optionsScript() {
    417    browser.test.sendMessage("options-page-loaded", window.location.href);
    418  }
    419 
    420  const extension = ExtensionTestUtils.loadExtension({
    421    useAddonManager: "temporary",
    422    manifest: {
    423      browser_specific_settings: {
    424        gecko: {id: addonID},
    425      },
    426      name: "Options UI open addon details Extension",
    427      description: "Longer addon description",
    428      options_ui: {
    429        page: "options.html",
    430      },
    431    },
    432    files: {
    433      "options.js": optionsScript,
    434      "options.html": `<!DOCTYPE html>
    435       <html>
    436         <head>
    437           <meta charset="utf-8">
    438         </head>
    439         <body>
    440           <h1>Options page</h1>
    441           <script src="options.js"><\/script>
    442         </body>
    443       </html>
    444     `,
    445    },
    446  });
    447 
    448  await extension.startup();
    449 
    450  const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
    451 
    452  const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
    453 
    454  BrowserApp.addTab("about:addons", {
    455    selected: true,
    456    parentId: BrowserApp.selectedTab.id,
    457  });
    458 
    459  await onceAboutAddonsLoaded;
    460 
    461  const aboutAddonsTab = BrowserApp.selectedTab;
    462 
    463  is(aboutAddonsTab.currentURI.spec, "about:addons",
    464     "about:addons is the currently selected tab");
    465 
    466  info("Wait the addon details to have been loaded");
    467  await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], waitAboutAddonsRendered);
    468  await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], navigateToAddonDetails);
    469 
    470  info("Wait the addon options page to have been loaded");
    471  await extension.awaitMessage("options-page-loaded");
    472 
    473  info("Click the addon disable button");
    474  await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonDisable);
    475 
    476  // NOTE: Currently after disabling the addon the extension.awaitMessage seems
    477  // to fail be able to receive events coming from the browser.test.sendMessage API
    478  // (nevertheless `await extension.unload()` seems to be able to remove the extension),
    479  // falling back to wait for the options page to be loaded here.
    480  const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
    481 
    482  info("Click the addon enable button");
    483  await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonEnable);
    484 
    485  info("Wait the addon options page to have been loaded after clicking the addon enable button");
    486  await onceAddonOptionsLoaded;
    487 
    488  BrowserApp.closeTab(BrowserApp.selectedTab);
    489 
    490  await extension.unload();
    491 });
    492 
    493 </script>
    494 
    495 </body>
    496 </html>