summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/rules/test/browser_rules_nested_rules.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/inspector/rules/test/browser_rules_nested_rules.js211
1 files changed, 211 insertions, 0 deletions
diff --git a/devtools/client/inspector/rules/test/browser_rules_nested_rules.js b/devtools/client/inspector/rules/test/browser_rules_nested_rules.js
new file mode 100644
index 0000000000..925f36a0e6
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_nested_rules.js
@@ -0,0 +1,211 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the rule-view content is correct when the page uses nested CSS rules
+const TEST_URI = `
+ <style type="text/css">
+ body {
+ background: tomato;
+ container-type: inline-size;
+
+ @media screen {
+ container-name: main;
+
+ & h1 {
+ border-color: gold;
+
+ .foo {
+ color: white;
+ }
+
+ #bar {
+ text-decoration: underline;
+ }
+
+ @container main (width > 10px) {
+ & + nav {
+ border: 1px solid;
+
+ [href] {
+ background-color: lightgreen;
+ }
+ }
+ }
+ }
+ }
+ }
+ </style>
+ <h1>Hello <i class="foo">nested</i> <em id="bar">rules</em>!</h1>
+ <nav>
+ <ul>
+ <li><a href="#">Leaf</a></li>
+ <li><a>Nowhere</a></li>
+ </ul>
+ </nav>
+`;
+
+add_task(async function () {
+ await addTab(
+ "https://example.com/document-builder.sjs?html=" +
+ encodeURIComponent(TEST_URI)
+ );
+ const { inspector, view } = await openRuleView();
+
+ await selectNode("body", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `&`,
+ // prettier-ignore
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`
+ ],
+ declarations: [{ name: "container-name", value: "main" }],
+ },
+ {
+ selector: `body`,
+ ancestorRulesData: null,
+ declarations: [
+ { name: "background", value: "tomato" },
+ { name: "container-type", value: "inline-size" },
+ ],
+ },
+ ]);
+
+ await selectNode("h1", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `& h1`,
+ // prettier-ignore
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`
+ ],
+ declarations: [{ name: "border-color", value: "gold" }],
+ },
+ ]);
+
+ await selectNode("h1 > .foo", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `.foo`,
+ // prettier-ignore
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`,
+ ` & h1 {`
+ ],
+ declarations: [{ name: "color", value: "white" }],
+ },
+ ]);
+
+ await selectNode("h1 > #bar", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `#bar`,
+ // prettier-ignore
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`,
+ ` & h1 {`
+ ],
+ declarations: [{ name: "text-decoration", value: "underline" }],
+ },
+ ]);
+
+ await selectNode("nav", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `& + nav`,
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`,
+ ` & h1 {`,
+ ` @container main (width > 10px) {`,
+ ],
+ declarations: [{ name: "border", value: "1px solid" }],
+ },
+ ]);
+
+ await selectNode("nav a", inspector);
+ checkRuleViewContent(view, [
+ { selector: "element", ancestorRulesData: null, declarations: [] },
+ {
+ selector: `[href]`,
+ ancestorRulesData: [
+ `body {`,
+ ` @media screen {`,
+ ` & h1 {`,
+ ` @container main (width > 10px) {`,
+ ` & + nav {`,
+ ],
+ declarations: [{ name: "background-color", value: "lightgreen" }],
+ },
+ ]);
+});
+
+function checkRuleViewContent(view, expectedRules) {
+ const rulesInView = Array.from(view.element.children);
+ is(
+ rulesInView.length,
+ expectedRules.length,
+ "All expected rules are displayed"
+ );
+
+ for (let i = 0; i < expectedRules.length; i++) {
+ const expectedRule = expectedRules[i];
+ info(`Checking rule #${i}: ${expectedRule.selector}`);
+
+ const ruleInView = rulesInView[i];
+ const selector = ruleInView.querySelector(
+ ".ruleview-selectors-container"
+ ).innerText;
+ is(selector, expectedRule.selector, `Expected selector for ${selector}`);
+
+ if (expectedRule.ancestorRulesData == null) {
+ is(
+ getRuleViewAncestorRulesDataElementByIndex(view, i),
+ null,
+ `No ancestor rules data displayed for ${selector}`
+ );
+ } else {
+ is(
+ getRuleViewAncestorRulesDataTextByIndex(view, i),
+ expectedRule.ancestorRulesData.join("\n"),
+ `Expected ancestor rules data displayed for ${selector}`
+ );
+ }
+
+ const declarations = ruleInView.querySelectorAll(".ruleview-property");
+ is(
+ declarations.length,
+ expectedRule.declarations.length,
+ "Got the expected number of declarations"
+ );
+ for (let j = 0; j < declarations.length; j++) {
+ const expectedDeclaration = expectedRule.declarations[j];
+ const [propName, propValue] = Array.from(
+ declarations[j].querySelectorAll(
+ ".ruleview-propertyname, .ruleview-propertyvalue"
+ )
+ );
+ is(
+ propName.innerText,
+ expectedDeclaration?.name,
+ "Got expected property name"
+ );
+ is(
+ propValue.innerText,
+ expectedDeclaration?.value,
+ "Got expected property value"
+ );
+ }
+ }
+}