summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/mochitest/test_inspector-search.html
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/tests/mochitest/test_inspector-search.html')
-rw-r--r--devtools/server/tests/mochitest/test_inspector-search.html296
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>