summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/markup/test/browser_markup_mutation_02.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/inspector/markup/test/browser_markup_mutation_02.js191
1 files changed, 191 insertions, 0 deletions
diff --git a/devtools/client/inspector/markup/test/browser_markup_mutation_02.js b/devtools/client/inspector/markup/test/browser_markup_mutation_02.js
new file mode 100644
index 0000000000..8e7d3de4f4
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_mutation_02.js
@@ -0,0 +1,191 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that markup-containers in the markup-view do flash when their
+// corresponding DOM nodes mutate
+
+// Have to use the same timer functions used by the inspector.
+// eslint-disable-next-line mozilla/no-redeclare-with-import-autofix
+const { clearTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+const TEST_URL = URL_ROOT + "doc_markup_flashing.html";
+
+// The test data contains a list of mutations to test.
+// Each item is an object:
+// - desc: a description of the test step, for better logging
+// - mutate: a generator function that should make changes to the content DOM
+// - attribute: if set, the test will expect the corresponding attribute to
+// flash instead of the whole node
+// - flashedNode: [optional] the css selector of the node that is expected to
+// flash in the markup-view as a result of the mutation.
+// If missing, the rootNode (".list") will be expected to flash
+const TEST_DATA = [
+ {
+ desc: "Adding a new node should flash the new node",
+ async mutate() {
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const newLi = content.document.createElement("LI");
+ newLi.textContent = "new list item";
+ content.document.querySelector(".list").appendChild(newLi);
+ });
+ },
+ flashedNode: ".list li:nth-child(3)",
+ },
+ {
+ desc: "Removing a node should flash its parent",
+ async mutate() {
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const root = content.document.querySelector(".list");
+ root.removeChild(root.lastElementChild);
+ });
+ },
+ },
+ {
+ desc: "Re-appending an existing node should only flash this node",
+ async mutate() {
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const root = content.document.querySelector(".list");
+ root.appendChild(root.firstElementChild);
+ });
+ },
+ flashedNode: ".list .item:last-child",
+ },
+ {
+ desc: "Adding an attribute should flash the attribute",
+ attribute: "test-name",
+ async mutate() {
+ await setContentPageElementAttribute(
+ ".list",
+ "test-name",
+ "value-" + Date.now()
+ );
+ },
+ },
+ {
+ desc:
+ "Adding an attribute with css reserved characters should flash the " +
+ "attribute",
+ attribute: "one:two",
+ async mutate() {
+ await setContentPageElementAttribute(
+ ".list",
+ "one:two",
+ "value-" + Date.now()
+ );
+ },
+ },
+ {
+ desc: "Editing an attribute should flash the attribute",
+ attribute: "class",
+ async mutate() {
+ await setContentPageElementAttribute(
+ ".list",
+ "class",
+ "list value-" + Date.now()
+ );
+ },
+ },
+ {
+ desc: "Multiple changes to an attribute should flash the attribute",
+ attribute: "class",
+ async mutate() {
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const root = content.document.querySelector(".list");
+ root.removeAttribute("class");
+ root.setAttribute("class", "list value-" + Date.now());
+ root.setAttribute("class", "list value-" + Date.now());
+ root.removeAttribute("class");
+ root.setAttribute("class", "list value-" + Date.now());
+ root.setAttribute("class", "list value-" + Date.now());
+ });
+ },
+ },
+ {
+ desc: "Removing an attribute should flash the node",
+ async mutate() {
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
+ const root = content.document.querySelector(".list");
+ root.removeAttribute("class");
+ });
+ },
+ },
+];
+
+add_task(async function () {
+ await pushPref("privacy.reduceTimerPrecision", false);
+
+ const { inspector } = await openInspectorForURL(TEST_URL);
+
+ // Make sure mutated nodes flash for a very long time so we can more easily
+ // assert they do
+ inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60;
+
+ info("Getting the <ul.list> root node to test mutations on");
+ const rootNodeFront = await getNodeFront(".list", inspector);
+
+ info("Selecting the last element of the root node before starting");
+ await selectNode(".list .item:nth-child(2)", inspector);
+
+ for (const { mutate, flashedNode, desc, attribute } of TEST_DATA) {
+ info("Starting test: " + desc);
+
+ info("Mutating the DOM and listening for markupmutation event");
+ const onMutation = inspector.once("markupmutation");
+ await mutate();
+ const mutations = await onMutation;
+
+ info("Wait for the breadcrumbs widget to update if it needs to");
+ if (inspector.breadcrumbs._hasInterestingMutations(mutations)) {
+ await inspector.once("breadcrumbs-updated");
+ }
+
+ info("Asserting that the correct markup-container is flashing");
+ let flashingNodeFront = rootNodeFront;
+ if (flashedNode) {
+ flashingNodeFront = await getNodeFront(flashedNode, inspector);
+ }
+
+ if (attribute) {
+ await assertAttributeFlashing(flashingNodeFront, attribute, inspector);
+ } else {
+ await assertNodeFlashing(flashingNodeFront, inspector);
+ }
+ }
+});
+
+function assertNodeFlashing(nodeFront, inspector) {
+ const container = getContainerForNodeFront(nodeFront, inspector);
+ ok(container, "Markup container for node found");
+ ok(
+ container.tagState.classList.contains("theme-bg-contrast"),
+ "Markup container for node is flashing"
+ );
+
+ // Clear the mutation flashing timeout now that we checked the node was
+ // flashing.
+ clearTimeout(container._flashMutationTimer);
+ container._flashMutationTimer = null;
+ container.tagState.classList.remove("theme-bg-contrast");
+}
+
+function assertAttributeFlashing(nodeFront, attribute, inspector) {
+ const container = getContainerForNodeFront(nodeFront, inspector);
+ ok(container, "Markup container for node found");
+ ok(
+ container.editor.attrElements.get(attribute),
+ "Attribute exists on editor"
+ );
+
+ const attributeElement = container.editor.getAttributeElement(attribute);
+
+ ok(
+ attributeElement.classList.contains("theme-bg-contrast"),
+ "Element for " + attribute + " attribute is flashing"
+ );
+
+ attributeElement.classList.remove("theme-bg-contrast");
+}