forked from mirrors/gecko-dev
Differential Revision: https://phabricator.services.mozilla.com/D51090 --HG-- extra : moz-landing-system : lando
201 lines
6.8 KiB
HTML
201 lines
6.8 KiB
HTML
<!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/";
|
|
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);
|
|
});
|
|
|
|
attachConsoleToTab(["ConsoleAPI"], onAttach);
|
|
};
|
|
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>
|