summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/compatibility/test/browser
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /devtools/client/inspector/compatibility/test/browser
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/inspector/compatibility/test/browser')
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser.ini27
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_css-property_issue.js91
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-attribute-change.js127
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-dom-change.js150
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_markup-dom-change.js158
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_ruleview-attribute-change.js117
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_document-reload.js95
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js173
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_rule-change.js179
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_selected-node-change.js86
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js84
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_issue-node.js49
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_preference.js28
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_settings.js113
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_throbber.js69
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_all.js33
-rw-r--r--devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_some.js47
-rw-r--r--devtools/client/inspector/compatibility/test/browser/head.js283
18 files changed, 1909 insertions, 0 deletions
diff --git a/devtools/client/inspector/compatibility/test/browser/browser.ini b/devtools/client/inspector/compatibility/test/browser/browser.ini
new file mode 100644
index 0000000000..4d09958d0b
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser.ini
@@ -0,0 +1,27 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ head.js
+ !/devtools/client/inspector/test/head.js
+ !/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
+
+[browser_compatibility_css-property_issue.js]
+[browser_compatibility_dynamic_js-attribute-change.js]
+[browser_compatibility_dynamic_js-dom-change.js]
+[browser_compatibility_dynamic_markup-dom-change.js]
+[browser_compatibility_dynamic_ruleview-attribute-change.js]
+[browser_compatibility_event_document-reload.js]
+[browser_compatibility_event_panel-select.js]
+[browser_compatibility_event_rule-change.js]
+[browser_compatibility_event_selected-node-change.js]
+[browser_compatibility_event_top-level-target-change.js]
+[browser_compatibility_issue-node.js]
+[browser_compatibility_preference.js]
+[browser_compatibility_settings.js]
+[browser_compatibility_throbber.js]
+[browser_compatibility_unsupported-browsers_all.js]
+[browser_compatibility_unsupported-browsers_some.js]
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_css-property_issue.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_css-property_issue.js
new file mode 100644
index 0000000000..dc3df0d1f0
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_css-property_issue.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that unsupported CSS properties are correctly reported as issues.
+
+const {
+ COMPATIBILITY_ISSUE_TYPE,
+} = require("resource://devtools/shared/constants.js");
+
+const TEST_URI = `
+ <style>
+ body {
+ color: blue;
+ scrollbar-width: thin;
+ user-modify: read-only;
+ hyphenate-limit-chars: auto;
+ overflow-clip-box: padding-box;
+ }
+ div {
+ ruby-align: center;
+ }
+ </style>
+ <body>
+ <div>test</div>
+ </body>
+`;
+
+const TEST_DATA_SELECTED = [
+ {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ deprecated: false,
+ experimental: false,
+ },
+ {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY_ALIASES,
+ property: "user-modify",
+ url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
+ aliases: ["user-modify"],
+ deprecated: true,
+ experimental: false,
+ },
+ {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "hyphenate-limit-chars",
+ // No MDN url but a spec one
+ specUrl:
+ "https://drafts.csswg.org/css-text-4/#propdef-hyphenate-limit-chars",
+ deprecated: false,
+ experimental: false,
+ },
+ {
+ // No MDN url nor spec url
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "overflow-clip-box",
+ deprecated: false,
+ experimental: false,
+ },
+];
+
+const TEST_DATA_ALL = [
+ ...TEST_DATA_SELECTED,
+ {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ deprecated: false,
+ experimental: true,
+ },
+];
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { allElementsPane, selectedElementPane } =
+ await openCompatibilityView();
+
+ // If the test fail because the properties used are no longer in the dataset, or they
+ // now have mdn/spec url although we expected them not to, uncomment the next line
+ // to get all the properties in the dataset that don't have a MDN url.
+ // logCssCompatDataPropertiesWithoutMDNUrl()
+
+ info("Check the content of the issue list on the selected element");
+ await assertIssueList(selectedElementPane, TEST_DATA_SELECTED);
+
+ info("Check the content of the issue list on all elements");
+ await assertIssueList(allElementsPane, TEST_DATA_ALL);
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-attribute-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-attribute-change.js
new file mode 100644
index 0000000000..6280e73278
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-attribute-change.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ COMPATIBILITY_ISSUE_TYPE,
+} = require("resource://devtools/shared/constants.js");
+
+const {
+ COMPATIBILITY_UPDATE_NODE_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+// Test the behavior rules are dynamically added
+
+const ISSUE_OUTLINE_RADIUS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "-moz-user-input",
+ url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input",
+ deprecated: true,
+ experimental: false,
+};
+
+const ISSUE_HYPHENS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY_ALIASES,
+ aliases: ["hyphens"],
+ property: "hyphens",
+ url: "https://developer.mozilla.org/docs/Web/CSS/hyphens",
+ deprecated: false,
+ experimental: false,
+};
+
+const TEST_URI = `
+ <style>
+ .issue {
+ -moz-user-input: none;
+ }
+ </style>
+ <body>
+ <div class="test"></div>
+ </body>
+`;
+
+add_task(async function () {
+ info("Testing dynamic style change using JavaScript");
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Testing inline style change due to JavaScript execution");
+ const onPanelUpdate = waitForUpdateSelectedNodeAction(inspector.store);
+ info("Select the div to undergo mutation");
+ await selectNode(".test", inspector);
+ await onPanelUpdate;
+
+ info("Check initial issues");
+ await assertIssueList(selectedElementPane, []);
+ await assertIssueList(allElementsPane, []);
+
+ info("Adding inline style with compatibility issue");
+ await testAttributeMutation(
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_HYPHENS],
+ [ISSUE_HYPHENS],
+ async function () {
+ content.document.querySelector(".test").style.hyphens = "none";
+ }
+ );
+
+ info("Adding a class with declarations having compatibility issue");
+ await testAttributeMutation(
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_HYPHENS, ISSUE_OUTLINE_RADIUS],
+ [ISSUE_HYPHENS, ISSUE_OUTLINE_RADIUS],
+ async function () {
+ content.document.querySelector(".test").classList.add("issue");
+ }
+ );
+
+ info("Removing a class with declarations having compatibility issue");
+ await testAttributeMutation(
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_HYPHENS],
+ [ISSUE_HYPHENS],
+ async function () {
+ content.document.querySelector(".test").classList.remove("issue");
+ }
+ );
+
+ await removeTab(tab);
+});
+
+async function testAttributeMutation(
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ expectedSelectedElementIssues,
+ expectedAllElementsIssues,
+ contentTaskFunction
+) {
+ const onPanelUpdate = Promise.all([
+ inspector.once("markupmutation"),
+ waitForDispatch(inspector.store, COMPATIBILITY_UPDATE_NODE_COMPLETE),
+ ]);
+ info("Run the task in webpage context");
+ await ContentTask.spawn(tab.linkedBrowser, {}, contentTaskFunction);
+ info("Wait for changes to reflect");
+ await onPanelUpdate;
+
+ info("Check issues listed in selected element pane");
+ await assertIssueList(selectedElementPane, expectedSelectedElementIssues);
+ info("Check issues listed in all issues pane");
+ await assertIssueList(allElementsPane, expectedAllElementsIssues);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-dom-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-dom-change.js
new file mode 100644
index 0000000000..1d8488a468
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_js-dom-change.js
@@ -0,0 +1,150 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ COMPATIBILITY_ISSUE_TYPE,
+} = require("resource://devtools/shared/constants.js");
+
+const {
+ COMPATIBILITY_APPEND_NODE_COMPLETE,
+ COMPATIBILITY_CLEAR_DESTROYED_NODES,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+// Test the behavior rules are dynamically added
+
+const ISSUE_OUTLINE_RADIUS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "-moz-user-input",
+ url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input",
+ deprecated: true,
+ experimental: false,
+};
+
+const ISSUE_HYPHENS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY_ALIASES,
+ aliases: ["hyphens"],
+ property: "hyphens",
+ url: "https://developer.mozilla.org/docs/Web/CSS/hyphens",
+ deprecated: false,
+ experimental: false,
+};
+
+const TEST_URI = `
+ <style>
+ .child {
+ -moz-user-input: none;
+ }
+ </style>
+ <body></body>
+`;
+
+add_task(async function () {
+ info("Testing dynamic DOM mutation using JavaScript");
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Check initial issues");
+ await assertIssueList(selectedElementPane, []);
+ await assertIssueList(allElementsPane, []);
+
+ info("Append nodes dynamically using JavaScript");
+ await testNodeMutation(
+ ".child",
+ COMPATIBILITY_APPEND_NODE_COMPLETE,
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_OUTLINE_RADIUS],
+ [ISSUE_HYPHENS, ISSUE_OUTLINE_RADIUS],
+ async function () {
+ const doc = content.document;
+ const parent = doc.querySelector("body");
+
+ const newElementWithIssue = doc.createElement("div");
+ newElementWithIssue.style.hyphens = "none";
+
+ const parentOfIssueElement = doc.createElement("div");
+ parentOfIssueElement.classList.add("parent");
+ const child = doc.createElement("div");
+ child.classList.add("child");
+ parentOfIssueElement.appendChild(child);
+
+ parent.appendChild(newElementWithIssue);
+ parent.appendChild(parentOfIssueElement);
+ }
+ );
+
+ info("Remove node whose child has compatibility issue");
+ await testNodeMutation(
+ "div",
+ COMPATIBILITY_CLEAR_DESTROYED_NODES,
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_HYPHENS],
+ [ISSUE_HYPHENS],
+ async function () {
+ const doc = content.document;
+ const parent = doc.querySelector(".parent");
+ parent.remove();
+ }
+ );
+
+ info("Remove node which has compatibility issue");
+ await testNodeMutation(
+ "body",
+ COMPATIBILITY_CLEAR_DESTROYED_NODES,
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [],
+ [],
+ async function () {
+ const doc = content.document;
+ const issueElement = doc.querySelector("div");
+ issueElement.remove();
+ }
+ );
+
+ await removeTab(tab);
+});
+
+async function testNodeMutation(
+ selector,
+ action,
+ tab,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ expectedSelectedElementIssues,
+ expectedAllElementsIssues,
+ contentTaskFunction
+) {
+ let onPanelUpdate = Promise.all([
+ inspector.once("markupmutation"),
+ waitForDispatch(inspector.store, action),
+ ]);
+ info("Add a new node with issue and another node whose child has the issue");
+ await ContentTask.spawn(tab.linkedBrowser, {}, contentTaskFunction);
+ info("Wait for changes");
+ await onPanelUpdate;
+
+ onPanelUpdate = waitForUpdateSelectedNodeAction(inspector.store);
+ await selectNode(selector, inspector);
+ await onPanelUpdate;
+
+ info("Check element issues");
+ await assertIssueList(selectedElementPane, expectedSelectedElementIssues);
+
+ info("Check all issues");
+ await assertIssueList(allElementsPane, expectedAllElementsIssues);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_markup-dom-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_markup-dom-change.js
new file mode 100644
index 0000000000..0a600ffddf
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_markup-dom-change.js
@@ -0,0 +1,158 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ COMPATIBILITY_ISSUE_TYPE,
+} = require("resource://devtools/shared/constants.js");
+
+const {
+ COMPATIBILITY_APPEND_NODE_COMPLETE,
+ COMPATIBILITY_REMOVE_NODE_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+// Test the behavior rules are dynamically added
+
+const ISSUE_OUTLINE_RADIUS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "-moz-user-input",
+ url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input",
+ deprecated: true,
+ experimental: false,
+};
+
+const ISSUE_HYPHENS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY_ALIASES,
+ aliases: ["hyphens"],
+ property: "hyphens",
+ url: "https://developer.mozilla.org/docs/Web/CSS/hyphens",
+ deprecated: false,
+ experimental: false,
+};
+
+const TEST_URI = `
+ <style>
+ div {
+ -moz-user-input: none;
+ }
+ </style>
+ <body>
+ <div></div>
+ <div class="parent">
+ <div style="hyphens: none"></div>
+ </div>
+ </body>
+`;
+
+add_task(async function () {
+ info("Testing dynamic DOM mutation using JavaScript");
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector } = await openCompatibilityView();
+
+ info("Check initial issues");
+ await assertIssueList(allElementsPane, [ISSUE_OUTLINE_RADIUS, ISSUE_HYPHENS]);
+
+ info("Delete node whose child node has CSS compatibility issue");
+ await testNodeRemoval(".parent", inspector, allElementsPane, [
+ ISSUE_OUTLINE_RADIUS,
+ ]);
+
+ info("Delete node that has CSS compatibility issue");
+ await testNodeRemoval("div", inspector, allElementsPane, []);
+
+ info("Add node that has CSS compatibility issue");
+ await testNodeAddition("div", inspector, allElementsPane, [
+ ISSUE_OUTLINE_RADIUS,
+ ]);
+
+ await removeTab(tab);
+});
+
+/**
+ * Simulate a click on the markup-container (a line in the markup-view)
+ * that corresponds to the selector passed.
+ * This overrides the definition in inspector/test/head.js which times
+ * out when the container to be clicked is already the selected node.
+ * @param {String|NodeFront} selector
+ * @param {InspectorPanel} inspector The instance of InspectorPanel currently
+ * loaded in the toolbox
+ * @return {Promise} Resolves when the node has been selected.
+ */
+var clickContainer = async function (selector, inspector) {
+ info("Clicking on the markup-container for node " + selector);
+
+ const nodeFront = await getNodeFront(selector, inspector);
+ const container = getContainerForNodeFront(nodeFront, inspector);
+
+ const updated = container.selected
+ ? Promise.resolve()
+ : inspector.once("inspector-updated");
+ EventUtils.synthesizeMouseAtCenter(
+ container.tagLine,
+ { type: "mousedown" },
+ inspector.markup.doc.defaultView
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ container.tagLine,
+ { type: "mouseup" },
+ inspector.markup.doc.defaultView
+ );
+ return updated;
+};
+
+async function deleteNode(inspector, selector) {
+ info("Select node " + selector + " and make sure it is focused");
+ await selectNode(selector, inspector);
+ await clickContainer(selector, inspector);
+
+ info("Delete the node");
+ const mutated = inspector.once("markupmutation");
+ const updated = inspector.once("inspector-updated");
+ EventUtils.sendKey("delete", inspector.panelWin);
+ await mutated;
+ await updated;
+}
+
+async function testNodeAddition(
+ selector,
+ inspector,
+ allElementsPane,
+ expectedAllElementsIssues
+) {
+ let onPanelUpdate = Promise.all([
+ inspector.once("markupmutation"),
+ waitForDispatch(inspector.store, COMPATIBILITY_APPEND_NODE_COMPLETE),
+ ]);
+ info("Add a new node");
+ await inspector.addNode();
+ await onPanelUpdate;
+
+ onPanelUpdate = waitForUpdateSelectedNodeAction(inspector.store);
+ await selectNode(selector, inspector);
+ await onPanelUpdate;
+
+ info("Check issues list for the webpage");
+ await assertIssueList(allElementsPane, expectedAllElementsIssues);
+}
+
+async function testNodeRemoval(
+ selector,
+ inspector,
+ allElementsPane,
+ expectedAllElementsIssues
+) {
+ const onPanelUpdate = Promise.all([
+ inspector.once("markupmutation"),
+ waitForDispatch(inspector.store, COMPATIBILITY_REMOVE_NODE_COMPLETE),
+ ]);
+ info(`Delete the node with selector ${selector}`);
+ await deleteNode(inspector, selector);
+ await onPanelUpdate;
+
+ info("Check issues list for the webpage");
+ await assertIssueList(allElementsPane, expectedAllElementsIssues);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_ruleview-attribute-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_ruleview-attribute-change.js
new file mode 100644
index 0000000000..920e360ef0
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_dynamic_ruleview-attribute-change.js
@@ -0,0 +1,117 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {
+ COMPATIBILITY_ISSUE_TYPE,
+} = require("resource://devtools/shared/constants.js");
+
+const {
+ COMPATIBILITY_UPDATE_NODE_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+// Test the behavior rules are dynamically added
+
+const ISSUE_OUTLINE_RADIUS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
+ property: "-moz-user-input",
+ url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input",
+ deprecated: true,
+ experimental: false,
+};
+
+const ISSUE_HYPHENS = {
+ type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY_ALIASES,
+ aliases: ["hyphens"],
+ property: "hyphens",
+ url: "https://developer.mozilla.org/docs/Web/CSS/hyphens",
+ deprecated: false,
+ experimental: false,
+};
+
+const TEST_URI = `
+ <style>
+ .issue {
+ -moz-user-input: none;
+ }
+ </style>
+ <body>
+ <div class="test issue"></div>
+ </body>
+`;
+
+add_task(async function () {
+ info("Testing dynamic style change via the devtools inspector's rule view");
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Select the div to undergo mutation");
+ const waitForCompatibilityListUpdate = waitForUpdateSelectedNodeAction(
+ inspector.store
+ );
+ await selectNode(".test.issue", inspector);
+ await waitForCompatibilityListUpdate;
+
+ info("Check initial issues");
+ await checkPanelIssues(selectedElementPane, allElementsPane, [
+ ISSUE_OUTLINE_RADIUS,
+ ]);
+
+ await addNewRule(
+ "hyphens",
+ "none",
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ [ISSUE_OUTLINE_RADIUS, ISSUE_HYPHENS]
+ );
+
+ info("Toggle the inline issue rendering it disable");
+ await togglePropStatusOnRuleView(inspector, 0, 0);
+ info("Check the issues listed in panel");
+ await checkPanelIssues(selectedElementPane, allElementsPane, [
+ ISSUE_OUTLINE_RADIUS,
+ ]);
+
+ info("Toggle the class rule rendering it disabled");
+ await togglePropStatusOnRuleView(inspector, 1, 0);
+ info("Check the panel issues listed in panel");
+ await checkPanelIssues(selectedElementPane, allElementsPane, []);
+
+ await removeTab(tab);
+});
+
+async function addNewRule(
+ newDeclaration,
+ value,
+ inspector,
+ selectedElementPane,
+ allElementsPane,
+ issue
+) {
+ const { view } = await openRuleView();
+ const waitForCompatibilityListUpdate = waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_NODE_COMPLETE
+ );
+
+ info("Add a new inline property");
+ await addProperty(view, 0, newDeclaration, value);
+ info("Wait for changes");
+ await waitForCompatibilityListUpdate;
+
+ info("Check issues list for element and the webpage");
+ await checkPanelIssues(selectedElementPane, allElementsPane, issue);
+}
+
+async function checkPanelIssues(selectedElementPane, allElementsPane, issues) {
+ info("Check selected element issues");
+ await assertIssueList(selectedElementPane, issues);
+ info("Check all panel issues");
+ await assertIssueList(allElementsPane, issues);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_document-reload.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_document-reload.js
new file mode 100644
index 0000000000..a7f18e0811
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_document-reload.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the issues after reloading the browsing document.
+
+const TEST_URI = `
+ <style>
+ body {
+ color: blue;
+ ruby-align: center;
+ user-modify: read-only;
+ }
+ div {
+ scrollbar-width: thin;
+ }
+ </style>
+ <body>
+ <div>test</div>
+ </body>
+`;
+
+const TEST_DATA_SELECTED = [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ {
+ property: "user-modify",
+ url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
+ },
+];
+
+const TEST_DATA_ALL = [
+ ...TEST_DATA_SELECTED,
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+];
+
+const {
+ COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+add_task(async function () {
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Check the issues on the selected element");
+ await assertIssueList(selectedElementPane, TEST_DATA_SELECTED);
+ info("Check the issues on all elements");
+ await assertIssueList(allElementsPane, TEST_DATA_ALL);
+
+ let isUpdateSelectedNodeFailure = false;
+ let isUpdateTopLevelTargetFailure = false;
+ waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE
+ ).then(() => {
+ isUpdateSelectedNodeFailure = true;
+ });
+ waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_FAILURE
+ ).then(() => {
+ isUpdateTopLevelTargetFailure = true;
+ });
+
+ info("Reload the browsing page");
+ const onReloaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ const onUpdateSelectedNode = waitForUpdateSelectedNodeAction(inspector.store);
+ const onUpdateTopLevelTarget = waitForUpdateTopLevelTargetAction(
+ inspector.store
+ );
+ gBrowser.reloadTab(tab);
+ await Promise.all([onReloaded, onUpdateSelectedNode, onUpdateTopLevelTarget]);
+
+ info("Check whether the failure action will be fired or not");
+ ok(
+ !isUpdateSelectedNodeFailure && !isUpdateTopLevelTargetFailure,
+ "No error occurred"
+ );
+
+ info("Check the issues on the selected element again");
+ await assertIssueList(selectedElementPane, TEST_DATA_SELECTED);
+ info("Check the issues on all elements again");
+ await assertIssueList(allElementsPane, TEST_DATA_ALL);
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js
new file mode 100644
index 0000000000..9aa845db0d
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the behavior when the panel is selected.
+
+const TEST_URI = "<body style='background-color: lime;'><div>test</div></body>";
+const TEST_ANOTHER_URI = "<body></body>";
+
+const {
+ COMPATIBILITY_UPDATE_SELECTED_NODE_START,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+add_task(async function () {
+ info(
+ "Check that the panel does not update when no changes occur while hidden"
+ );
+
+ await pushPref("devtools.inspector.activeSidebar", "");
+
+ const tab = await addTab(_toDataURL(TEST_URI));
+ const { inspector } = await openCompatibilityView();
+
+ info("Select another sidebar panel");
+ await _selectSidebarPanel(inspector, "changesview");
+
+ info("Select the compatibility panel again");
+ let isSelectedNodeUpdated = false;
+ let isTopLevelTargetUpdated = false;
+ waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_SELECTED_NODE_START
+ ).then(() => {
+ isSelectedNodeUpdated = true;
+ });
+ waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START
+ ).then(() => {
+ isTopLevelTargetUpdated = true;
+ });
+
+ await _selectSidebarPanel(inspector, "compatibilityview");
+
+ // Check above both flags after taking enough time.
+ await wait(1000);
+
+ ok(!isSelectedNodeUpdated, "Avoid updating the selected node pane");
+ ok(!isTopLevelTargetUpdated, "Avoid updating the top level target pane");
+
+ await removeTab(tab);
+});
+
+add_task(async function () {
+ info(
+ "Check that the panel only updates for the selected node when the node is changed while the panel is hidden"
+ );
+
+ await pushPref("devtools.inspector.activeSidebar", "");
+
+ const tab = await addTab(_toDataURL(TEST_URI));
+ const { inspector } = await openCompatibilityView();
+
+ info("Select another sidebar panel");
+ await _selectSidebarPanel(inspector, "changesview");
+
+ info("Select another node");
+ await selectNode("div", inspector);
+
+ info("Select the compatibility panel again");
+ const onSelectedNodePaneUpdated = waitForUpdateSelectedNodeAction(
+ inspector.store
+ );
+ let isTopLevelTargetUpdated = false;
+ waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START
+ ).then(() => {
+ isTopLevelTargetUpdated = true;
+ });
+
+ await _selectSidebarPanel(inspector, "compatibilityview");
+
+ await onSelectedNodePaneUpdated;
+ ok(true, "Update the selected node pane");
+ ok(!isTopLevelTargetUpdated, "Avoid updating the top level target pane");
+
+ await removeTab(tab);
+});
+
+add_task(async function () {
+ info(
+ "Check that both panes update when the top-level target changed while the panel is hidden"
+ );
+
+ await pushPref("devtools.inspector.activeSidebar", "");
+
+ const tab = await addTab(_toDataURL(TEST_URI));
+ const { inspector } = await openCompatibilityView();
+
+ info("Select another sidebar panel");
+ await _selectSidebarPanel(inspector, "changesview");
+
+ info("Navigate to another page");
+ BrowserTestUtils.loadURIString(
+ tab.linkedBrowser,
+ _toDataURL(TEST_ANOTHER_URI)
+ );
+
+ info("Select the compatibility panel again");
+ const onSelectedNodePaneUpdated = waitForUpdateSelectedNodeAction(
+ inspector.store
+ );
+ const onTopLevelTargetPaneUpdated = waitForUpdateTopLevelTargetAction(
+ inspector.store
+ );
+
+ await _selectSidebarPanel(inspector, "compatibilityview");
+
+ await onSelectedNodePaneUpdated;
+ await onTopLevelTargetPaneUpdated;
+ ok(true, "Update both panes");
+
+ await removeTab(tab);
+});
+
+add_task(async function () {
+ info(
+ "Check that both panes update when a rule is changed changed while the panel is hidden"
+ );
+
+ await pushPref("devtools.inspector.activeSidebar", "");
+
+ info("Disable 3 pane mode");
+ await pushPref("devtools.inspector.three-pane-enabled", false);
+
+ const tab = await addTab(_toDataURL(TEST_URI));
+ const { inspector } = await openCompatibilityView();
+
+ info("Select rule view");
+ await _selectSidebarPanel(inspector, "ruleview");
+
+ info("Change a rule");
+ await togglePropStatusOnRuleView(inspector, 0, 0);
+
+ info("Select the compatibility panel again");
+ const onSelectedNodePaneUpdated = waitForUpdateSelectedNodeAction(
+ inspector.store
+ );
+ const onTopLevelTargetPaneUpdated = waitForUpdateTopLevelTargetAction(
+ inspector.store
+ );
+
+ await _selectSidebarPanel(inspector, "compatibilityview");
+
+ await onSelectedNodePaneUpdated;
+ await onTopLevelTargetPaneUpdated;
+ ok(true, "Update both panes");
+
+ await removeTab(tab);
+});
+
+async function _selectSidebarPanel(inspector, toolId) {
+ const onSelected = inspector.sidebar.once(`${toolId}-selected`);
+ inspector.sidebar.select(toolId);
+ await onSelected;
+}
+
+function _toDataURL(content) {
+ return "data:text/html;charset=utf-8," + encodeURIComponent(content);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_rule-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_rule-change.js
new file mode 100644
index 0000000000..91b29b488b
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_rule-change.js
@@ -0,0 +1,179 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether the content of the issue list will be changed when the rules are changed
+// on the rule view.
+
+const TEST_URI = `
+ <style>
+ .test-class {
+ ruby-align: center;
+ }
+ div {
+ scrollbar-width: thin;
+ }
+ </style>
+ <div class="test-class">test class</div>
+ <div>test</div>
+`;
+
+const TEST_DATA_SELECTED = {
+ fullRule: {
+ expectedProperties: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "ruby-align",
+ nodes: [],
+ },
+ {
+ property: "scrollbar-width",
+ nodes: [],
+ },
+ ],
+ },
+ classRule: {
+ expectedProperties: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "ruby-align",
+ nodes: [],
+ },
+ ],
+ },
+ elementRule: {
+ expectedProperties: [
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "scrollbar-width",
+ nodes: [],
+ },
+ ],
+ },
+};
+
+const TEST_DATA_ALL = {
+ fullRule: {
+ expectedProperties: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "ruby-align",
+ nodes: ["div.test-class"],
+ },
+ {
+ property: "scrollbar-width",
+ nodes: ["div.test-class", "div"],
+ },
+ ],
+ },
+ classRule: {
+ expectedProperties: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "ruby-align",
+ nodes: ["div.test-class"],
+ },
+ ],
+ },
+ elementRule: {
+ expectedProperties: [
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ ],
+ expectedNodes: [
+ {
+ property: "scrollbar-width",
+ nodes: ["div.test-class", "div"],
+ },
+ ],
+ },
+};
+
+const {
+ COMPATIBILITY_UPDATE_NODES_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+add_task(async function () {
+ info("Enable 3 pane mode");
+ await pushPref("devtools.inspector.three-pane-enabled", true);
+
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+ await selectNode(".test-class", inspector);
+
+ info("Check the initial issue");
+ await assertAll(selectedElementPane, TEST_DATA_SELECTED.fullRule);
+ await assertAll(allElementsPane, TEST_DATA_ALL.fullRule);
+
+ info("Check the issue after unchecking class rule");
+ await _togglePropStatus(inspector, 1, 0);
+ await assertAll(selectedElementPane, TEST_DATA_SELECTED.elementRule);
+ await assertAll(allElementsPane, TEST_DATA_ALL.elementRule);
+
+ info("Check the issue after unchecking div rule");
+ await _togglePropStatus(inspector, 2, 0);
+ await assertIssueList(selectedElementPane, []);
+ await assertIssueList(allElementsPane, []);
+
+ info("Check the issue after reverting class rule");
+ await _togglePropStatus(inspector, 1, 0);
+ await assertAll(selectedElementPane, TEST_DATA_SELECTED.classRule);
+ await assertAll(allElementsPane, TEST_DATA_ALL.classRule);
+
+ info("Check the issue after reverting div rule");
+ await _togglePropStatus(inspector, 2, 0);
+ await assertAll(selectedElementPane, TEST_DATA_SELECTED.fullRule);
+ await assertAll(allElementsPane, TEST_DATA_ALL.fullRule);
+});
+
+async function assertAll(pane, { expectedProperties, expectedNodes }) {
+ await assertIssueList(pane, expectedProperties);
+ await assertNodeList(pane, expectedNodes);
+}
+
+async function _togglePropStatus(inspector, ruleIndex, propIndex) {
+ const onNodesUpdated = waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_NODES_COMPLETE
+ );
+ await togglePropStatusOnRuleView(inspector, ruleIndex, propIndex);
+ await onNodesUpdated;
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_selected-node-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_selected-node-change.js
new file mode 100644
index 0000000000..d24f450968
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_selected-node-change.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether the content of the issue list will be changed when the new node is selected.
+
+const TEST_URI = `
+ <style>
+ body {
+ ruby-align: center;
+ }
+
+ .has-issue {
+ scrollbar-width: thin;
+ user-modify: read-only;
+ }
+
+ .no-issue {
+ color: black;
+ }
+ </style>
+ <body>
+ <div class="has-issue">has issue</div>
+ <div class="no-issue">no issue</div>
+ </body>
+`;
+
+const TEST_DATA_SELECTED = [
+ {
+ selector: ".has-issue",
+ expectedIssues: [
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ {
+ property: "user-modify",
+ url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
+ },
+ ],
+ },
+ {
+ selector: ".no-issue",
+ expectedIssues: [],
+ },
+ {
+ selector: "body",
+ expectedIssues: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ ],
+ },
+];
+
+const TEST_DATA_ALL = [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ {
+ property: "user-modify",
+ url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
+ },
+];
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ for (const { selector, expectedIssues } of TEST_DATA_SELECTED) {
+ info(`Check the issue list for ${selector} node`);
+ await selectNode(selector, inspector);
+ await assertIssueList(selectedElementPane, expectedIssues);
+ info("Check whether the issues on all elements pane are not changed");
+ await assertIssueList(allElementsPane, TEST_DATA_ALL);
+ }
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js
new file mode 100644
index 0000000000..b6a0239d46
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the issues after navigating to another page.
+
+const TEST_DATA_ISSUES = {
+ uri: `
+ <style>
+ body {
+ ruby-align: center;
+ }
+ div {
+ scrollbar-width: thin;
+ }
+ </style>
+ <body>
+ <div>test</div>
+ </body>
+ `,
+ expectedIssuesOnSelected: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ ],
+ expectedIssuesOnAll: [
+ {
+ property: "ruby-align",
+ url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
+ },
+ {
+ property: "scrollbar-width",
+ url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
+ },
+ ],
+};
+
+const TEST_DATA_NO_ISSUES = {
+ uri: "<body></body>",
+ expectedIssuesOnSelected: [],
+ expectedIssuesOnAll: [],
+};
+
+add_task(async function () {
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_DATA_ISSUES.uri)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Check issues at initial");
+ await assertIssues(selectedElementPane, allElementsPane, TEST_DATA_ISSUES);
+
+ info("Navigate to next uri that has no issues");
+ await navigateTo(TEST_DATA_NO_ISSUES.uri, tab, inspector);
+ info("Check issues after navigating");
+ await assertIssues(selectedElementPane, allElementsPane, TEST_DATA_NO_ISSUES);
+
+ info("Revert the uri");
+ await navigateTo(TEST_DATA_ISSUES.uri, tab, inspector);
+ info("Check issues after reverting");
+ await assertIssues(selectedElementPane, allElementsPane, TEST_DATA_ISSUES);
+});
+
+async function assertIssues(
+ selectedElementPane,
+ allElementsPane,
+ { expectedIssuesOnSelected, expectedIssuesOnAll }
+) {
+ await assertIssueList(selectedElementPane, expectedIssuesOnSelected);
+ await assertIssueList(allElementsPane, expectedIssuesOnAll);
+}
+
+async function navigateTo(uri, tab, { store }) {
+ uri = "data:text/html;charset=utf-8," + encodeURIComponent(uri);
+ const onSelectedNodeUpdated = waitForUpdateSelectedNodeAction(store);
+ const onTopLevelTargetUpdated = waitForUpdateTopLevelTargetAction(store);
+ const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, uri);
+ await Promise.all([onLoaded, onSelectedNodeUpdated, onTopLevelTargetUpdated]);
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_issue-node.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_issue-node.js
new file mode 100644
index 0000000000..b99dfd4062
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_issue-node.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test displaying the nodes that caused issues.
+
+const TEST_URI = `
+ <style>
+ body {
+ user-modify: read-only;
+ }
+ div {
+ user-modify: read-only;
+ scrollbar-width: thin;
+ }
+ </style>
+ <body>
+ <div>div</div>
+ </body>
+`;
+
+const TEST_DATA_ALL = [
+ {
+ property: "user-modify",
+ nodes: ["body", "div"],
+ },
+ {
+ property: "scrollbar-width",
+ nodes: ["div"],
+ },
+];
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ const { allElementsPane, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Check nodes that caused issues on the selected element");
+ is(
+ selectedElementPane.querySelectorAll(".compatibility-node-item").length,
+ 0,
+ "Nodes are not displayed on the selected element"
+ );
+
+ info("Check nodes that caused issues on all elements");
+ await assertNodeList(allElementsPane, TEST_DATA_ALL);
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_preference.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_preference.js
new file mode 100644
index 0000000000..5c54206c2d
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_preference.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether the compatibility tool is enabled or not according to the preference.
+
+add_task(async function () {
+ info("Check the compatibility tool is enabled if the pref is on");
+ await addTab("data:text/html;charset=utf-8,test");
+ await pushPref("devtools.inspector.compatibility.enabled", true);
+ const { inspector } = await openRuleView();
+ const compatibilityTab = inspector.panelDoc.getElementById(
+ "compatibilityview-tab"
+ );
+ ok(compatibilityTab, "The compatibility tool is enabled");
+});
+
+add_task(async function () {
+ info("Check the compatibility tool is disabled if the pref is off");
+ await addTab("data:text/html;charset=utf-8,test");
+ await pushPref("devtools.inspector.compatibility.enabled", false);
+ const { inspector } = await openRuleView();
+ const compatibilityTab = inspector.panelDoc.getElementById(
+ "compatibilityview-tab"
+ );
+ ok(!compatibilityTab, "The compatibility tool is disabled");
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_settings.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_settings.js
new file mode 100644
index 0000000000..36e4d57735
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_settings.js
@@ -0,0 +1,113 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether settings page works.
+
+const TEST_URI = `
+ <style>
+ body {
+ text-size-adjust: none;
+ }
+ div {
+ text-size-adjust: none;
+ }
+ </style>
+ <body><div></div></body>
+`;
+
+const {
+ COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+add_task(async function () {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(
+ "devtools.inspector.compatibility.target-browsers"
+ );
+ });
+
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, panel } = await openCompatibilityView();
+ const { store } = inspector;
+
+ info("Check initial state");
+ ok(
+ panel.querySelector(`.compatibility-browser-icon__image[src*="firefox"]`),
+ "Firefox browsers are the target"
+ );
+
+ info("Make Firefox browsers out of target");
+ await updateTargetBrowsers(panel, store, id => !id.includes("firefox"));
+ ok(
+ !panel.querySelector(`.compatibility-browser-icon__image[src*="firefox"]`),
+ "Firefox browsers are not the target"
+ );
+
+ info("Make all browsers out of target");
+ await updateTargetBrowsers(panel, store, () => false);
+ ok(
+ !panel.querySelector(".compatibility-browser-icon__image"),
+ "No browsers are the target"
+ );
+
+ info("Make Firefox browsers target");
+ await updateTargetBrowsers(panel, store, id => id.includes("firefox"));
+ ok(
+ panel.querySelector(`.compatibility-browser-icon__image[src*="firefox"]`),
+ "Firefox browsers are the target now"
+ );
+});
+
+async function updateTargetBrowsers(panel, store, isTargetBrowserFunc) {
+ info("Open settings pane");
+ const settingsButton = panel.querySelector(".compatibility-footer__button");
+ settingsButton.click();
+ await waitUntil(() => panel.querySelector(".compatibility-settings"));
+
+ const browsers = [
+ ...new Set(
+ Array.from(panel.querySelectorAll("[data-id]")).map(el =>
+ el.getAttribute("data-id")
+ )
+ ),
+ ];
+ Assert.deepEqual(
+ // Filter out IE, to be removed in an upcoming browser compat data sync.
+ // TODO: Remove the filter once D150961 lands. see Bug 1778009
+ browsers.filter(browser => browser != "ie"),
+ [
+ "chrome",
+ "chrome_android",
+ "edge",
+ "firefox",
+ "firefox_android",
+ "safari",
+ "safari_ios",
+ ],
+ "The expected browsers are displayed"
+ );
+
+ info("Change target browsers");
+ const settingsPane = panel.querySelector(".compatibility-settings");
+ for (const checkbox of settingsPane.querySelectorAll(
+ ".compatibility-settings__target-browsers-item input"
+ )) {
+ if (checkbox.checked !== isTargetBrowserFunc(checkbox.id)) {
+ // Need to click to toggle since the input is designed as controlled component.
+ checkbox.click();
+ }
+ }
+
+ info("Close settings pane");
+ const onUpdated = waitForDispatch(
+ store,
+ COMPATIBILITY_UPDATE_TARGET_BROWSERS_COMPLETE
+ );
+ const closeButton = settingsPane.querySelector(
+ ".compatibility-settings__header-button"
+ );
+ closeButton.click();
+ await onUpdated;
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_throbber.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_throbber.js
new file mode 100644
index 0000000000..eff0f9ac93
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_throbber.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether the throbber is displayed correctly or not.
+
+const TEST_URI = `
+ <style>
+ body {
+ color: blue;
+ border-block-color: lime;
+ user-modify: read-only;
+ }
+ div {
+ font-variant-alternates: historical-forms;
+ }
+ </style>
+ <body>
+ <div>test</div>
+ </body>
+`;
+
+const {
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+add_task(async function () {
+ const tab = await addTab(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)
+ );
+
+ const { allElementsPane, inspector, selectedElementPane } =
+ await openCompatibilityView();
+
+ info("Check the throbber visibility at the beginning");
+ assertThrobber(allElementsPane, false);
+ assertThrobber(selectedElementPane, false);
+
+ info("Reload the browsing page");
+ const onStart = waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_START
+ );
+ const onComplete = waitForDispatch(
+ inspector.store,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE
+ );
+ gBrowser.reloadTab(tab);
+
+ info("Check the throbber visibility of after starting updating action");
+ await onStart;
+ assertThrobber(allElementsPane, true);
+ assertThrobber(selectedElementPane, false);
+
+ info("Check the throbber visibility of after completing updating action");
+ await onComplete;
+ assertThrobber(allElementsPane, false);
+ assertThrobber(selectedElementPane, false);
+});
+
+function assertThrobber(panel, expectedVisibility) {
+ const isThrobberVisible = !!panel.querySelector(".devtools-throbber");
+ is(
+ isThrobberVisible,
+ expectedVisibility,
+ "Visibility of the throbber is correct"
+ );
+}
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_all.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_all.js
new file mode 100644
index 0000000000..c57c805ce1
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_all.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether the all of default browsers are unsupported.
+
+const TEST_URI = `
+ <style>
+ body {
+ user-modify: read-only;
+ }
+ </style>
+ <body></body>
+`;
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, selectedElementPane } = await openCompatibilityView();
+
+ info("Get the taget browsers we set as default");
+ const { targetBrowsers } = inspector.store.getState().compatibility;
+
+ info("Check the content of the issue item");
+ const expectedIssues = [
+ {
+ property: "user-modify",
+ unsupportedBrowsers: targetBrowsers,
+ url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
+ },
+ ];
+ await assertIssueList(selectedElementPane, expectedIssues);
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_some.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_some.js
new file mode 100644
index 0000000000..6359b34e31
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_unsupported-browsers_some.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test whether some of browsers are unsupported.
+
+const {
+ updateTargetBrowsers,
+} = require("resource://devtools/client/inspector/compatibility/actions/compatibility.js");
+
+const TEST_URI = `
+ <style>
+ body {
+ border-block-color: lime;
+ }
+ </style>
+ <body></body>
+`;
+
+const TARGET_BROWSERS = [
+ { id: "firefox", name: "Firefox", version: "1" },
+ { id: "firefox", name: "Firefox", version: "70" },
+ { id: "firefox_android", name: "Firefox Android", version: "1" },
+ { id: "firefox_android", name: "Firefox Android", version: "70" },
+];
+
+add_task(async function () {
+ await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ const { inspector, selectedElementPane } = await openCompatibilityView();
+
+ info("Update the target browsers for this test");
+ await inspector.store.dispatch(updateTargetBrowsers(TARGET_BROWSERS));
+
+ info("Check the content of the issue item");
+ const expectedIssues = [
+ {
+ property: "border-block-color",
+ unsupportedBrowsers: [
+ { id: "firefox", name: "Firefox", version: "1" },
+ { id: "firefox_android", name: "Firefox Android", version: "1" },
+ ],
+ url: "https://developer.mozilla.org/docs/Web/CSS/border-block-color",
+ },
+ ];
+ await assertIssueList(selectedElementPane, expectedIssues);
+});
diff --git a/devtools/client/inspector/compatibility/test/browser/head.js b/devtools/client/inspector/compatibility/test/browser/head.js
new file mode 100644
index 0000000000..54e897093b
--- /dev/null
+++ b/devtools/client/inspector/compatibility/test/browser/head.js
@@ -0,0 +1,283 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Import the rule view's head.js first (which itself imports inspector's head.js and shared-head.js).
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/inspector/rules/test/head.js",
+ this
+);
+
+const {
+ COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE,
+ COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE,
+} = require("resource://devtools/client/inspector/compatibility/actions/index.js");
+
+const {
+ toCamelCase,
+} = require("resource://devtools/client/inspector/compatibility/utils/cases.js");
+
+async function openCompatibilityView() {
+ info("Open the compatibility view");
+ await pushPref("devtools.inspector.compatibility.enabled", true);
+
+ const { inspector } = await openInspectorSidebarTab("compatibilityview");
+ await Promise.all([
+ waitForUpdateSelectedNodeAction(inspector.store),
+ waitForUpdateTopLevelTargetAction(inspector.store),
+ ]);
+ const panel = inspector.panelDoc.querySelector(
+ "#compatibilityview-panel .inspector-tabpanel"
+ );
+
+ const selectedElementPane = panel.querySelector(
+ "#compatibility-app--selected-element-pane"
+ );
+
+ const allElementsPane = panel.querySelector(
+ "#compatibility-app--all-elements-pane"
+ );
+
+ return { allElementsPane, inspector, panel, selectedElementPane };
+}
+
+/**
+ * Check whether the content of issue item element is matched with the expected values.
+ *
+ * @param {Element} panel
+ * @param {Array} expectedIssues
+ * Array of the issue expected.
+ * For the structure of issue items, see types.js.
+ */
+async function assertIssueList(panel, expectedIssues) {
+ info("Check the number of issues");
+ await waitUntil(
+ () =>
+ panel.querySelectorAll("[data-qa-property]").length ===
+ expectedIssues.length
+ );
+ ok(true, "The number of issues is correct");
+
+ if (expectedIssues.length === 0) {
+ // No issue.
+ return;
+ }
+
+ const getFluentString = await getFluentStringHelper([
+ "devtools/client/compatibility.ftl",
+ ]);
+
+ for (const expectedIssue of expectedIssues) {
+ const property = expectedIssue.property;
+ info(`Check an element for ${property}`);
+ const issueEl = getIssueItem(property, panel);
+ ok(issueEl, `Issue element for the ${property} is in the panel`);
+
+ if (expectedIssue.unsupportedBrowsers) {
+ // We only display a single icon per unsupported browser, so we need to
+ // group the expected unsupported browsers (versions) by their browser id.
+ const expectedUnsupportedBrowsersById = new Map();
+ for (const unsupportedBrowser of expectedIssue.unsupportedBrowsers) {
+ if (!expectedUnsupportedBrowsersById.has(unsupportedBrowser.id)) {
+ expectedUnsupportedBrowsersById.set(unsupportedBrowser.id, []);
+ }
+ expectedUnsupportedBrowsersById
+ .get(unsupportedBrowser.id)
+ .push(unsupportedBrowser);
+ }
+
+ const unsupportedBrowserListEl = issueEl.querySelector(
+ ".compatibility-unsupported-browser-list"
+ );
+ const unsupportedBrowsersEl =
+ unsupportedBrowserListEl.querySelectorAll("li");
+
+ is(
+ unsupportedBrowsersEl.length,
+ expectedUnsupportedBrowsersById.size,
+ "The expected number of browser icons are displayed"
+ );
+
+ for (const unsupportedBrowserEl of unsupportedBrowsersEl) {
+ const expectedUnsupportedBrowsers = expectedUnsupportedBrowsersById.get(
+ unsupportedBrowserEl.getAttribute("data-browser-id")
+ );
+
+ ok(expectedUnsupportedBrowsers, "The expected browser is displayed");
+ // debugger;
+ is(
+ unsupportedBrowserEl.querySelector(".compatibility-browser-version")
+ .innerText,
+ // If esr is not supported, but a newest version isn't as well, we don't display
+ // the esr version number
+ (
+ expectedUnsupportedBrowsers.find(
+ ({ status }) => status !== "esr"
+ ) || expectedUnsupportedBrowsers[0]
+ ).version,
+ "The expected browser version is displayed"
+ );
+
+ is(
+ unsupportedBrowserEl.getAttribute("title"),
+ getFluentString("compatibility-issue-browsers-list", "title", {
+ browsers: expectedUnsupportedBrowsers
+ .map(
+ ({ name, status, version }) =>
+ `${name} ${version}${status ? ` (${status})` : ""}`
+ )
+ .join("\n"),
+ }),
+ "The brower item has the expected title attribute"
+ );
+ }
+ }
+
+ for (const [key, value] of Object.entries(expectedIssue)) {
+ const datasetKey = toCamelCase(`qa-${key}`);
+ is(
+ issueEl.dataset[datasetKey],
+ JSON.stringify(value),
+ `The value of ${datasetKey} is correct`
+ );
+ }
+
+ const propertyEl = issueEl.querySelector(
+ ".compatibility-issue-item__property"
+ );
+ const MDN_CLASSNAME = "compatibility-issue-item__mdn-link";
+ const SPEC_CLASSNAME = "compatibility-issue-item__spec-link";
+
+ is(
+ propertyEl.textContent,
+ property,
+ "property name is displayed as expected"
+ );
+
+ is(
+ propertyEl.classList.contains(MDN_CLASSNAME),
+ !!expectedIssue.url,
+ `${property} element ${
+ expectedIssue.url ? "has" : "does not have"
+ } mdn link class`
+ );
+ is(
+ propertyEl.classList.contains(SPEC_CLASSNAME),
+ !!expectedIssue.specUrl,
+ `${property} element ${
+ expectedIssue.specUrl ? "has" : "does not have"
+ } spec link class`
+ );
+
+ if (expectedIssue.url || expectedIssue.specUrl) {
+ is(
+ propertyEl.nodeName.toLowerCase(),
+ "a",
+ `Link rendered for ${property}`
+ );
+
+ const expectedUrl = expectedIssue.url
+ ? expectedIssue.url +
+ "?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
+ : expectedIssue.specUrl;
+ const { link } = await simulateLinkClick(propertyEl);
+ is(
+ link,
+ expectedUrl,
+ `Click on ${property} link navigates user to expected url`
+ );
+ } else {
+ is(
+ propertyEl.nodeName.toLowerCase(),
+ "span",
+ `No link rendered for ${property}`
+ );
+
+ const { link } = await simulateLinkClick(propertyEl);
+ is(link, null, `Click on ${property} does not navigate`);
+ }
+ }
+}
+
+/**
+ * Check whether the content of node item element is matched with the expected values.
+ *
+ * @param {Element} panel
+ * @param {Array} expectedNodes
+ * e.g.
+ * [{ property: "margin-inline-end", nodes: ["body", "div.classname"] },...]
+ */
+async function assertNodeList(panel, expectedNodes) {
+ for (const { property, nodes } of expectedNodes) {
+ info(`Check nodes for ${property}`);
+ const issueEl = getIssueItem(property, panel);
+
+ await waitUntil(
+ () =>
+ issueEl.querySelectorAll(".compatibility-node-item").length ===
+ nodes.length
+ );
+ ok(true, "The number of nodes is correct");
+
+ const nodeEls = [...issueEl.querySelectorAll(".compatibility-node-item")];
+ for (const node of nodes) {
+ const nodeEl = nodeEls.find(el => el.textContent === node);
+ ok(nodeEl, "The text content of the node element is correct");
+ }
+ }
+}
+
+/**
+ * Get IssueItem of given property from given element.
+ *
+ * @param {String} property
+ * @param {Element} element
+ * @return {Element}
+ */
+function getIssueItem(property, element) {
+ return element.querySelector(`[data-qa-property=\"\\"${property}\\"\"]`);
+}
+
+/**
+ * Toggle enable/disable checkbox of a specific property on rule view.
+ *
+ * @param {Inspector} inspector
+ * @param {Number} ruleIndex
+ * @param {Number} propIndex
+ */
+async function togglePropStatusOnRuleView(inspector, ruleIndex, propIndex) {
+ const ruleView = inspector.getPanel("ruleview").view;
+ const rule = getRuleViewRuleEditor(ruleView, ruleIndex).rule;
+ // In case of inline style changes, we track the mutations via the
+ // inspector's markupmutation event to react to dynamic style changes
+ // which Resource Watcher doesn't cover yet.
+ // If an inline style is applied to the element, we need to wait on the
+ // markupmutation event
+ const onMutation =
+ ruleIndex === 0 ? inspector.once("markupmutation") : Promise.resolve();
+ const textProp = rule.textProps[propIndex];
+ const onRuleviewChanged = ruleView.once("ruleview-changed");
+ textProp.editor.enable.click();
+ await Promise.all([onRuleviewChanged, onMutation]);
+}
+
+/**
+ * Return a promise which waits for COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE action.
+ *
+ * @param {Object} store
+ * @return {Promise}
+ */
+function waitForUpdateSelectedNodeAction(store) {
+ return waitForDispatch(store, COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE);
+}
+
+/**
+ * Return a promise which waits for COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE action.
+ *
+ * @param {Object} store
+ * @return {Promise}
+ */
+function waitForUpdateTopLevelTargetAction(store) {
+ return waitForDispatch(store, COMPATIBILITY_UPDATE_TOP_LEVEL_TARGET_COMPLETE);
+}