summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-nesting/parsing.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-nesting/parsing.html')
-rw-r--r--testing/web-platform/tests/css/css-nesting/parsing.html86
1 files changed, 86 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-nesting/parsing.html b/testing/web-platform/tests/css/css-nesting/parsing.html
new file mode 100644
index 0000000000..f29eff9730
--- /dev/null
+++ b/testing/web-platform/tests/css/css-nesting/parsing.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<title>CSS Selectors parsing</title>
+<link rel="author" title="Adam Argyle" href="mailto:argyle@google.com">
+<link rel="author" title="Tab Atkins-Bittner" href="https://tabatkins.com/contact/">
+<link rel="help" href="https://drafts.csswg.org/css-nesting-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style id="test-sheet"></style>
+<script>
+ let [ss] = document.styleSheets
+
+ function resetStylesheet() {
+ while (ss.rules.length)
+ ss.removeRule(0)
+ }
+
+ function testNestedSelector(sel, {expected=sel, parent=".foo"}={}) {
+ resetStylesheet();
+ const ruleText = `${parent} { ${sel} { color: green; }}`
+ test(()=>{
+ ss.insertRule(ruleText);
+ assert_equals(ss.rules.length, 1, "Outer rule should exist.");
+ const rule = ss.rules[0];
+ assert_equals(rule.cssRules.length, 1, "Inner rule should exist.");
+ const innerRule = rule.cssRules[0];
+ assert_equals(innerRule.selectorText, expected, `Inner rule's selector should be "${expected}".`);
+ }, ruleText);
+ }
+
+ function testInvalidNestingSelector(sel, {parent=".foo"}={}) {
+ resetStylesheet();
+ const ruleText = `${parent} { ${sel} { color: green; }}`
+ test(()=>{
+ ss.insertRule(ruleText);
+ assert_equals(ss.rules.length, 1, "Outer rule should exist.");
+ const rule = ss.rules[0];
+ assert_equals(rule.cssRules.length, 0, "Inner rule should not exist.");
+ }, "INVALID: " + ruleText);
+ }
+
+ // basic usage
+ testNestedSelector("&");
+ testNestedSelector("&.bar");
+ testNestedSelector("& .bar");
+ testNestedSelector("& > .bar");
+
+ // relative selector
+ testNestedSelector("> .bar", {expected:"& > .bar"});
+ testNestedSelector("> & .bar", {expected:"& > & .bar"});
+ testNestedSelector("+ .bar &", {expected:"& + .bar &"});
+ testNestedSelector("+ .bar, .foo, > .baz", {expected:"& + .bar, & .foo, & > .baz"});
+
+ // implicit relative (and not)
+ testNestedSelector(".foo", {expected:"& .foo"});
+ testNestedSelector(".test > & .bar");
+ testNestedSelector(".foo, .foo &", {expected:"& .foo, .foo &"});
+ testNestedSelector(":is(.bar, .baz)", {expected:"& :is(.bar, .baz)"});
+ testNestedSelector("&:is(.bar, .baz)");
+ testNestedSelector(":is(.bar, &.baz)");
+ testNestedSelector("&:is(.bar, &.baz)");
+
+ // Mixing nesting selector with other simple selectors
+ testNestedSelector("div&");
+ testInvalidNestingSelector("&div"); // type selector must be first
+ testNestedSelector(".class&");
+ testNestedSelector("&.class");
+ testNestedSelector("[attr]&");
+ testNestedSelector("&[attr]");
+ testNestedSelector("#id&");
+ testNestedSelector("&#id");
+ testNestedSelector(":hover&");
+ testNestedSelector("&:hover");
+ testNestedSelector(":is(div)&");
+ testNestedSelector("&:is(div)");
+
+ // Multiple nesting selectors
+ testNestedSelector("& .bar & .baz & .qux");
+ testNestedSelector("&&");
+
+ // Selector list in inner rule
+ testNestedSelector("& > section, & > article");
+
+ // Selector list in both inner and outer rule.
+ testNestedSelector("& + .baz, &.qux", {parent:".foo, .bar"});
+</script>