tor-browser

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

test_ext_tabs_events.html (9409B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <meta charset="utf-8">
      5  <title>Tabs Events Test</title>
      6  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
      7  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
      8  <script type="text/javascript" src="head.js"></script>
      9  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
     10 </head>
     11 <body>
     12 
     13 <script type="text/javascript">
     14 "use strict";
     15 
     16 add_task(async function testTabEvents() {
     17  async function background() {
     18    const events = [];
     19    let eventPromise;
     20    const checkEvents = () => {
     21      if (eventPromise && events.length >= eventPromise.names.length) {
     22        eventPromise.resolve();
     23      }
     24    };
     25 
     26    browser.tabs.onCreated.addListener(tab => {
     27      events.push({type: "onCreated", tab});
     28      checkEvents();
     29    });
     30 
     31    browser.tabs.onAttached.addListener((tabId, info) => {
     32      events.push(Object.assign({type: "onAttached", tabId}, info));
     33      checkEvents();
     34    });
     35 
     36    browser.tabs.onDetached.addListener((tabId, info) => {
     37      events.push(Object.assign({type: "onDetached", tabId}, info));
     38      checkEvents();
     39    });
     40 
     41    browser.tabs.onRemoved.addListener((tabId, info) => {
     42      events.push(Object.assign({type: "onRemoved", tabId}, info));
     43      checkEvents();
     44    });
     45 
     46    browser.tabs.onMoved.addListener((tabId, info) => {
     47      events.push(Object.assign({type: "onMoved", tabId}, info));
     48      checkEvents();
     49    });
     50 
     51    async function expectEvents(names) {
     52      browser.test.log(`Expecting events: ${names.join(", ")}`);
     53 
     54      await new Promise(resolve => {
     55        eventPromise = {names, resolve};
     56        checkEvents();
     57      });
     58 
     59      browser.test.assertEq(names.length, events.length, "Got expected number of events");
     60      for (const [i, name] of names.entries()) {
     61        browser.test.assertEq(name, i in events && events[i].type,
     62                              `Got expected ${name} event`);
     63      }
     64      return events.splice(0);
     65    }
     66 
     67    try {
     68      browser.test.log("Create tab");
     69      const tab = await browser.tabs.create({url: "about:blank"});
     70      const oldIndex = tab.index;
     71 
     72      const [created] = await expectEvents(["onCreated"]);
     73      browser.test.assertEq(tab.id, created.tab.id, "Got expected tab ID");
     74      browser.test.assertEq(oldIndex, created.tab.index, "Got expected tab index");
     75 
     76 
     77      browser.test.log("Remove tab");
     78      await browser.tabs.remove(tab.id);
     79      const [removed] = await expectEvents(["onRemoved"]);
     80 
     81      browser.test.assertEq(tab.id, removed.tabId, "Expected removed tab ID");
     82      browser.test.assertEq(tab.windowId, removed.windowId, "Expected removed tab window ID");
     83      // Note: We want to test for the actual boolean value false here.
     84      browser.test.assertEq(false, removed.isWindowClosing, "Expected isWindowClosing value");
     85 
     86      browser.test.notifyPass("tabs-events");
     87    } catch (e) {
     88      browser.test.fail(`${e} :: ${e.stack}`);
     89      browser.test.notifyFail("tabs-events");
     90    }
     91  }
     92 
     93  const extension = ExtensionTestUtils.loadExtension({
     94    manifest: {
     95      "permissions": ["tabs"],
     96    },
     97    background,
     98  });
     99 
    100  await extension.startup();
    101  await extension.awaitFinish("tabs-events");
    102  await extension.unload();
    103 });
    104 
    105 add_task(async function testTabRemovalEvent() {
    106  async function background() {
    107    function awaitLoad(tabId) {
    108      return new Promise(resolve => {
    109        browser.tabs.onUpdated.addListener(function listener(tabId_, changed) {
    110          if (tabId == tabId_ && changed.status == "complete") {
    111            browser.tabs.onUpdated.removeListener(listener);
    112            resolve();
    113          }
    114        });
    115      });
    116    }
    117 
    118    chrome.tabs.onRemoved.addListener((tabId) => {
    119      browser.test.log("Make sure the removed tab is not available in the tabs.query callback.");
    120      chrome.tabs.query({}, tabs => {
    121        for (const tab of tabs) {
    122          browser.test.assertTrue(tab.id != tabId, "Tab query should not include removed tabId");
    123        }
    124        browser.test.notifyPass("tabs-events");
    125      });
    126    });
    127 
    128    try {
    129      const url = "http://example.com/mochitest/mobile/shared/components/extensions/test/mochitest/context.html";
    130      const tab = await browser.tabs.create({url: url});
    131      await awaitLoad(tab.id);
    132 
    133      await browser.tabs.remove(tab.id);
    134    } catch (e) {
    135      browser.test.fail(`${e} :: ${e.stack}`);
    136      browser.test.notifyFail("tabs-events");
    137    }
    138  }
    139 
    140  const extension = ExtensionTestUtils.loadExtension({
    141    manifest: {
    142      "permissions": ["tabs"],
    143    },
    144    background,
    145  });
    146 
    147  await extension.startup();
    148  await extension.awaitFinish("tabs-events");
    149  await extension.unload();
    150 });
    151 
    152 add_task(async function testTabActivationEvent() {
    153  // TODO bug 1565536: tabs.onActivated is not supported in GeckoView.
    154  if (true) {
    155    todo(false, "skipping testTabActivationEvent");
    156    return;
    157  }
    158  async function background() {
    159    function makeExpectable() {
    160      let expectation = null, resolver = null;
    161      const expectable = param => {
    162        if (expectation === null) {
    163          browser.test.fail("unexpected call to expectable");
    164        } else {
    165          try {
    166            resolver(expectation(param));
    167          } catch (e) {
    168            resolver(Promise.reject(e));
    169          } finally {
    170            expectation = null;
    171          }
    172        }
    173      };
    174      expectable.expect = e => {
    175        expectation = e;
    176        return new Promise(r => { resolver = r; });
    177      };
    178      return expectable;
    179    }
    180    try {
    181      const listener = makeExpectable();
    182      browser.tabs.onActivated.addListener(listener);
    183 
    184      const [tab0] = await browser.tabs.query({active: true});
    185      const [, tab1] = await Promise.all([
    186        listener.expect(info => {
    187          browser.test.assertEq(tab0.id, info.previousTabId, "Got expected previousTabId");
    188        }),
    189        browser.tabs.create({url: "about:blank"}),
    190      ]);
    191      const [, tab2] = await Promise.all([
    192        listener.expect(info => {
    193          browser.test.assertEq(tab1.id, info.previousTabId, "Got expected previousTabId");
    194        }),
    195        browser.tabs.create({url: "about:blank"}),
    196      ]);
    197 
    198      await Promise.all([
    199        listener.expect(info => {
    200          browser.test.assertEq(tab1.id, info.tabId, "Got expected tabId");
    201          browser.test.assertEq(tab2.id, info.previousTabId, "Got expected previousTabId");
    202        }),
    203        browser.tabs.update(tab1.id, {active: true}),
    204      ]);
    205 
    206      await Promise.all([
    207        listener.expect(info => {
    208          browser.test.assertEq(tab2.id, info.tabId, "Got expected tabId");
    209          browser.test.assertEq(undefined, info.previousTabId, "previousTabId should not be defined when previous tab was closed");
    210        }),
    211        browser.tabs.remove(tab1.id),
    212      ]);
    213 
    214      browser.tabs.onActivated.removeListener(listener);
    215      await browser.tabs.remove(tab2.id);
    216 
    217      browser.test.notifyPass("tabs-events");
    218    } catch (e) {
    219      browser.test.fail(`${e} :: ${e.stack}`);
    220      browser.test.notifyFail("tabs-events");
    221    }
    222  }
    223 
    224  const extension = ExtensionTestUtils.loadExtension({
    225    manifest: {
    226      "permissions": ["tabs"],
    227    },
    228 
    229    background,
    230  });
    231 
    232  await extension.startup();
    233  await extension.awaitFinish("tabs-events");
    234  await extension.unload();
    235 });
    236 
    237 add_task(async function test_tabs_event_page() {
    238  function background() {
    239    const EVENTS = [
    240      "onActivated",
    241      "onRemoved",
    242      "onUpdated",
    243    ];
    244    browser.tabs.onCreated.addListener(() => {
    245      browser.test.sendMessage("onCreated");
    246    });
    247    for (const event of EVENTS) {
    248      browser.tabs[event].addListener(() => {
    249      });
    250    }
    251    browser.test.onMessage.addListener(async msg => {
    252      if (msg === "createTab") {
    253        await browser.tabs.create({url: "about:blank"});
    254      }
    255    });
    256    browser.test.sendMessage("ready");
    257  }
    258 
    259  const apiEvents = ["onActivated", "onCreated", "onRemoved", "onUpdated"];
    260  const apiNs = "tabs";
    261  const extension = ExtensionTestUtils.loadExtension({
    262    manifest: {
    263      browser_specific_settings: { gecko: { id: "eventpage@tabs" } },
    264      "permissions": ["tabs"],
    265      background: { persistent: false },
    266    },
    267    background,
    268  });
    269 
    270  await extension.startup();
    271  info("Wait for event page to be started");
    272  await extension.awaitMessage("ready");
    273  // Sanity check
    274  info("Wait for tabs.onCreated listener call");
    275  extension.sendMessage("createTab");
    276  await extension.awaitMessage("onCreated");
    277 
    278  // on startup, all event listeners should not be primed
    279  await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
    280 
    281  // when the extension is killed, all event listeners should be primed
    282  info("Terminate event page");
    283  await extension.terminateBackground({ disableResetIdleForTest: true });
    284  await assertPersistentListeners(extension, apiNs, apiEvents, { primed: true });
    285 
    286  // on start up again, all event listeners should not be primed
    287  info("Wake up event page on a new tabs.onCreated event");
    288  const newWin = window.open();
    289  info("Wait for event page to be restarted");
    290  await extension.awaitMessage("ready");
    291  info("Wait for the primed tabs.onCreated to be received by the event page");
    292  await extension.awaitMessage("onCreated");
    293  await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
    294 
    295  await extension.unload();
    296  newWin.close();
    297 });
    298 
    299 </script>
    300 
    301 </body>
    302 </html>