summaryrefslogtreecommitdiffstats
path: root/devtools/shared/webconsole/test/chrome/test_console_serviceworker.html
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/webconsole/test/chrome/test_console_serviceworker.html')
-rw-r--r--devtools/shared/webconsole/test/chrome/test_console_serviceworker.html212
1 files changed, 212 insertions, 0 deletions
diff --git a/devtools/shared/webconsole/test/chrome/test_console_serviceworker.html b/devtools/shared/webconsole/test/chrome/test_console_serviceworker.html
new file mode 100644
index 0000000000..4cb6332abd
--- /dev/null
+++ b/devtools/shared/webconsole/test/chrome/test_console_serviceworker.html
@@ -0,0 +1,212 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+ <meta charset="utf8">
+ <title>Test for the Console API and Service Workers</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="common.js"></script>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for the Console API and Service Workers</p>
+
+<script class="testbody" type="text/javascript">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+// Utils functions
+function withFrame(url) {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ iframe.onload = function () {
+ resolve(iframe);
+ };
+ iframe.src = url;
+ document.body.appendChild(iframe);
+ });
+}
+
+function navigateFrame(iframe, url) {
+ return new Promise(resolve => {
+ iframe.onload = function () {
+ resolve(iframe);
+ };
+ iframe.src = url;
+ });
+}
+
+function forceReloadFrame(iframe) {
+ return new Promise(resolve => {
+ iframe.onload = function () {
+ resolve(iframe);
+ };
+ iframe.contentWindow.location.reload(true);
+ });
+}
+
+function messageServiceWorker(win, scope, message) {
+ return win.navigator.serviceWorker.getRegistration(scope).then(swr => {
+ return new Promise(resolve => {
+ win.navigator.serviceWorker.onmessage = evt => {
+ resolve();
+ };
+ const sw = swr.active || swr.waiting || swr.installing;
+ sw.postMessage({ type: "PING", message });
+ });
+ });
+}
+
+function unregisterServiceWorker(win) {
+ return win.navigator.serviceWorker.ready.then(swr => {
+ return swr.unregister();
+ });
+}
+
+// Test
+const BASE_URL = "https://example.com/chrome/devtools/shared/webconsole/test/chrome/";
+const SERVICE_WORKER_URL = BASE_URL + "helper_serviceworker.js";
+const SCOPE = BASE_URL + "foo/";
+const NONSCOPE_FRAME_URL = BASE_URL + "sandboxed_iframe.html";
+const SCOPE_FRAME_URL = SCOPE + "fake.html";
+const SCOPE_FRAME_URL2 = SCOPE + "whatsit.html";
+const MESSAGE = 'Tic Tock';
+
+const expectedConsoleCalls = [
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ arguments: ['script evaluation'],
+ },
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ // Note that the second argument isn't a SharedArrayBuffer, but a DevTools "Object Front" instance.
+ arguments: ['Here is a SAB', { class : "SharedArrayBuffer" }],
+ },
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ arguments: ['install event'],
+ },
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ arguments: ['activate event'],
+ },
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ arguments: ['fetch event: ' + SCOPE_FRAME_URL],
+ },
+ {
+ level: "log",
+ filename: /helper_serviceworker/,
+ arguments: ['fetch event: ' + SCOPE_FRAME_URL2],
+ },
+];
+let consoleCalls = [];
+
+const startTest = async function () {
+ removeEventListener("load", startTest);
+
+ await new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.enabled", true],
+ ["devtools.webconsole.filter.serviceworkers", true],
+ [
+ "dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
+ true
+ ],
+ ]}, resolve);
+ });
+
+ const {state, response} = await attachConsoleToTab(["ConsoleAPI"]);
+ onAttach(state, response);
+};
+addEventListener("load", startTest);
+
+const onAttach = async function (state, response) {
+ onConsoleAPICall = onConsoleAPICall.bind(null, state);
+ state.webConsoleFront.on("consoleAPICall", onConsoleAPICall);
+
+ let currentFrame;
+ try {
+ // First, we need a frame from which to register our script. This
+ // will not trigger any console calls.
+ info("Loading a non-scope frame from which to register a service worker.");
+ currentFrame = await withFrame(NONSCOPE_FRAME_URL);
+
+ // Now register the service worker and wait for it to become
+ // activate. This should trigger 3 console calls; 1 for script
+ // evaluation, 1 for the install event, and 1 for the activate
+ // event. These console calls are received because we called
+ // register(), not because we are in scope for the worker.
+ info("Registering the service worker");
+ await withActiveServiceWorker(currentFrame.contentWindow,
+ SERVICE_WORKER_URL, SCOPE);
+ ok(!currentFrame.contentWindow.navigator.serviceWorker.controller,
+ 'current frame should not be controlled');
+
+ // Now that the service worker is activate, lets navigate our frame.
+ // This will trigger 1 more console call for the fetch event.
+ info("Service worker registered. Navigating frame.");
+ await navigateFrame(currentFrame, SCOPE_FRAME_URL);
+ ok(currentFrame.contentWindow.navigator.serviceWorker.controller,
+ 'navigated frame should be controlled');
+
+ // We now have a controlled frame. Lets perform a non-navigation fetch.
+ // This should produce another console call for the fetch event.
+ info("Frame navigated. Calling fetch().");
+ await currentFrame.contentWindow.fetch(SCOPE_FRAME_URL2);
+
+ // Now force refresh our controlled frame. This will cause the frame
+ // to bypass the service worker and become an uncontrolled frame. It
+ // also happens to make the frame display a 404 message because the URL
+ // does not resolve to a real resource. This is ok, as we really only
+ // care about the frame being non-controlled, but still having a location
+ // that matches our service worker scope so we can provide its not
+ // incorrectly getting console calls.
+ info("Completed fetch(). Force refreshing to get uncontrolled frame.");
+ await forceReloadFrame(currentFrame);
+ ok(!currentFrame.contentWindow.navigator.serviceWorker.controller,
+ 'current frame should not be controlled after force refresh');
+ is(currentFrame.contentWindow.location.toString(), SCOPE_FRAME_URL,
+ 'current frame should still have in-scope location URL even though it got 404');
+
+ // Now postMessage() the service worker to trigger its message event
+ // handler. This will generate 1 or 2 to console.log() statements
+ // depending on if the worker thread needs to spin up again. In either
+ // case, though, we should not get any console calls because we don't
+ // have a controlled or registering document.
+ info("Completed force refresh. Messaging service worker.");
+ await messageServiceWorker(currentFrame.contentWindow, SCOPE, MESSAGE);
+
+ info("Done messaging service worker. Unregistering service worker.");
+ await unregisterServiceWorker(currentFrame.contentWindow);
+
+ info('Service worker unregistered. Checking console calls.');
+ state.webConsoleFront.off("consoleAPICall", onConsoleAPICall);
+ checkConsoleAPICalls(consoleCalls, expectedConsoleCalls);
+ } catch(error) {
+ ok(false, 'unexpected error: ' + error);
+ } finally {
+ if (currentFrame) {
+ currentFrame.remove();
+ currentFrame = null;
+ }
+ consoleCalls = [];
+ closeDebugger(state, function() {
+ SimpleTest.finish();
+ });
+ }
+};
+
+function onConsoleAPICall(state, packet) {
+ info("received message level: " + packet.message.level);
+ consoleCalls.push(packet.message);
+}
+</script>
+</body>
+</html>