diff --git a/devtools/client/webconsole/components/Input/EvaluationContextSelector.js b/devtools/client/webconsole/components/Input/EvaluationContextSelector.js
index 7c5162879183..15a7e3fb0d25 100644
--- a/devtools/client/webconsole/components/Input/EvaluationContextSelector.js
+++ b/devtools/client/webconsole/components/Input/EvaluationContextSelector.js
@@ -144,7 +144,10 @@ class EvaluationContextSelector extends Component {
);
}
- return MenuList({ id: "webconsole-console-settings-menu-list" }, items);
+ return MenuList(
+ { id: "webconsole-console-evaluation-context-selector-menu-list" },
+ items
+ );
}
getLabel() {
diff --git a/devtools/client/webconsole/test/browser/_jsterm.ini b/devtools/client/webconsole/test/browser/_jsterm.ini
index 16ae15fba0ed..5c790bc34cb3 100644
--- a/devtools/client/webconsole/test/browser/_jsterm.ini
+++ b/devtools/client/webconsole/test/browser/_jsterm.ini
@@ -105,6 +105,8 @@ skip-if = os != 'mac' # The tested ctrl+key shortcuts are OSX only
[browser_jsterm_editor_toolbar.js]
[browser_jsterm_error_docs.js]
[browser_jsterm_error_outside_valid_range.js]
+[browser_jsterm_evaluation_context_selector_inspector.js]
+skip-if = !fission # context selector is only visible when fission is enabled.
[browser_jsterm_evaluation_context_selector.js]
skip-if = !fission # context selector is only visible when fission is enabled.
[browser_jsterm_file_load_save_keyboard_shortcut.js]
diff --git a/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector.js b/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector.js
index 85f11314d9f6..112b6c5f6492 100644
--- a/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector.js
+++ b/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector.js
@@ -14,32 +14,10 @@ add_task(async function() {
await pushPref("devtools.contenttoolbox.fission", true);
await pushPref("devtools.contenttoolbox.webconsole.input.context", true);
- await addTab(TEST_URI);
-
- info("Create new iframes and add them to the page.");
- await ContentTask.spawn(gBrowser.selectedBrowser, IFRAME_PATH, async function(
- iframPath
- ) {
- const iframe1 = content.document.createElement("iframe");
- const iframe2 = content.document.createElement("iframe");
- iframe1.classList.add("iframe-1");
- iframe2.classList.add("iframe-2");
- content.document.body.append(iframe1, iframe2);
-
- const onLoadIframe1 = new Promise(resolve => {
- iframe1.addEventListener("load", resolve, { once: true });
- });
- const onLoadIframe2 = new Promise(resolve => {
- iframe2.addEventListener("load", resolve, { once: true });
- });
-
- iframe1.src = `http://example.org/${iframPath}?id=iframe-1`;
- iframe2.src = `http://mochi.test:8888/${iframPath}?id=iframe-2`;
-
- await Promise.all([onLoadIframe1, onLoadIframe2]);
- });
-
- const hud = await openConsole();
+ const hud = await openNewTabWithIframesAndConsole(TEST_URI, [
+ `http://example.org/${IFRAME_PATH}?id=iframe-1`,
+ `http://mochi.test:8888/${IFRAME_PATH}?id=iframe-2`,
+ ]);
const evaluationContextSelectorButton = hud.ui.outputNode.querySelector(
".webconsole-evaluation-selector-button"
@@ -72,17 +50,39 @@ add_task(async function() {
setInputValue(hud, "document.location.host");
await waitForEagerEvaluationResult(hud, `"example.com"`);
- info("Go to the inspector panel");
- const inspector = await openInspector();
+ info("Check the context selector menu");
+ const expectedTopItem = {
+ label: "Top",
+ tooltip: TEST_URI,
+ };
+ const expectedSeparatorItem = { separator: true };
+ const expectedFirstIframeItem = {
+ label: "iframe-1|example.org",
+ tooltip: `http://example.org/${IFRAME_PATH}?id=iframe-1`,
+ };
+ const expectedSecondIframeItem = {
+ label: "iframe-2|mochi.test:8888",
+ tooltip: `http://mochi.test:8888/${IFRAME_PATH}?id=iframe-2`,
+ };
- info("Expand all the nodes");
- await inspector.markup.expandAll();
+ await checkContextSelectorMenu(hud, [
+ {
+ ...expectedTopItem,
+ checked: true,
+ },
+ expectedSeparatorItem,
+ {
+ ...expectedFirstIframeItem,
+ checked: false,
+ },
+ {
+ ...expectedSecondIframeItem,
+ checked: false,
+ },
+ ]);
- info("Open the split console");
- await hud.toolbox.openSplitConsole();
-
- info("Select the first iframe h2 element");
- await selectIframeContentElement(inspector, ".iframe-1", "h2");
+ info("Select the first iframe");
+ selectTargetInContextSelector(hud, expectedFirstIframeItem.label);
await waitFor(() =>
evaluationContextSelectorButton.innerText.includes("example.org")
@@ -107,8 +107,23 @@ add_task(async function() {
);
setInputValue(hud, "document.location.host");
- info("Select the second iframe h2 element");
- await selectIframeContentElement(inspector, ".iframe-2", "h2");
+ info("Select the second iframe in the context selector menu");
+ await checkContextSelectorMenu(hud, [
+ {
+ ...expectedTopItem,
+ checked: false,
+ },
+ expectedSeparatorItem,
+ {
+ ...expectedFirstIframeItem,
+ checked: true,
+ },
+ {
+ ...expectedSecondIframeItem,
+ checked: false,
+ },
+ ]);
+ selectTargetInContextSelector(hud, expectedSecondIframeItem.label);
await waitFor(() =>
evaluationContextSelectorButton.innerText.includes("mochi.test")
@@ -133,10 +148,23 @@ add_task(async function() {
);
setInputValue(hud, "document.location.host");
- info("Select an element in the top document");
- const h1NodeFront = await inspector.walker.findNodeFront(["h1"]);
- inspector.selection.setNodeFront(null);
- inspector.selection.setNodeFront(h1NodeFront);
+ info("Select the top frame in the context selector menu");
+ await checkContextSelectorMenu(hud, [
+ {
+ ...expectedTopItem,
+ checked: false,
+ },
+ expectedSeparatorItem,
+ {
+ ...expectedFirstIframeItem,
+ checked: false,
+ },
+ {
+ ...expectedSecondIframeItem,
+ checked: true,
+ },
+ ]);
+ selectTargetInContextSelector(hud, expectedTopItem.label);
await waitForEagerEvaluationResult(hud, `"example.com"`);
await waitFor(() =>
@@ -150,7 +178,6 @@ add_task(async function() {
"The non-top class isn't applied"
);
- await hud.toolbox.selectTool("webconsole");
info("Check that 'Store as global variable' selects the right context");
await testStoreAsGlobalVariable(
hud,
@@ -193,75 +220,8 @@ add_task(async function() {
evaluationContextSelectorButton.innerText.includes("Top")
);
ok(true, "The context was set to the top document");
-
- info("Open the inspector again");
- await hud.toolbox.selectTool("inspector");
-
- info(
- "Check that 'Use in console' works as expected for element in the first iframe"
- );
- await testUseInConsole(
- hud,
- inspector,
- ".iframe-1",
- "h2",
- "temp1",
- `
`
- );
- await waitFor(() =>
- evaluationContextSelectorButton.innerText.includes("example.org")
- );
- ok(true, "The context selector was updated");
-
- info(
- "Check that 'Use in console' works as expected for element in the second iframe"
- );
- await testUseInConsole(
- hud,
- inspector,
- ".iframe-2",
- "h2",
- "temp1",
- `
`
- );
- await waitFor(() =>
- evaluationContextSelectorButton.innerText.includes("mochi.test:8888")
- );
- ok(true, "The context selector was updated");
-
- info(
- "Check that 'Use in console' works as expected for element in the top frame"
- );
- await testUseInConsole(
- hud,
- inspector,
- ":root",
- "h1",
- "temp1",
- `
`
- );
- await waitFor(() =>
- evaluationContextSelectorButton.innerText.includes("Top")
- );
- ok(true, "The context selector was updated");
});
-async function selectIframeContentElement(
- inspector,
- iframeSelector,
- iframeContentSelector
-) {
- inspector.selection.setNodeFront(null);
- const iframeNodeFront = await inspector.walker.findNodeFront([
- iframeSelector,
- ]);
- const childrenNodeFront = await iframeNodeFront
- .treeChildren()[0]
- .walkerFront.findNodeFront([iframeContentSelector]);
- inspector.selection.setNodeFront(childrenNodeFront);
- return childrenNodeFront;
-}
-
async function testStoreAsGlobalVariable(
hud,
msg,
@@ -292,47 +252,3 @@ async function testStoreAsGlobalVariable(
);
ok(true, "Correct variable assigned into console.");
}
-
-async function testUseInConsole(
- hud,
- inspector,
- iframeSelector,
- iframeContentSelector,
- variableName,
- expectedTextResult
-) {
- const nodeFront = await selectIframeContentElement(
- inspector,
- iframeSelector,
- iframeContentSelector
- );
- const container = inspector.markup.getContainer(nodeFront);
-
- const onConsoleReady = inspector.once("console-var-ready");
- const menu = inspector.markup.contextMenu._openMenu({
- target: container.tagLine,
- });
- const useInConsoleItem = menu.items.find(
- ({ id }) => id === "node-menu-useinconsole"
- );
- useInConsoleItem.click();
- await onConsoleReady;
-
- menu.clear();
-
- is(
- getInputValue(hud),
- variableName,
- "A variable with the expected name was created"
- );
- await waitForEagerEvaluationResult(hud, expectedTextResult);
- ok(true, "The eager evaluation display the expected result");
-
- await executeAndWaitForMessage(
- hud,
- variableName,
- expectedTextResult,
- ".result"
- );
- ok(true, "the expected variable was created with the expected value.");
-}
diff --git a/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector_inspector.js b/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector_inspector.js
new file mode 100644
index 000000000000..b82a528bf9f2
--- /dev/null
+++ b/devtools/client/webconsole/test/browser/browser_jsterm_evaluation_context_selector_inspector.js
@@ -0,0 +1,180 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test that the evaluation context selector reacts as expected when performing some
+// inspector actions (selecting a node, "use in console" context menu entry, …).
+
+const FILE_FOLDER = `browser/devtools/client/webconsole/test/browser`;
+const TEST_URI = `http://example.com/${FILE_FOLDER}/test-console-evaluation-context-selector.html`;
+const IFRAME_PATH = `${FILE_FOLDER}/test-console-evaluation-context-selector-child.html`;
+
+requestLongerTimeout(2);
+
+add_task(async function() {
+ await pushPref("devtools.contenttoolbox.fission", true);
+ await pushPref("devtools.contenttoolbox.webconsole.input.context", true);
+
+ const hud = await openNewTabWithIframesAndConsole(TEST_URI, [
+ `http://example.org/${IFRAME_PATH}?id=iframe-1`,
+ `http://mochi.test:8888/${IFRAME_PATH}?id=iframe-2`,
+ ]);
+
+ const evaluationContextSelectorButton = hud.ui.outputNode.querySelector(
+ ".webconsole-evaluation-selector-button"
+ );
+
+ setInputValue(hud, "document.location.host");
+ await waitForEagerEvaluationResult(hud, `"example.com"`);
+
+ info("Go to the inspector panel");
+ const inspector = await openInspector();
+
+ info("Expand all the nodes");
+ await inspector.markup.expandAll();
+
+ info("Open the split console");
+ await hud.toolbox.openSplitConsole();
+
+ info("Select the first iframe h2 element");
+ await selectIframeContentElement(inspector, ".iframe-1", "h2");
+
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("example.org")
+ );
+ ok(true, "The context was set to the selected iframe document");
+
+ await waitForEagerEvaluationResult(hud, `"example.org"`);
+ ok(true, "The instant evaluation result is updated in the iframe context");
+
+ info("Select the second iframe h2 element");
+ await selectIframeContentElement(inspector, ".iframe-2", "h2");
+
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("mochi.test")
+ );
+ ok(true, "The context was set to the selected iframe document");
+
+ await waitForEagerEvaluationResult(hud, `"mochi.test:8888"`);
+ ok(true, "The instant evaluation result is updated in the iframe context");
+
+ info("Select an element in the top document");
+ const h1NodeFront = await inspector.walker.findNodeFront(["h1"]);
+ inspector.selection.setNodeFront(null);
+ inspector.selection.setNodeFront(h1NodeFront);
+
+ await waitForEagerEvaluationResult(hud, `"example.com"`);
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("Top")
+ );
+
+ info(
+ "Check that 'Use in console' works as expected for element in the first iframe"
+ );
+ await testUseInConsole(
+ hud,
+ inspector,
+ ".iframe-1",
+ "h2",
+ "temp0",
+ `
`
+ );
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("example.org")
+ );
+ ok(true, "The context selector was updated");
+
+ info(
+ "Check that 'Use in console' works as expected for element in the second iframe"
+ );
+ await testUseInConsole(
+ hud,
+ inspector,
+ ".iframe-2",
+ "h2",
+ "temp0",
+ `
`
+ );
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("mochi.test:8888")
+ );
+ ok(true, "The context selector was updated");
+
+ info(
+ "Check that 'Use in console' works as expected for element in the top frame"
+ );
+ await testUseInConsole(
+ hud,
+ inspector,
+ ":root",
+ "h1",
+ "temp0",
+ `
`
+ );
+ await waitFor(() =>
+ evaluationContextSelectorButton.innerText.includes("Top")
+ );
+ ok(true, "The context selector was updated");
+});
+
+async function selectIframeContentElement(
+ inspector,
+ iframeSelector,
+ iframeContentSelector
+) {
+ inspector.selection.setNodeFront(null);
+ const iframeNodeFront = await inspector.walker.findNodeFront([
+ iframeSelector,
+ ]);
+ const childrenNodeFront = await iframeNodeFront
+ .treeChildren()[0]
+ .walkerFront.findNodeFront([iframeContentSelector]);
+ inspector.selection.setNodeFront(childrenNodeFront);
+ return childrenNodeFront;
+}
+
+async function testUseInConsole(
+ hud,
+ inspector,
+ iframeSelector,
+ iframeContentSelector,
+ variableName,
+ expectedTextResult
+) {
+ const nodeFront = await selectIframeContentElement(
+ inspector,
+ iframeSelector,
+ iframeContentSelector
+ );
+ const container = inspector.markup.getContainer(nodeFront);
+
+ const onConsoleReady = inspector.once("console-var-ready");
+ const menu = inspector.markup.contextMenu._openMenu({
+ target: container.tagLine,
+ });
+ const useInConsoleItem = menu.items.find(
+ ({ id }) => id === "node-menu-useinconsole"
+ );
+ useInConsoleItem.click();
+ await onConsoleReady;
+
+ menu.clear();
+
+ is(
+ getInputValue(hud),
+ variableName,
+ "A variable with the expected name was created"
+ );
+ await waitForEagerEvaluationResult(hud, expectedTextResult);
+ ok(true, "The eager evaluation display the expected result");
+
+ await executeAndWaitForMessage(
+ hud,
+ variableName,
+ expectedTextResult,
+ ".result"
+ );
+ ok(true, "the expected variable was created with the expected value.");
+}
diff --git a/devtools/client/webconsole/test/browser/head.js b/devtools/client/webconsole/test/browser/head.js
index 38e867fdcac1..bae2465ee1d5 100644
--- a/devtools/client/webconsole/test/browser/head.js
+++ b/devtools/client/webconsole/test/browser/head.js
@@ -73,7 +73,7 @@ registerCleanupFunction(async function() {
* The type of toolbox host to be used.
* @return Promise
* Resolves when the tab has been added, loaded and the toolbox has been opened.
- * Resolves to the toolbox.
+ * Resolves to the hud.
*/
async function openNewTabAndConsole(url, clearJstermHistory = true, hostId) {
const toolbox = await openNewTabAndToolbox(url, "webconsole", hostId);
@@ -87,6 +87,42 @@ async function openNewTabAndConsole(url, clearJstermHistory = true, hostId) {
return hud;
}
+/**
+ * Add a new tab with iframes, open the toolbox in it, and select the webconsole.
+ *
+ * @param string url
+ * The URL for the tab to be opened.
+ * @param Arra iframes
+ * An array of URLs that will be added to the top document.
+ * @return Promise
+ * Resolves when the tab has been added, loaded, iframes loaded, and the toolbox
+ * has been opened. Resolves to the hud.
+ */
+async function openNewTabWithIframesAndConsole(tabUrl, iframes) {
+ // We need to add the tab and the iframes before opening the console in case we want
+ // to handle remote frames (we don't support creating frames target when the toolbox
+ // is already open).
+ await addTab(tabUrl);
+ await ContentTask.spawn(gBrowser.selectedBrowser, iframes, async function(
+ urls
+ ) {
+ const iframesLoadPromises = urls.map((url, i) => {
+ const iframe = content.document.createElement("iframe");
+ iframe.classList.add(`iframe-${i + 1}`);
+ const onLoadIframe = new Promise(resolve => {
+ iframe.addEventListener("load", resolve, { once: true });
+ });
+ content.document.body.append(iframe);
+ iframe.src = url;
+ return onLoadIframe;
+ });
+
+ await Promise.all(iframesLoadPromises);
+ });
+
+ return openConsole();
+}
+
/**
* Open a new window with a tab,open the toolbox, and select the webconsole.
*
@@ -1686,3 +1722,83 @@ async function clearOutput(hud, { keepStorage = false } = {}) {
ui.clearOutput(!keepStorage);
await Promise.all(promises);
}
+
+/**
+ * Retrieve all the items of the context selector menu.
+ *
+ * @param {WebConsole} hud
+ * @return Array
+ */
+function getContextSelectorItems(hud) {
+ const toolbox = hud.toolbox;
+ const doc = toolbox ? toolbox.doc : hud.chromeWindow.document;
+ const list = doc.getElementById(
+ "webconsole-console-evaluation-context-selector-menu-list"
+ );
+ return Array.from(list.querySelectorAll("li.menuitem button"));
+}
+
+/**
+ * Check that the evaluation context selector menu has the expected item, in the expected
+ * state.
+ *
+ * @param {WebConsole} hud
+ * @param {Array