summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/browser/browser_webextension_inspected_window.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/tests/browser/browser_webextension_inspected_window.js')
-rw-r--r--devtools/server/tests/browser/browser_webextension_inspected_window.js597
1 files changed, 597 insertions, 0 deletions
diff --git a/devtools/server/tests/browser/browser_webextension_inspected_window.js b/devtools/server/tests/browser/browser_webextension_inspected_window.js
new file mode 100644
index 0000000000..9ec089e7a4
--- /dev/null
+++ b/devtools/server/tests/browser/browser_webextension_inspected_window.js
@@ -0,0 +1,597 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_RELOAD_URL = `${MAIN_DOMAIN}/inspectedwindow-reload-target.sjs`;
+
+async function setup(pageUrl) {
+ const extension = ExtensionTestUtils.loadExtension({
+ background() {
+ // This is just an empty extension used to ensure that the caller extension uuid
+ // actually exists.
+ },
+ });
+
+ await extension.startup();
+
+ const fakeExtCallerInfo = {
+ url: WebExtensionPolicy.getByID(extension.id).getURL(
+ "fake-caller-script.js"
+ ),
+ lineNumber: 1,
+ addonId: extension.id,
+ };
+
+ const target = await addTabTarget(pageUrl);
+
+ await target.attach();
+
+ const { client } = target;
+ const webConsoleFront = await target.getFront("console");
+ const inspectedWindowFront = await target.getFront(
+ "webExtensionInspectedWindow"
+ );
+
+ return {
+ client,
+ target,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ };
+}
+
+async function teardown({ client, extension }) {
+ await client.close();
+ DevToolsServer.destroy();
+ gBrowser.removeCurrentTab();
+ await extension.unload();
+}
+
+function waitForNextTabNavigated(target) {
+ return new Promise(resolve => {
+ target.on("tabNavigated", function tabNavigatedListener(pkt) {
+ if (pkt.state == "stop" && !pkt.isFrameSwitching) {
+ target.off("tabNavigated", tabNavigatedListener);
+ resolve();
+ }
+ });
+ });
+}
+
+// Script used as the injectedScript option in the inspectedWindow.reload tests.
+function injectedScript() {
+ if (!window.pageScriptExecutedFirst) {
+ window.addEventListener(
+ "DOMContentLoaded",
+ function() {
+ if (document.querySelector("pre")) {
+ document.querySelector("pre").textContent =
+ "injected script executed first";
+ }
+ },
+ { once: true }
+ );
+ }
+}
+
+// Script evaluated in the target tab, to collect the results of injectedScript
+// evaluation in the inspectedWindow.reload tests.
+function collectEvalResults() {
+ const results = [];
+ let iframeDoc = document;
+
+ while (iframeDoc) {
+ if (iframeDoc.querySelector("pre")) {
+ results.push(iframeDoc.querySelector("pre").textContent);
+ }
+ const iframe = iframeDoc.querySelector("iframe");
+ iframeDoc = iframe ? iframe.contentDocument : null;
+ }
+ return JSON.stringify(results);
+}
+
+add_task(async function test_successfull_inspectedWindowEval_result() {
+ const {
+ client,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ } = await setup(MAIN_DOMAIN);
+
+ const result = await inspectedWindowFront.eval(
+ fakeExtCallerInfo,
+ "window.location",
+ {}
+ );
+
+ ok(result.value, "Got a result from inspectedWindow eval");
+ is(
+ result.value.href,
+ MAIN_DOMAIN,
+ "Got the expected window.location.href property value"
+ );
+ is(
+ result.value.protocol,
+ "http:",
+ "Got the expected window.location.protocol property value"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_successfull_inspectedWindowEval_resultAsGrip() {
+ const {
+ client,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ webConsoleFront,
+ } = await setup(MAIN_DOMAIN);
+
+ let result = await inspectedWindowFront.eval(fakeExtCallerInfo, "window", {
+ evalResultAsGrip: true,
+ toolboxConsoleActorID: webConsoleFront.actor,
+ });
+
+ ok(result.valueGrip, "Got a result from inspectedWindow eval");
+ ok(result.valueGrip.actor, "Got a object actor as expected");
+ is(result.valueGrip.type, "object", "Got a value grip of type object");
+ is(
+ result.valueGrip.class,
+ "Window",
+ "Got a value grip which is instanceof Location"
+ );
+
+ // Test invalid evalResultAsGrip request.
+ result = await inspectedWindowFront.eval(fakeExtCallerInfo, "window", {
+ evalResultAsGrip: true,
+ });
+
+ ok(
+ !result.value && !result.valueGrip,
+ "Got a null result from the invalid inspectedWindow eval call"
+ );
+ ok(
+ result.exceptionInfo.isError,
+ "Got an API Error result from inspectedWindow eval"
+ );
+ ok(
+ !result.exceptionInfo.isException,
+ "An error isException is false as expected"
+ );
+ is(
+ result.exceptionInfo.code,
+ "E_PROTOCOLERROR",
+ "Got the expected 'code' property in the error result"
+ );
+ is(
+ result.exceptionInfo.description,
+ "Inspector protocol error: %s - %s",
+ "Got the expected 'description' property in the error result"
+ );
+ is(
+ result.exceptionInfo.details.length,
+ 2,
+ "The 'details' array property should contains 1 element"
+ );
+ is(
+ result.exceptionInfo.details[0],
+ "Unexpected invalid sidebar panel expression request",
+ "Got the expected content in the error results's details"
+ );
+ is(
+ result.exceptionInfo.details[1],
+ "missing toolboxConsoleActorID",
+ "Got the expected content in the error results's details"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_error_inspectedWindowEval_result() {
+ const {
+ client,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ } = await setup(MAIN_DOMAIN);
+
+ const result = await inspectedWindowFront.eval(
+ fakeExtCallerInfo,
+ "window",
+ {}
+ );
+
+ ok(!result.value, "Got a null result from inspectedWindow eval");
+ ok(
+ result.exceptionInfo.isError,
+ "Got an API Error result from inspectedWindow eval"
+ );
+ ok(
+ !result.exceptionInfo.isException,
+ "An error isException is false as expected"
+ );
+ is(
+ result.exceptionInfo.code,
+ "E_PROTOCOLERROR",
+ "Got the expected 'code' property in the error result"
+ );
+ is(
+ result.exceptionInfo.description,
+ "Inspector protocol error: %s",
+ "Got the expected 'description' property in the error result"
+ );
+ is(
+ result.exceptionInfo.details.length,
+ 1,
+ "The 'details' array property should contains 1 element"
+ );
+ ok(
+ result.exceptionInfo.details[0].includes("cyclic object value"),
+ "Got the expected content in the error results's details"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(
+ async function test_system_principal_denied_error_inspectedWindowEval_result() {
+ const {
+ client,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ } = await setup("about:addons");
+
+ const result = await inspectedWindowFront.eval(
+ fakeExtCallerInfo,
+ "window",
+ {}
+ );
+
+ ok(!result.value, "Got a null result from inspectedWindow eval");
+ ok(
+ result.exceptionInfo.isError,
+ "Got an API Error result from inspectedWindow eval on a system principal page"
+ );
+ is(
+ result.exceptionInfo.code,
+ "E_PROTOCOLERROR",
+ "Got the expected 'code' property in the error result"
+ );
+ is(
+ result.exceptionInfo.description,
+ "Inspector protocol error: %s",
+ "Got the expected 'description' property in the error result"
+ );
+ is(
+ result.exceptionInfo.details.length,
+ 1,
+ "The 'details' array property should contains 1 element"
+ );
+ is(
+ result.exceptionInfo.details[0],
+ "This target has a system principal. inspectedWindow.eval denied.",
+ "Got the expected content in the error results's details"
+ );
+
+ await teardown({ client, extension });
+ }
+);
+
+add_task(async function test_exception_inspectedWindowEval_result() {
+ const {
+ client,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ } = await setup(MAIN_DOMAIN);
+
+ const result = await inspectedWindowFront.eval(
+ fakeExtCallerInfo,
+ "throw Error('fake eval error');",
+ {}
+ );
+
+ ok(result.exceptionInfo.isException, "Got an exception as expected");
+ ok(!result.value, "Got an undefined eval value");
+ ok(!result.exceptionInfo.isError, "An exception should not be isError=true");
+ ok(
+ result.exceptionInfo.value.includes("Error: fake eval error"),
+ "Got the expected exception message"
+ );
+
+ const expectedCallerInfo = `called from ${fakeExtCallerInfo.url}:${fakeExtCallerInfo.lineNumber}`;
+ ok(
+ result.exceptionInfo.value.includes(expectedCallerInfo),
+ "Got the expected caller info in the exception message"
+ );
+
+ const expectedStack = `eval code:1:7`;
+ ok(
+ result.exceptionInfo.value.includes(expectedStack),
+ "Got the expected stack trace in the exception message"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload() {
+ const {
+ client,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ target,
+ } = await setup(`${TEST_RELOAD_URL}?test=cache`);
+
+ // Test reload with bypassCache=false.
+
+ const waitForNoBypassCacheReload = waitForNextTabNavigated(target);
+ const reloadResult = await inspectedWindowFront.reload(fakeExtCallerInfo, {
+ ignoreCache: false,
+ });
+
+ ok(
+ !reloadResult,
+ "Got the expected undefined result from inspectedWindow reload"
+ );
+
+ await waitForNoBypassCacheReload;
+
+ const noBypassCacheEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ noBypassCacheEval.result,
+ "empty cache headers",
+ "Got the expected result with reload forceBypassCache=false"
+ );
+
+ // Test reload with bypassCache=true.
+
+ const waitForForceBypassCacheReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, { ignoreCache: true });
+
+ await waitForForceBypassCacheReload;
+
+ const forceBypassCacheEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ forceBypassCacheEval.result,
+ "no-cache:no-cache",
+ "Got the expected result with reload forceBypassCache=true"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
+ const {
+ client,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ target,
+ } = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
+
+ // Test reload with custom userAgent.
+
+ const waitForCustomUserAgentReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent",
+ });
+
+ await waitForCustomUserAgentReload;
+
+ const customUserAgentEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ customUserAgentEval.result,
+ "Customized User Agent",
+ "Got the expected result on reload with a customized userAgent"
+ );
+
+ // Test reload with no custom userAgent.
+
+ const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {});
+
+ await waitForNoCustomUserAgentReload;
+
+ const noCustomUserAgentEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ noCustomUserAgentEval.result,
+ window.navigator.userAgent,
+ "Got the expected result with reload without a customized userAgent"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_injectedScript() {
+ const {
+ client,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ target,
+ } = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
+
+ // Test reload with an injectedScript.
+
+ const waitForInjectedScriptReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {
+ injectedScript: `new ${injectedScript}`,
+ });
+ await waitForInjectedScriptReload;
+
+ const injectedScriptEval = await webConsoleFront.evaluateJSAsync(
+ `(${collectEvalResults})()`
+ );
+
+ const expectedResult = new Array(5).fill("injected script executed first");
+
+ SimpleTest.isDeeply(
+ JSON.parse(injectedScriptEval.result),
+ expectedResult,
+ "Got the expected result on reload with an injected script"
+ );
+
+ // Test reload without an injectedScript.
+
+ const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {});
+ await waitForNoInjectedScriptReload;
+
+ const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
+ `(${collectEvalResults})()`
+ );
+
+ const newExpectedResult = new Array(5).fill("injected script NOT executed");
+
+ SimpleTest.isDeeply(
+ JSON.parse(noInjectedScriptEval.result),
+ newExpectedResult,
+ "Got the expected result on reload with no injected script"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
+ const {
+ client,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ target,
+ } = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
+
+ // Test reload with custom userAgent three times (and then
+ // check that only the first one has affected the page reload.
+
+ const waitForCustomUserAgentReload = waitForNextTabNavigated(target);
+
+ inspectedWindowFront.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent 1",
+ });
+ inspectedWindowFront.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent 2",
+ });
+
+ await waitForCustomUserAgentReload;
+
+ const customUserAgentEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ customUserAgentEval.result,
+ "Customized User Agent 1",
+ "Got the expected result on reload with a customized userAgent"
+ );
+
+ // Test reload with no custom userAgent.
+
+ const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {});
+
+ await waitForNoCustomUserAgentReload;
+
+ const noCustomUserAgentEval = await webConsoleFront.evaluateJSAsync(
+ "document.body.textContent"
+ );
+
+ is(
+ noCustomUserAgentEval.result,
+ window.navigator.userAgent,
+ "Got the expected result with reload without a customized userAgent"
+ );
+
+ await teardown({ client, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_stopped() {
+ const {
+ client,
+ webConsoleFront,
+ inspectedWindowFront,
+ extension,
+ fakeExtCallerInfo,
+ target,
+ } = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
+
+ // Test reload on a page that calls window.stop() immediately during the page loading
+
+ const waitForPageLoad = waitForNextTabNavigated(target);
+ await inspectedWindowFront.eval(
+ fakeExtCallerInfo,
+ "window.location += '&stop=windowStop'"
+ );
+
+ info("Load a webpage that calls 'window.stop()' while is still loading");
+ await waitForPageLoad;
+
+ info("Starting a reload with an injectedScript");
+ const waitForInjectedScriptReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {
+ injectedScript: `new ${injectedScript}`,
+ });
+ await waitForInjectedScriptReload;
+
+ const injectedScriptEval = await webConsoleFront.evaluateJSAsync(
+ `(${collectEvalResults})()`
+ );
+
+ // The page should have stopped during the reload and only one injected script
+ // is expected.
+ const expectedResult = new Array(1).fill("injected script executed first");
+
+ SimpleTest.isDeeply(
+ JSON.parse(injectedScriptEval.result),
+ expectedResult,
+ "The injected script has been executed on the 'stopped' page reload"
+ );
+
+ // Reload again with no options.
+
+ info("Reload the tab again without any reload options");
+ const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
+ await inspectedWindowFront.reload(fakeExtCallerInfo, {});
+ await waitForNoInjectedScriptReload;
+
+ const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
+ `(${collectEvalResults})()`
+ );
+
+ // The page should have stopped during the reload and no injected script should
+ // have been executed during this second reload (or it would mean that the previous
+ // customized reload was still pending and has wrongly affected the second reload)
+ const newExpectedResult = new Array(1).fill("injected script NOT executed");
+
+ SimpleTest.isDeeply(
+ JSON.parse(noInjectedScriptEval.result),
+ newExpectedResult,
+ "No injectedScript should have been evaluated during the second reload"
+ );
+
+ await teardown({ client, extension });
+});
+
+// TODO: check eval with $0 binding once implemented (Bug 1300590)