diff options
Diffstat (limited to 'devtools/shared/commands/inspector/tests')
6 files changed, 510 insertions, 0 deletions
diff --git a/devtools/shared/commands/inspector/tests/browser.ini b/devtools/shared/commands/inspector/tests/browser.ini new file mode 100644 index 0000000000..cd3e3117cf --- /dev/null +++ b/devtools/shared/commands/inspector/tests/browser.ini @@ -0,0 +1,15 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +support-files = + !/devtools/client/inspector/test/shared-head.js + !/devtools/client/shared/test/shared-head.js + !/devtools/client/shared/test/telemetry-test-helpers.js + !/devtools/client/shared/test/highlighter-test-actor.js + head.js + +[browser_inspector_command_findNodeFrontFromSelectors.js] +skip-if = http3 # Bug 1829298 +[browser_inspector_command_getNodeFrontSelectorsFromTopDocument.js] +[browser_inspector_command_getSuggestionsForQuery.js] +[browser_inspector_command_search.js] diff --git a/devtools/shared/commands/inspector/tests/browser_inspector_command_findNodeFrontFromSelectors.js b/devtools/shared/commands/inspector/tests/browser_inspector_command_findNodeFrontFromSelectors.js new file mode 100644 index 0000000000..7991421c8d --- /dev/null +++ b/devtools/shared/commands/inspector/tests/browser_inspector_command_findNodeFrontFromSelectors.js @@ -0,0 +1,140 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async () => { + // Build a simple test page with a remote iframe, using two distinct origins .com and .org + const iframeOrgHtml = encodeURIComponent( + `<h2 id="in-iframe">in org - same origin</h2>` + ); + const iframeComHtml = encodeURIComponent(`<h3>in com - remote</h3>`); + const html = encodeURIComponent( + `<main class="foo bar"> + <button id="child">Click</button> + </main> + <!-- adding delay to both iframe so we can check we handle loading document has expected --> + <iframe id="iframe-org" src="https://example.org/document-builder.sjs?delay=3000&html=${iframeOrgHtml}"></iframe> + <iframe id="iframe-com" src="https://example.com/document-builder.sjs?delay=6000&html=${iframeComHtml}"></iframe>` + ); + const tab = await addTab( + "https://example.org/document-builder.sjs?html=" + html, + { waitForLoad: false } + ); + + const commands = await CommandsFactory.forTab(tab); + await commands.targetCommand.startListening(); + + info("Check that it returns null when no params are passed"); + let nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors(); + is( + nodeFront, + null, + `findNodeFrontFromSelectors returns null when no param is passed` + ); + + info("Check that it returns null when a string is passed"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors( + "body main" + ); + is( + nodeFront, + null, + `findNodeFrontFromSelectors returns null when passed a string` + ); + + info("Check it returns null when an empty array is passed"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([]); + is( + nodeFront, + null, + `findNodeFrontFromSelectors returns null when passed an empty array` + ); + + info("Check that passing a selector for a non-matching element returns null"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([ + "h1", + ]); + is( + nodeFront, + null, + "findNodeFrontFromSelectors returns null as there's no <h1> element in the page" + ); + + info("Check passing a selector for an element in the top document"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([ + "button", + ]); + is( + nodeFront.typeName, + "domnode", + "findNodeFrontFromSelectors returns a nodeFront" + ); + is( + nodeFront.displayName, + "button", + "findNodeFrontFromSelectors returned the appropriate nodeFront" + ); + + info("Check passing a selector for an element in a same origin iframe"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([ + "#iframe-org", + "#in-iframe", + ]); + is( + nodeFront.displayName, + "h2", + "findNodeFrontFromSelectors returned the appropriate nodeFront" + ); + + info("Check passing a selector for an element in a cross origin iframe"); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([ + "#iframe-com", + "h3", + ]); + is( + nodeFront.displayName, + "h3", + "findNodeFrontFromSelectors returned the appropriate nodeFront" + ); + + info( + "Check passing a selector for an non-existing element in an existing iframe" + ); + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors([ + "iframe", + "#non-existant-id", + ]); + is( + nodeFront.displayName, + "#document", + "findNodeFrontFromSelectors returned the last matching iframe document if the children selector isn't found" + ); + is( + nodeFront.parentNode().displayName, + "iframe", + "findNodeFrontFromSelectors returned the last matching iframe document if the children selector isn't found" + ); + + info("Check that timeout does work"); + // Reload the page so we'll have the iframe loading (for 3s) and we can check that + // putting a smaller timeout will result in the function returning null. + // we need to wait until it's fully processed to avoid pending promises. + const onNewTargetProcessed = commands.targetCommand.once( + "processed-available-target" + ); + await reloadBrowser({ waitForLoad: false }); + await onNewTargetProcessed; + nodeFront = await commands.inspectorCommand.findNodeFrontFromSelectors( + ["#iframe-org", "#in-iframe"], + // timeout in ms (smaller than 3s) + 100 + ); + is( + nodeFront, + null, + "findNodeFrontFromSelectors timed out and returned null, as expected" + ); + + await commands.destroy(); +}); diff --git a/devtools/shared/commands/inspector/tests/browser_inspector_command_getNodeFrontSelectorsFromTopDocument.js b/devtools/shared/commands/inspector/tests/browser_inspector_command_getNodeFrontSelectorsFromTopDocument.js new file mode 100644 index 0000000000..3e5abcddd0 --- /dev/null +++ b/devtools/shared/commands/inspector/tests/browser_inspector_command_getNodeFrontSelectorsFromTopDocument.js @@ -0,0 +1,119 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Testing getNodeFrontSelectorsFromTopDocument + +add_task(async () => { + const html = ` + <html> + <head> + <meta charset="utf8"> + <title>Test</title> + </head> + <body> + <header> + <span>hello</span> + <span>world</span> + </header> + <main> + <iframe src="data:text/html,${encodeURIComponent( + "<html><body><h2 class='frame-child'>foo</h2></body></html>" + )}"></iframe> + </main> + <footer></footer> + + <test-component> + <div slot="slot1" id="el1">content</div> + </test-component> + <script> + 'use strict'; + + customElements.define('test-component', class extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({mode: 'open'}); + shadowRoot.innerHTML = '<slot class="slot-class" name="slot1"></slot>'; + } + }); + </script> + </body> + </html>`; + + const tab = await addTab("data:text/html," + encodeURIComponent(html)); + const commands = await CommandsFactory.forTab(tab); + await commands.targetCommand.startListening(); + + const walker = ( + await commands.targetCommand.targetFront.getFront("inspector") + ).walker; + + const checkSelectors = (...args) => + checkSelectorsFromTopDocumentForNode(commands, ...args); + + let node = await getNodeFrontInFrames(["meta"], { walker }); + await checkSelectors( + node, + ["head > meta:nth-child(1)"], + "Got expected selectors for the top-level meta node" + ); + + node = await getNodeFrontInFrames(["body"], { walker }); + await checkSelectors( + node, + ["body"], + "Got expected selectors for the top-level body node" + ); + + node = await getNodeFrontInFrames(["header > span"], { walker }); + await checkSelectors( + node, + ["body > header:nth-child(1) > span:nth-child(1)"], + "Got expected selectors for the top-level span node" + ); + + node = await getNodeFrontInFrames(["iframe"], { walker }); + await checkSelectors( + node, + ["body > main:nth-child(2) > iframe:nth-child(1)"], + "Got expected selectors for the iframe node" + ); + + node = await getNodeFrontInFrames(["iframe", "body"], { walker }); + await checkSelectors( + node, + ["body > main:nth-child(2) > iframe:nth-child(1)", "body"], + "Got expected selectors for the iframe body node" + ); + + const hostFront = await getNodeFront("test-component", { walker }); + const { nodes } = await walker.children(hostFront); + const shadowRoot = nodes.find(hostNode => hostNode.isShadowRoot); + node = await walker.querySelector(shadowRoot, ".slot-class"); + + await checkSelectors( + node, + ["body > test-component:nth-child(4)", ".slot-class"], + "Got expected selectors for the shadow dom node" + ); + + await commands.destroy(); +}); + +async function checkSelectorsFromTopDocumentForNode( + commands, + nodeFront, + expectedSelectors, + assertionText +) { + const selectors = + await commands.inspectorCommand.getNodeFrontSelectorsFromTopDocument( + nodeFront + ); + is( + JSON.stringify(selectors), + JSON.stringify(expectedSelectors), + assertionText + ); +} diff --git a/devtools/shared/commands/inspector/tests/browser_inspector_command_getSuggestionsForQuery.js b/devtools/shared/commands/inspector/tests/browser_inspector_command_getSuggestionsForQuery.js new file mode 100644 index 0000000000..e7b765b1d0 --- /dev/null +++ b/devtools/shared/commands/inspector/tests/browser_inspector_command_getSuggestionsForQuery.js @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async () => { + // Build a test page with a remote iframe, using two distinct origins .com and .org + const iframeHtml = encodeURIComponent(`<div id="iframe"></div>`); + const html = encodeURIComponent( + `<div class="foo bar"> + <div id="child"></div> + </div> + <iframe src="https://example.org/document-builder.sjs?html=${iframeHtml}"></iframe>` + ); + const tab = await addTab( + "https://example.com/document-builder.sjs?html=" + html + ); + + const commands = await CommandsFactory.forTab(tab); + await commands.targetCommand.startListening(); + + info( + "Suggestions for 'di' with tag search, will match the two <div> elements in top document and the one in the iframe" + ); + await assertSuggestion( + commands, + { query: "", firstPart: "di", state: "tag" }, + [ + { + suggestion: "div", + count: 3, // Matches the two <div> in the top document and the one in the iframe + type: "tag", + }, + ] + ); + + info( + "Suggestions for 'ifram' with id search, will only match the <div> within the iframe" + ); + await assertSuggestion( + commands, + { query: "", firstPart: "ifram", state: "id" }, + [ + { + suggestion: "#iframe", + count: 1, + type: "id", + }, + ] + ); + + info( + "Suggestions for 'fo' with tag search, will match the class of the top <div> element" + ); + await assertSuggestion( + commands, + { query: "", firstPart: "fo", state: "tag" }, + [ + { + suggestion: ".foo", + count: 1, + type: "class", + }, + ] + ); + + info( + "Suggestions for classes, based on div elements, will match the two classes of top <div> element" + ); + await assertSuggestion( + commands, + { query: "div", firstPart: "", state: "class" }, + [ + { + suggestion: ".bar", + count: 1, + type: "class", + }, + { + suggestion: ".foo", + count: 1, + type: "class", + }, + ] + ); + + info("Suggestion for non-existent tag names will return no suggestion"); + await assertSuggestion( + commands, + { query: "", firstPart: "marquee", state: "tag" }, + [] + ); + + await commands.destroy(); +}); + +async function assertSuggestion( + commands, + { query, firstPart, state }, + expectedSuggestions +) { + const suggestions = await commands.inspectorCommand.getSuggestionsForQuery( + query, + firstPart, + state + ); + is( + suggestions.length, + expectedSuggestions.length, + "Got the expected number of suggestions" + ); + for (let i = 0; i < expectedSuggestions.length; i++) { + info(` ## Asserting suggestion #${i}:`); + const expectedSuggestion = expectedSuggestions[i]; + const [suggestion, count, type] = suggestions[i]; + is( + suggestion, + expectedSuggestion.suggestion, + "The suggested string is valid" + ); + is(count, expectedSuggestion.count, "The number of matches is valid"); + is(type, expectedSuggestion.type, "The type of match is valid"); + } +} diff --git a/devtools/shared/commands/inspector/tests/browser_inspector_command_search.js b/devtools/shared/commands/inspector/tests/browser_inspector_command_search.js new file mode 100644 index 0000000000..d7d25d3ce6 --- /dev/null +++ b/devtools/shared/commands/inspector/tests/browser_inspector_command_search.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Testing basic inspector search + +add_task(async () => { + const html = `<div> + <div> + <p>This is the paragraph node down in the tree</p> + </div> + <div class="child"></div> + <div class="child"></div> + <iframe src="data:text/html,${encodeURIComponent( + "<html><body><div class='frame-child'>foo</div></body></html>" + )}"> + </iframe> + </div>`; + + const tab = await addTab("data:text/html," + encodeURIComponent(html)); + + const commands = await CommandsFactory.forTab(tab); + await commands.targetCommand.startListening(); + + info("Search using text"); + await searchAndAssert( + commands, + { query: "paragraph", reverse: false }, + { resultsLength: 1, resultsIndex: 0 } + ); + + info("Search using class selector"); + info(" > Get first result "); + await searchAndAssert( + commands, + { query: ".child", reverse: false }, + { resultsLength: 2, resultsIndex: 0 } + ); + + info(" > Get next result "); + await searchAndAssert( + commands, + { query: ".child", reverse: false }, + { resultsLength: 2, resultsIndex: 1 } + ); + + info("Search using el selector with reverse option"); + info(" > Get first result "); + await searchAndAssert( + commands, + { query: "div", reverse: true }, + { resultsLength: 6, resultsIndex: 5 } + ); + + info(" > Get next result "); + await searchAndAssert( + commands, + { query: "div", reverse: true }, + { resultsLength: 6, resultsIndex: 4 } + ); + + info("Search for foo in remote frame"); + await searchAndAssert( + commands, + { query: ".frame-child", reverse: false }, + { resultsLength: 1, resultsIndex: 0 } + ); + + await commands.destroy(); +}); +/** + * Does an inspector search to find the next node and assert the results + * + * @param {Object} commands + * @param {Object} options + * options.query - search query + * options.reverse - search in reverse + * @param {Object} expected + * Holds the expected values + */ +async function searchAndAssert(commands, { query, reverse }, expected) { + const response = await commands.inspectorCommand.findNextNode(query, { + reverse, + }); + + is( + response.resultsLength, + expected.resultsLength, + "Got the expected no of results" + ); + + is( + response.resultsIndex, + expected.resultsIndex, + "Got the expected currently selected node index" + ); +} diff --git a/devtools/shared/commands/inspector/tests/head.js b/devtools/shared/commands/inspector/tests/head.js new file mode 100644 index 0000000000..73d9798446 --- /dev/null +++ b/devtools/shared/commands/inspector/tests/head.js @@ -0,0 +1,14 @@ +/* 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"; + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/devtools/client/inspector/test/shared-head.js", + this +); |