diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/shared/webconsole/test/chrome/test_console_serviceworker.html | 202 |
1 files changed, 202 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..33b6ba1457 --- /dev/null +++ b/devtools/shared/webconsole/test/chrome/test_console_serviceworker.html @@ -0,0 +1,202 @@ +<!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/, + 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] + ]}, 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> |