1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 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: 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>
|