<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf8"> <title>Test for the Console API and Service Workers</title> <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript;version=1.8" 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;version=1.8"> SimpleTest.waitForExplicitFinish(); let BASE_URL = "https://example.com/chrome/devtools/shared/webconsole/test/"; let SERVICE_WORKER_URL = BASE_URL + "helper_serviceworker.js"; let SCOPE = BASE_URL + "foo/"; let NONSCOPE_FRAME_URL = BASE_URL + "sandboxed_iframe.html"; let SCOPE_FRAME_URL = SCOPE + "fake.html"; let SCOPE_FRAME_URL2 = SCOPE + "whatsit.html"; let MESSAGE = 'Tic Tock'; let 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], }, { level: "log", filename: /helper_serviceworker/, arguments: ['message event: ' + MESSAGE], }, ]; let consoleCalls = []; let startTest = Task.async(function*() { removeEventListener("load", startTest); yield new Promise(resolve => { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.enabled", true], ["devtools.webconsole.filter.serviceworkers", true] ]}, resolve); }); attachConsoleToTab(["ConsoleAPI"], onAttach); }); addEventListener("load", startTest); let onAttach = Task.async(function*(state, response) { onConsoleAPICall = onConsoleAPICall.bind(null, state); state.dbgClient.addListener("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 = yield 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"); yield 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."); yield 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()."); yield 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."); yield 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. Although we // don't have a controlled or registering document in both cases, we still // could get console calls since we only flush reports when the channel is // finally destroyed. info("Completed force refresh. Messaging service worker."); yield messageServiceWorker(currentFrame.contentWindow, SCOPE, MESSAGE); info("Done messaging service worker. Unregistering service worker."); yield unregisterServiceWorker(currentFrame.contentWindow); info('Service worker unregistered. Checking console calls.'); state.dbgClient.removeListener("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, type, packet) { info("received message level: " + packet.message.level); is(packet.from, state.actor, "console API call actor"); consoleCalls.push(packet.message); } </script> </body> </html>