summaryrefslogtreecommitdiffstats
path: root/devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js')
-rw-r--r--devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js523
1 files changed, 523 insertions, 0 deletions
diff --git a/devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js b/devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js
new file mode 100644
index 0000000000..bf2b752e4d
--- /dev/null
+++ b/devtools/shared/commands/inspected-window/tests/browser_webextension_inspected_window.js
@@ -0,0 +1,523 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_RELOAD_URL = `${URL_ROOT_SSL}/inspectedwindow-reload-target.sjs`;
+
+async function setup(pageUrl) {
+ // Disable bfcache for Fission for now.
+ // If Fission is disabled, the pref is no-op.
+ await SpecialPowers.pushPrefEnv({
+ set: [["fission.bfcacheInParent", false]],
+ });
+
+ 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 tab = await addTab(pageUrl);
+
+ const commands = await CommandsFactory.forTab(tab, { isWebExtension: true });
+ await commands.targetCommand.startListening();
+
+ const webConsoleFront = await commands.targetCommand.targetFront.getFront(
+ "console"
+ );
+
+ return {
+ webConsoleFront,
+ commands,
+ extension,
+ fakeExtCallerInfo,
+ };
+}
+
+async function teardown({ commands, extension }) {
+ await commands.destroy();
+ gBrowser.removeCurrentTab();
+ await extension.unload();
+}
+
+function waitForNextTabNavigated(commands) {
+ const target = commands.targetCommand.targetFront;
+ 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 { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT_SSL);
+
+ const result = await commands.inspectedWindowCommand.eval(
+ fakeExtCallerInfo,
+ "window.location",
+ {}
+ );
+
+ ok(result.value, "Got a result from inspectedWindow eval");
+ is(
+ result.value.href,
+ URL_ROOT_SSL,
+ "Got the expected window.location.href property value"
+ );
+ is(
+ result.value.protocol,
+ "https:",
+ "Got the expected window.location.protocol property value"
+ );
+
+ await teardown({ commands, extension });
+});
+
+add_task(async function test_successfull_inspectedWindowEval_resultAsGrip() {
+ const { commands, extension, fakeExtCallerInfo, webConsoleFront } =
+ await setup(URL_ROOT_SSL);
+
+ let result = await commands.inspectedWindowCommand.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 commands.inspectedWindowCommand.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({ commands, extension });
+});
+
+add_task(async function test_error_inspectedWindowEval_result() {
+ const { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT_SSL);
+
+ const result = await commands.inspectedWindowCommand.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({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowEval_result() {
+ const { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT_SSL);
+
+ const result = await commands.inspectedWindowCommand.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({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload() {
+ const { commands, extension, fakeExtCallerInfo } = await setup(
+ `${TEST_RELOAD_URL}?test=cache`
+ );
+
+ // Test reload with bypassCache=false.
+
+ const waitForNoBypassCacheReload = waitForNextTabNavigated(commands);
+ const reloadResult = await commands.inspectedWindowCommand.reload(
+ fakeExtCallerInfo,
+ {
+ ignoreCache: false,
+ }
+ );
+
+ ok(
+ !reloadResult,
+ "Got the expected undefined result from inspectedWindow reload"
+ );
+
+ await waitForNoBypassCacheReload;
+
+ const noBypassCacheEval = await commands.scriptCommand.execute(
+ "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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ ignoreCache: true,
+ });
+
+ await waitForForceBypassCacheReload;
+
+ const forceBypassCacheEval = await commands.scriptCommand.execute(
+ "document.body.textContent"
+ );
+
+ is(
+ forceBypassCacheEval.result,
+ "no-cache:no-cache",
+ "Got the expected result with reload forceBypassCache=true"
+ );
+
+ await teardown({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
+ const { commands, extension, fakeExtCallerInfo } = await setup(
+ `${TEST_RELOAD_URL}?test=user-agent`
+ );
+
+ // Test reload with custom userAgent.
+
+ const waitForCustomUserAgentReload = waitForNextTabNavigated(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent",
+ });
+
+ await waitForCustomUserAgentReload;
+
+ const customUserAgentEval = await commands.scriptCommand.execute(
+ "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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
+
+ await waitForNoCustomUserAgentReload;
+
+ const noCustomUserAgentEval = await commands.scriptCommand.execute(
+ "document.body.textContent"
+ );
+
+ is(
+ noCustomUserAgentEval.result,
+ window.navigator.userAgent,
+ "Got the expected result with reload without a customized userAgent"
+ );
+
+ await teardown({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_injectedScript() {
+ const { commands, extension, fakeExtCallerInfo } = await setup(
+ `${TEST_RELOAD_URL}?test=injected-script&frames=3`
+ );
+
+ // Test reload with an injectedScript.
+
+ const waitForInjectedScriptReload = waitForNextTabNavigated(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ injectedScript: `new ${injectedScript}`,
+ });
+ await waitForInjectedScriptReload;
+
+ const injectedScriptEval = await commands.scriptCommand.execute(
+ `(${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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
+ await waitForNoInjectedScriptReload;
+
+ const noInjectedScriptEval = await commands.scriptCommand.execute(
+ `(${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({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
+ const { commands, extension, fakeExtCallerInfo } = 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(commands);
+
+ commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent 1",
+ });
+ commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ userAgent: "Customized User Agent 2",
+ });
+
+ await waitForCustomUserAgentReload;
+
+ const customUserAgentEval = await commands.scriptCommand.execute(
+ "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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
+
+ await waitForNoCustomUserAgentReload;
+
+ const noCustomUserAgentEval = await commands.scriptCommand.execute(
+ "document.body.textContent"
+ );
+
+ is(
+ noCustomUserAgentEval.result,
+ window.navigator.userAgent,
+ "Got the expected result with reload without a customized userAgent"
+ );
+
+ await teardown({ commands, extension });
+});
+
+add_task(async function test_exception_inspectedWindowReload_stopped() {
+ const { commands, extension, fakeExtCallerInfo } = 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(commands);
+ await commands.inspectedWindowCommand.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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
+ injectedScript: `new ${injectedScript}`,
+ });
+ await waitForInjectedScriptReload;
+
+ const injectedScriptEval = await commands.scriptCommand.execute(
+ `(${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(commands);
+ await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
+ await waitForNoInjectedScriptReload;
+
+ const noInjectedScriptEval = await commands.scriptCommand.execute(
+ `(${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({ commands, extension });
+});
+
+// TODO: check eval with $0 binding once implemented (Bug 1300590)