diff options
Diffstat (limited to 'devtools/server/tests/mochitest/test_inspector-search.html')
-rw-r--r-- | devtools/server/tests/mochitest/test_inspector-search.html | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/devtools/server/tests/mochitest/test_inspector-search.html b/devtools/server/tests/mochitest/test_inspector-search.html new file mode 100644 index 000000000..623d3018d --- /dev/null +++ b/devtools/server/tests/mochitest/test_inspector-search.html @@ -0,0 +1,296 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=835896 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 835896</title> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script> + <script type="application/javascript;version=1.8"> +window.onload = function() { + const Cu = Components.utils; + const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); + const promise = require("promise"); + const {InspectorFront} = require("devtools/shared/fronts/inspector"); + const {WalkerSearch, WalkerIndex} = + require("devtools/server/actors/utils/walker-search"); + const {console} = Cu.import("resource://gre/modules/Console.jsm", {}); + + SimpleTest.waitForExplicitFinish(); + + let walkerActor = null; + let walkerSearch = null; + let inspectee = null; + let inspector = null; + + // WalkerSearch specific tests. This is to make sure search results are + // coming back as expected. + // See also test_inspector-search-front.html. + + addAsyncTest(function* setup() { + info ("Setting up inspector and walker actors."); + + let url = document.getElementById("inspectorContent").href; + + yield new promise(resolve => { + attachURL(url, function(err, client, tab, doc) { + inspectee = doc; + inspector = InspectorFront(client, tab); + resolve(); + }); + }); + + let walkerFront = yield inspector.getWalker(); + ok(walkerFront, "getWalker() should return an actor."); + + walkerActor = DebuggerServer._searchAllConnectionsForActor(walkerFront.actorID); + ok(walkerActor, + "Got a reference to the walker actor (" + walkerFront.actorID + ")"); + + walkerSearch = walkerActor.walkerSearch; + + runNextTest(); + }); + + addAsyncTest(function* testIndexExists() { + info ("Testing basic index APIs exist."); + + let index = new WalkerIndex(walkerActor); + ok(index.data.size > 0, "public index is filled after getting"); + + index.clearIndex(); + ok(!index._data, "private index is empty after clearing"); + ok(index.data.size > 0, "public index is filled after getting"); + + index.destroy(); + runNextTest(); + }); + + addAsyncTest(function* testSearchExists() { + info ("Testing basic search APIs exist."); + + ok(walkerSearch, "walker search exists on the WalkerActor"); + ok(walkerSearch.search, "walker search has `search` method"); + ok(walkerSearch.index, "walker search has `index` property"); + is(walkerSearch.walker, walkerActor, "referencing the correct WalkerActor"); + + let search = new WalkerSearch(walkerActor); + ok(search, "a new search instance can be created"); + ok(search.search, "new search instance has `search` method"); + ok(search.index, "new search instance has `index` property"); + isnot(search, walkerSearch, "new search instance differs from the WalkerActor's"); + + search.destroy(); + runNextTest(); + }); + + addAsyncTest(function* testEmptySearch() { + info ("Testing search with an empty query."); + results = walkerSearch.search(""); + is(results.length, 0, "No results when searching for ''"); + + results = walkerSearch.search(null); + is(results.length, 0, "No results when searching for null"); + + results = walkerSearch.search(undefined); + is(results.length, 0, "No results when searching for undefined"); + + results = walkerSearch.search(10); + is(results.length, 0, "No results when searching for 10"); + + runNextTest(); + }); + + addAsyncTest(function* testBasicSearchData() { + let testData = [ + { + desc: "Search for tag with one result.", + search: "body", + expected: [ + {node: inspectee.body, type: "tag"} + ] + }, + { + desc: "Search for tag with multiple results", + search: "h2", + expected: [ + {node: inspectee.querySelectorAll("h2")[0], type: "tag"}, + {node: inspectee.querySelectorAll("h2")[1], type: "tag"}, + {node: inspectee.querySelectorAll("h2")[2], type: "tag"}, + ] + }, + { + desc: "Search for selector with multiple results", + search: "body > h2", + expected: [ + {node: inspectee.querySelectorAll("h2")[0], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[1], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[2], type: "selector"}, + ] + }, + { + desc: "Search for selector with multiple results", + search: ":root h2", + expected: [ + {node: inspectee.querySelectorAll("h2")[0], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[1], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[2], type: "selector"}, + ] + }, + { + desc: "Search for selector with multiple results", + search: "* h2", + expected: [ + {node: inspectee.querySelectorAll("h2")[0], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[1], type: "selector"}, + {node: inspectee.querySelectorAll("h2")[2], type: "selector"}, + ] + }, + { + desc: "Search with multiple matches in a single tag expecting a single result", + search: "💩", + expected: [ + {node: inspectee.getElementById("💩"), type: "attributeValue"} + ] + }, + { + desc: "Search that has tag and text results", + search: "h1", + expected: [ + {node: inspectee.querySelector("h1"), type: "tag"}, + {node: inspectee.querySelector("h1 + p").childNodes[0], type: "text"}, + {node: inspectee.querySelector("h1 + p > strong").childNodes[0], type: "text"}, + ] + }, + ] + + for (let {desc, search, expected} of testData) { + info("Running test: " + desc); + let results = walkerSearch.search(search); + isDeeply(results, expected, + "Search returns correct results with '" + search + "'"); + } + + runNextTest(); + }); + + addAsyncTest(function* testPseudoElements() { + info ("Testing ::before and ::after element matching"); + + let beforeElt = new _documentWalker(inspectee.querySelector("#pseudo"), + inspectee.defaultView).firstChild(); + let afterElt = new _documentWalker(inspectee.querySelector("#pseudo"), + inspectee.defaultView).lastChild(); + let styleText = inspectee.querySelector("style").childNodes[0]; + + // ::before + let results = walkerSearch.search("::before"); + isDeeply(results, [ {node: beforeElt, type: "tag"} ], + "Tag search works for pseudo element"); + + results = walkerSearch.search("_moz_generated_content_before"); + is(results.length, 0, "No results for anon tag name"); + + results = walkerSearch.search("before element"); + isDeeply(results, [ + {node: styleText, type: "text"}, + {node: beforeElt, type: "text"} + ], "Text search works for pseudo element"); + + // ::after + results = walkerSearch.search("::after"); + isDeeply(results, [ {node: afterElt, type: "tag"} ], + "Tag search works for pseudo element"); + + results = walkerSearch.search("_moz_generated_content_after"); + is(results.length, 0, "No results for anon tag name"); + + results = walkerSearch.search("after element"); + isDeeply(results, [ + {node: styleText, type: "text"}, + {node: afterElt, type: "text"} + ], "Text search works for pseudo element"); + + runNextTest(); + }); + + addAsyncTest(function* testSearchMutationChangeResults() { + info ("Testing search before and after a mutation."); + let expected = [ + {node: inspectee.querySelectorAll("h3")[0], type: "tag"}, + {node: inspectee.querySelectorAll("h3")[1], type: "tag"}, + {node: inspectee.querySelectorAll("h3")[2], type: "tag"}, + ]; + + let results = walkerSearch.search("h3"); + isDeeply(results, expected, "Search works with tag results"); + + yield mutateDocumentAndWaitForMutation(() => { + expected[0].node.remove(); + }); + + results = walkerSearch.search("h3"); + isDeeply(results, [ + expected[1], + expected[2] + ], "Results are updated after removal"); + + yield new promise(resolve => { + info("Waiting for a mutation to happen"); + let observer = new inspectee.defaultView.MutationObserver(() => { + resolve(); + }); + observer.observe(inspectee, {attributes: true, subtree: true}); + inspectee.body.setAttribute("h3", "true"); + }); + + results = walkerSearch.search("h3"); + isDeeply(results, [ + {node: inspectee.body, type: "attributeName"}, + expected[1], + expected[2] + ], "Results are updated after addition"); + + yield new promise(resolve => { + info("Waiting for a mutation to happen"); + let observer = new inspectee.defaultView.MutationObserver(() => { + resolve(); + }); + observer.observe(inspectee, {attributes: true, childList: true, subtree: true}); + inspectee.body.removeAttribute("h3"); + expected[1].node.remove(); + expected[2].node.remove(); + }); + + results = walkerSearch.search("h3"); + is(results.length, 0, "Results are updated after removal"); + + runNextTest(); + }); + + runNextTest(); + + function mutateDocumentAndWaitForMutation(mutationFn) { + return new promise(resolve => { + info("Listening to markup mutation on the inspectee"); + let observer = new inspectee.defaultView.MutationObserver(resolve); + observer.observe(inspectee, {childList: true, subtree: true}); + mutationFn(); + }); + } +}; + </script> +</head> +<body> +<a id="inspectorContent" target="_blank" href="inspector-search-data.html">Test Document</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> |