tor-browser

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

test_console_serviceworker.html (7346B)


      1 <!DOCTYPE HTML>
      2 <html lang="en">
      3 <head>
      4  <meta charset="utf8">
      5  <title>Test for the Console API and Service Workers</title>
      6  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7  <script type="text/javascript" src="common.js"></script>
      8  <!-- Any copyright is dedicated to the Public Domain.
      9     - http://creativecommons.org/publicdomain/zero/1.0/ -->
     10 </head>
     11 <body>
     12 <p>Test for the Console API and Service Workers</p>
     13 
     14 <script class="testbody" type="text/javascript">
     15 "use strict";
     16 
     17 SimpleTest.waitForExplicitFinish();
     18 
     19 // Utils functions
     20 function withFrame(url) {
     21  return new Promise(resolve => {
     22    const iframe = document.createElement("iframe");
     23    iframe.onload = function () {
     24      resolve(iframe);
     25    };
     26    iframe.src = url;
     27    document.body.appendChild(iframe);
     28  });
     29 }
     30 
     31 function navigateFrame(iframe, url) {
     32  return new Promise(resolve => {
     33    iframe.onload = function () {
     34      resolve(iframe);
     35    };
     36    iframe.src = url;
     37  });
     38 }
     39 
     40 function forceReloadFrame(iframe) {
     41  return new Promise(resolve => {
     42    iframe.onload = function () {
     43      resolve(iframe);
     44    };
     45    iframe.contentWindow.location.reload(true);
     46  });
     47 }
     48 
     49 function messageServiceWorker(win, scope, message) {
     50  return win.navigator.serviceWorker.getRegistration(scope).then(swr => {
     51    return new Promise(resolve => {
     52      win.navigator.serviceWorker.onmessage = () => {
     53        resolve();
     54      };
     55      const sw = swr.active || swr.waiting || swr.installing;
     56      sw.postMessage({ type: "PING", message });
     57    });
     58  });
     59 }
     60 
     61 function unregisterServiceWorker(win) {
     62  return win.navigator.serviceWorker.ready.then(swr => {
     63    return swr.unregister();
     64  });
     65 }
     66 
     67 // Test
     68 const BASE_URL = "https://example.com/chrome/devtools/shared/webconsole/test/chrome/";
     69 const SERVICE_WORKER_URL = BASE_URL + "helper_serviceworker.js";
     70 const SCOPE = BASE_URL + "foo/";
     71 const NONSCOPE_FRAME_URL = BASE_URL + "sandboxed_iframe.html";
     72 const SCOPE_FRAME_URL = SCOPE + "fake.html";
     73 const SCOPE_FRAME_URL2 = SCOPE + "whatsit.html";
     74 const MESSAGE = 'Tic Tock';
     75 
     76 const expectedConsoleCalls = [
     77    {
     78      level: "log",
     79      filename: /helper_serviceworker/,
     80      arguments: ['script evaluation'],
     81    },
     82    {
     83      level: "log",
     84      filename: /helper_serviceworker/,
     85      // Note that the second argument isn't a SharedArrayBuffer, but a DevTools "Object Front" instance.
     86      arguments: ['Here is a SAB', { class : "SharedArrayBuffer" }],
     87    },
     88    {
     89      level: "log",
     90      filename: /helper_serviceworker/,
     91      arguments: ['install event'],
     92    },
     93    {
     94      level: "log",
     95      filename: /helper_serviceworker/,
     96      arguments: ['activate event'],
     97    },
     98    {
     99      level: "log",
    100      filename: /helper_serviceworker/,
    101      arguments: ['fetch event: ' + SCOPE_FRAME_URL],
    102    },
    103    {
    104      level: "log",
    105      filename: /helper_serviceworker/,
    106      arguments: ['fetch event: ' + SCOPE_FRAME_URL2],
    107    },
    108 ];
    109 let consoleCalls = [];
    110 
    111 const startTest = async function () {
    112  removeEventListener("load", startTest);
    113 
    114  await new Promise(resolve => {
    115    SpecialPowers.pushPrefEnv({"set": [
    116      ["dom.serviceWorkers.enabled", true],
    117      ["devtools.webconsole.filter.serviceworkers", true],
    118      [
    119        "dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
    120        true
    121      ],
    122    ]}, resolve);
    123  });
    124 
    125  const {state, response} = await attachConsoleToTab(["ConsoleAPI"]);
    126  onAttach(state, response);
    127 };
    128 addEventListener("load", startTest);
    129 
    130 const onAttach = async function (state) {
    131  onConsoleAPICall = onConsoleAPICall.bind(null, state);
    132  state.webConsoleFront.on("consoleAPICall", onConsoleAPICall);
    133 
    134  let currentFrame;
    135  try {
    136    // First, we need a frame from which to register our script.  This
    137    // will not trigger any console calls.
    138    info("Loading a non-scope frame from which to register a service worker.");
    139    currentFrame = await withFrame(NONSCOPE_FRAME_URL);
    140 
    141    // Now register the service worker and wait for it to become
    142    // activate.  This should trigger 3 console calls; 1 for script
    143    // evaluation, 1 for the install event, and 1 for the activate
    144    // event.  These console calls are received because we called
    145    // register(), not because we are in scope for the worker.
    146    info("Registering the service worker");
    147    await withActiveServiceWorker(currentFrame.contentWindow,
    148                                  SERVICE_WORKER_URL, SCOPE);
    149    ok(!currentFrame.contentWindow.navigator.serviceWorker.controller,
    150       'current frame should not be controlled');
    151 
    152    // Now that the service worker is activate, lets navigate our frame.
    153    // This will trigger 1 more console call for the fetch event.
    154    info("Service worker registered. Navigating frame.");
    155    await navigateFrame(currentFrame, SCOPE_FRAME_URL);
    156    ok(currentFrame.contentWindow.navigator.serviceWorker.controller,
    157       'navigated frame should be controlled');
    158 
    159    // We now have a controlled frame.  Lets perform a non-navigation fetch.
    160    // This should produce another console call for the fetch event.
    161    info("Frame navigated.  Calling fetch().");
    162    await currentFrame.contentWindow.fetch(SCOPE_FRAME_URL2);
    163 
    164    // Now force refresh our controlled frame.  This will cause the frame
    165    // to bypass the service worker and become an uncontrolled frame.  It
    166    // also happens to make the frame display a 404 message because the URL
    167    // does not resolve to a real resource.  This is ok, as we really only
    168    // care about the frame being non-controlled, but still having a location
    169    // that matches our service worker scope so we can provide its not
    170    // incorrectly getting console calls.
    171    info("Completed fetch().  Force refreshing to get uncontrolled frame.");
    172    await forceReloadFrame(currentFrame);
    173    ok(!currentFrame.contentWindow.navigator.serviceWorker.controller,
    174       'current frame should not be controlled after force refresh');
    175    is(currentFrame.contentWindow.location.toString(), SCOPE_FRAME_URL,
    176       'current frame should still have in-scope location URL even though it got 404');
    177 
    178    // Now postMessage() the service worker to trigger its message event
    179    // handler.  This will generate 1 or 2 to console.log() statements
    180    // depending on if the worker thread needs to spin up again.  In either
    181    // case, though, we should not get any console calls because we don't
    182    // have a controlled or registering document.
    183    info("Completed force refresh.  Messaging service worker.");
    184    await messageServiceWorker(currentFrame.contentWindow, SCOPE, MESSAGE);
    185 
    186    info("Done messaging service worker.  Unregistering service worker.");
    187    await unregisterServiceWorker(currentFrame.contentWindow);
    188 
    189    info('Service worker unregistered.  Checking console calls.');
    190    state.webConsoleFront.off("consoleAPICall", onConsoleAPICall);
    191    checkConsoleAPICalls(consoleCalls, expectedConsoleCalls);
    192  } catch(error) {
    193    ok(false, 'unexpected error: ' + error);
    194  } finally {
    195    if (currentFrame) {
    196      currentFrame.remove();
    197      currentFrame = null;
    198    }
    199    consoleCalls = [];
    200    closeDebugger(state, function() {
    201      SimpleTest.finish();
    202    });
    203  }
    204 };
    205 
    206 function onConsoleAPICall(state, packet) {
    207  info("received message level: " + packet.message.level);
    208  consoleCalls.push(packet.message);
    209 }
    210 </script>
    211 </body>
    212 </html>