Tests: Import more CSS selector tests from WPT

This commit is contained in:
Andreas Kling 2024-11-06 19:19:08 +01:00 committed by Andreas Kling
parent 9dff6bca1f
commit 6c945fc353
Notes: github-actions[bot] 2024-11-06 20:44:15 +00:00
72 changed files with 2798 additions and 0 deletions

View file

@ -0,0 +1,65 @@
Summary
Harness status: OK
Rerun
Found 54 tests
30 Pass
24 Fail
Details
Result Test Name MessagePass Expected HTML element to match :first-child with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to match :last-child with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to match :only-child with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to match :first-of-type with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to match :last-of-type with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to match :only-of-type with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-child(1) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-child(n) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-last-child(1) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-last-child(n) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-of-type(1) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-of-type(n) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-last-of-type(1) with matches, querySelector(), and querySelectorAll()
Fail Expected HTML element to match :nth-last-of-type(n) with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to not match :nth-child(2) with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to not match :nth-last-child(2) with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to not match :nth-of-type(2) with matches, querySelector(), and querySelectorAll()
Pass Expected HTML element to not match :nth-last-of-type(2) with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :first-child with matches
Pass Expected DIV element to match :last-child with matches
Pass Expected DIV element to match :only-child with matches
Pass Expected DIV element to match :first-of-type with matches
Pass Expected DIV element to match :last-of-type with matches
Pass Expected DIV element to match :only-of-type with matches
Fail Expected DIV element to match :nth-child(1) with matches
Fail Expected DIV element to match :nth-child(n) with matches
Fail Expected DIV element to match :nth-last-child(1) with matches
Fail Expected DIV element to match :nth-last-child(n) with matches
Fail Expected DIV element to match :nth-of-type(1) with matches
Fail Expected DIV element to match :nth-of-type(n) with matches
Fail Expected DIV element to match :nth-last-of-type(1) with matches
Fail Expected DIV element to match :nth-last-of-type(n) with matches
Pass Expected DIV element to not match :nth-child(2) with matches
Pass Expected DIV element to not match :nth-last-child(2) with matches
Pass Expected DIV element to not match :nth-of-type(2) with matches
Pass Expected DIV element to not match :nth-last-of-type(2) with matches
Pass Expected DIV element to match :first-child with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :last-child with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :only-child with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :first-of-type with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :last-of-type with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to match :only-of-type with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-child(1) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-child(n) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-last-child(1) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-last-child(n) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-of-type(1) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-of-type(n) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-last-of-type(1) with matches, querySelector(), and querySelectorAll()
Fail Expected DIV element to match :nth-last-of-type(n) with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to not match :nth-child(2) with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to not match :nth-last-child(2) with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to not match :nth-of-type(2) with matches, querySelector(), and querySelectorAll()
Pass Expected DIV element to not match :nth-last-of-type(2) with matches, querySelector(), and querySelectorAll()

View file

@ -0,0 +1,16 @@
Summary
Harness status: OK
Rerun
Found 5 tests
3 Pass
2 Fail
Details
Result Test Name MessageFail bdi element without dir content attribute
Fail bdi element with invalid dir content attribute
Pass bdi element with dir=auto content attribute
Pass bdi element with dir=ltr content attribute
Pass bdi element with dir=rtl content attribute

View file

@ -0,0 +1,30 @@
Summary
Harness status: OK
Rerun
Found 20 tests
20 Pass
Details
Result Test Name MessagePass input element whose type attribute is in the telephone state
Pass input element whose type attribute is in the telephone state in a RTL block
Pass input element whose type attribute is in the password state
Pass input element whose type attribute is in the text state
Pass input element whose type attribute is in the search state
Pass input element whose type attribute is in the url state
Pass input element whose type attribute is in the email state
Pass input element whose type attribute is in the submit state
Pass input element whose type attribute is in the reset state
Pass input element whose type attribute is in the button state
Pass input element whose type attribute is in the hidden state
Pass dynamic changes to type of input elements affect whether value is used for dir=auto
Pass input element whose type attribute is in the date state
Pass input element whose type attribute is in the time state
Pass input element whose type attribute is in the number state
Pass input element whose type attribute is in the range state
Pass input element whose type attribute is in the color state
Pass input element whose type attribute is in the checkbox state
Pass input element whose type attribute is in the radio state
Pass input element whose type attribute is in the image state

View file

@ -0,0 +1,32 @@
Summary
Harness status: OK
Rerun
Found 22 tests
22 Pass
Details
Result Test Name MessagePass Initial directionality of element div1 is ltr
Pass Initial directionality of element div1_1 is ltr
Pass Initial directionality of element div2 is rtl
Pass Initial directionality of element div2_1 is rtl
Pass Initial directionality of element div3 is ltr
Pass Initial directionality of element div3_1 is rtl
Pass Initial directionality of element div3_2 is ltr
Pass Initial directionality of element div4 is ltr
Pass Initial directionality of element div4_1 is ltr
Pass Initial directionality of element div4_1_1 is ltr
Pass Updated directionality of element div1 is rtl
Pass Updated directionality of element div1_1 is rtl
Pass Updated directionality of element div1 is ltr
Pass Updated directionality of element div1_1 is ltr
Pass Reupdated directionality of element div1 is ltr
Pass Reupdated directionality of element div1_1 is ltr
Pass Updated directionality of element div2 is ltr
Pass Updated directionality of element div3 is rtl
Pass Updated directionality of element div3 is ltr
Pass Updated directionality of element div4 is rtl
Pass Updated directionality of element div4_1 is rtl
Pass Updated directionality of element div4_1_1 is rtl

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 4 tests
3 Pass
1 Fail
Details
Result Test Name MessageFail :dir() allows any ident value but strings other than ltr/rtl don't match Failed to parse selector
Pass :dir() requires exactly an ident argument
Pass :dir() works in compound selectors
Pass :dir() works in complex selectors

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass There is the second child element.
Pass A comment node should be ignored.
Pass Non-whitespace text node should be ignored.
Pass The second child should not be matched.

View file

@ -0,0 +1,19 @@
Summary
Harness status: OK
Rerun
Found 9 tests
9 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass Thre is another child element of the same type.
Pass There is a prior child element of another type.
Pass A previous element of the parent should not affect.
Pass The parent element of the same type should not affect.
Pass A child of the previous element should not affect.
Pass The second child element of the same type should not match.
Pass The second child element of the same type should not match, the first child has case-different tag name.
Pass Dynamic insertion and removal

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Fail
Details
Result Test Name MessageFail Test ':focus' after 'display:none' on input
Fail Test ':focus' after 'display:none' on input's parent

View file

@ -0,0 +1,13 @@
Summary
Harness status: OK
Rerun
Found 3 tests
3 Pass
Details
Result Test Name MessagePass Checks that ':focus' pseudo-class matches inside 'focus' event handler
Pass Checks that ':focus-visible' pseudo-class matches inside 'focus' event handler
Pass Checks that ':focus-within' pseudo-class matches inside 'focus' event handler

View file

@ -0,0 +1,13 @@
Summary
Harness status: OK
Rerun
Found 3 tests
3 Pass
Details
Result Test Name MessagePass Checks that ':focus' pseudo-class matches inside 'focusin' event handler
Pass Checks that ':focus-visible' pseudo-class matches inside 'focusin' event handler
Pass Checks that ':focus-within' pseudo-class matches inside 'focusin' event handler

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Fail
Details
Result Test Name MessageFail Autofocus should match :focus-visible

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass Programmatic focus on page load should match :focus-visible

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass :focus-visible matches after script focus move

View file

@ -0,0 +1,48 @@
Summary
Harness status: OK
Rerun
Found 38 tests
38 Pass
Details
Result Test Name MessagePass ":focus-visible" should be a valid selector
Pass By default initial programatic focus matches ':focus-visible', so the element ABBR shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element ADDRESS shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element BDI shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element BLOCKQUOTE shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element CODE shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element DD shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element SUMMARY shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element DETAILS shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element DIV shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element DL shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element DT shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element EM shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element LEGEND shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element FIGCAPTION shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element FIGURE shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element FORM shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element HR shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element IMG shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element LABEL shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element LI shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element MARK shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element METER shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element OL shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element PRE shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element PROGRESS shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element P shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element SMALL shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element S shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element STRONG shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element SUB shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element SUP shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element CAPTION shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element TABLE shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element TD shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element TIME shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element UL shows a focus ring with 'outline-style: auto'
Pass By default initial programatic focus matches ':focus-visible', so the element U shows a focus ring with 'outline-style: auto'

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Pass
Details
Result Test Name MessagePass ":focus-visible" should be a valid selector
Pass By default initial programatic focus matches ':focus-visible', so the element shows a focus ring with 'outline-style: auto'

View file

@ -0,0 +1,13 @@
Summary
Harness status: OK
Rerun
Found 2 tests
1 Pass
1 Fail
Details
Result Test Name MessagePass ":focus-visible" should be a valid selector
Fail :focus-visible doesn't match on ShadowRoot

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Pass
Details
Result Test Name MessagePass ":focus-visible" should be a valid selector
Pass Script focus without any previous user interaction matches :focus-visible

View file

@ -0,0 +1,23 @@
Summary
Harness status: OK
Rerun
Found 12 tests
1 Pass
11 Fail
Details
Result Test Name MessagePass Initial State
Fail Focus 'target1'
Fail Focus 'target2'
Fail Focus 'target1' again
Fail Focus 'target2' again
Fail Focus 'target1' once again
Fail Detach 'container1' from the document
Fail Try to focus 'target1'
Fail Focus 'target2' once again
Fail Attach 'container1' in 'container2'
Fail Focus 'target1' for the last time
Fail Move 'target1' in 'container2'

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Fail
Details
Result Test Name MessageFail Test ':focus-within' after 'display:none' on input
Fail Test ':focus-within' after 'display:none' on input's parent

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Fail
Details
Result Test Name MessageFail Test string hash collision in bucketing

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass There is a prior child element.
Pass A comment node should be ignored.
Pass Non-whitespace text node should be ignored.
Pass The first child should not be matched.

View file

@ -0,0 +1,19 @@
Summary
Harness status: OK
Rerun
Found 9 tests
9 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass Thre is another child element of the same type.
Pass There is a posterior child element of another type.
Pass A next element of the parent should not affect.
Pass The parent element of the same type should not affect.
Pass A child of the next element should not affect.
Pass The first child element of the same type should not match.
Pass The first child element of the same type should not match, the last child has a case-different tag name.
Pass Dynamic insertion and removal

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass attribute selectors with missing right tokens succeed

View file

@ -0,0 +1,30 @@
Summary
Harness status: OK
Rerun
Found 20 tests
20 Pass
Details
Result Test Name MessagePass :not(#a) matches expected elements
Pass :not(#a #d) matches expected elements
Pass :not(#b div) matches expected elements
Pass :not(div div) matches expected elements
Pass :not(div + div) matches expected elements
Pass :not(main > div) matches expected elements
Pass :not(#a, #b) matches expected elements
Pass :not(#f, main > div) matches expected elements
Pass :not(div + div + div, div + div > div) matches expected elements
Pass :not(div:nth-child(1)) matches expected elements
Pass :not(:not(div)) matches expected elements
Pass :not(:not(:not(div))) matches expected elements
Pass :not(div, span) matches expected elements
Pass :not(span, p) matches expected elements
Pass :not(#unknown, .unknown) matches expected elements
Pass :not(#unknown > div, span) matches expected elements
Pass :not(#unknown ~ div, span) matches expected elements
Pass :not(:hover div) matches expected elements
Pass :not(:link div) matches expected elements
Pass :not(:visited div) matches expected elements

View file

@ -0,0 +1,18 @@
Summary
Harness status: OK
Rerun
Found 8 tests
8 Fail
Details
Result Test Name MessageFail :not(#foo) wins over :not(.foo)
Fail :not(div#foo) wins over :not(#foo)
Fail :not(.bar, #foo) has same specificity as :not(#foo, .bar)
Fail :not(.bar, #foo) wins over :not(.foo, .bar)
Fail :not(span + span) wins over :not(span)
Fail :not(span, li, p) wins over :not(span, lo, p)
Fail :not(span, :not(:not(.a#foo)), p) wins over :not(span, #foo, p)
Fail :not(span, #foo, p) wins over :not(span, :where(.a#foo), p)

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass CSS Selectors: :nth-last-child() with no argument

View file

@ -0,0 +1,14 @@
Summary
Harness status: OK
Rerun
Found 3 tests
2 Pass
1 Fail
Details
Result Test Name MessagePass :nth-of-type selectors matching takes element namespace into account (http://www.w3.org/1999/xhtml)
Pass :nth-of-type selectors matching takes element namespace into account (http://dummy1/)
Fail :nth-of-type selectors matching takes element namespace into account (http://dummy2/)

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass A comment node should be ignored.
Pass Non-whitespace text node should be ignored.
Pass There is another child element.
Pass Dynamic addition and removal

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass Whitespace nodes should be ignored.
Pass A comment node should be ignored.
Pass Non-whitespace text node should be ignored.
Pass There is another child element of a different type.
Pass Dynamic addition and removal

View file

@ -0,0 +1,17 @@
Summary
Harness status: OK
Rerun
Found 7 tests
7 Pass
Details
Result Test Name MessagePass CSS Selectors Test: :placeholder-shown matching
Pass CSS Selectors Test: :placeholder-shown matching 1
Pass CSS Selectors Test: :placeholder-shown matching 2
Pass CSS Selectors Test: :placeholder-shown matching 3
Pass CSS Selectors Test: :placeholder-shown matching 4
Pass CSS Selectors Test: :placeholder-shown matching 5
Pass CSS Selectors Test: :placeholder-shown matching 6

View file

@ -0,0 +1,14 @@
Summary
Harness status: OK
Rerun
Found 4 tests
4 Pass
Details
Result Test Name MessagePass :enabeld should match to enabled controls
Pass :disabled should match to enabled controls
Pass :not(:enabeld) should match to disabled controls and non-controls
Pass :not(:disabled) should match to enabled controls and non-controls

View file

@ -0,0 +1,14 @@
Summary
Harness status: OK
Rerun
Found 3 tests
2 Pass
1 Fail
Details
Result Test Name MessagePass scope-selector
Pass scope-selector 1
Fail querySelector() with ":scope" should return the document element, if present in the subtree

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Pass
Details
Result Test Name MessagePass input:placeholder-shown should not be matched
Pass textarea:placeholder-shown should not be matched

View file

@ -0,0 +1,14 @@
Summary
Harness status: OK
Rerun
Found 3 tests
1 Pass
2 Fail
Details
Result Test Name MessageFail CSS selector should match for Unicode uppercase element
Fail Elements with namespace should work the same way
Pass `querySelector` should not use Unicode case-folding

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 4 tests
3 Pass
1 Fail
Details
Result Test Name MessagePass rules include webkit-prefixed pseudo-element should be cascaded
Fail webkit-prefixed pseudo-element selectors should be accessible from CSSOM
Pass qS and qSA shouldn't throw exception
Pass webkit-prefix without dash is invalid

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass x-prefixed pseudo-elements should make the whole rule invalid

View file

@ -0,0 +1,55 @@
<!doctype html>
<meta charset=utf-8>
<title>Matching of child-indexed pseudo-classes</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:ecoal95@gmail.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#child-index">
<script src=../../resources/testharness.js></script>
<script src=../../resources/testharnessreport.js></script>
<script>
var check = function(element, selectors, qsRoot) {
for (var i = 0; i < selectors.length; ++i) {
var selector = selectors[i][0];
var expected = selectors[i][1];
test(function() {
assert_equals(expected, element.matches(selector));
if (qsRoot) {
assert_equals(expected, element === qsRoot.querySelector(selector));
var qsa = qsRoot.querySelectorAll(selector);
assert_equals(expected, !!qsa.length && element === qsa[0]);
}
}, "Expected " + element.tagName + " element to " +
(expected ? "match " : "not match ") + selector + " with matches" +
(qsRoot ? ", querySelector(), and querySelectorAll()" : ""));
}
}
var rootOfSubtreeSelectors = [
[ ":first-child", true ],
[ ":last-child", true ],
[ ":only-child", true ],
[ ":first-of-type", true ],
[ ":last-of-type", true ],
[ ":only-of-type", true ],
[ ":nth-child(1)", true ],
[ ":nth-child(n)", true ],
[ ":nth-last-child(1)", true ],
[ ":nth-last-child(n)", true ],
[ ":nth-of-type(1)", true ],
[ ":nth-of-type(n)", true ],
[ ":nth-last-of-type(1)", true ],
[ ":nth-last-of-type(n)", true ],
[ ":nth-child(2)", false ],
[ ":nth-last-child(2)", false],
[ ":nth-of-type(2)", false ],
[ ":nth-last-of-type(2)", false],
];
check(document.documentElement, rootOfSubtreeSelectors, document);
check(document.createElement('div'), rootOfSubtreeSelectors);
var fragment = document.createDocumentFragment();
var div = document.createElement('div');
fragment.appendChild(div);
check(div, rootOfSubtreeSelectors, fragment);
</script>

View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#the-directionality">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
test(() => {
const bdi = document.createElement('bdi');
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
bdi.textContent = '\u05EA';
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
}, 'bdi element without dir content attribute');
test(() => {
const bdi = document.createElement('bdi');
bdi.setAttribute('dir', 'foo');
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
bdi.textContent = '\u05EA';
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
}, 'bdi element with invalid dir content attribute');
test(() => {
const bdi = document.createElement('bdi');
bdi.setAttribute('dir', 'auto');
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
bdi.textContent = '\u05EA';
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
bdi.setAttribute('dir', 'AUTO');
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
}, 'bdi element with dir=auto content attribute');
test(() => {
const bdi = document.createElement('bdi');
bdi.setAttribute('dir', 'ltr');
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
bdi.setAttribute('dir', 'LTR');
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
bdi.textContent = '\u05EA';
assert_true(bdi.matches(':dir(ltr)'));
assert_false(bdi.matches(':dir(rtl)'));
}, 'bdi element with dir=ltr content attribute');
test(() => {
const bdi = document.createElement('bdi');
bdi.setAttribute('dir', 'rtl');
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
bdi.setAttribute('dir', 'RTL');
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
bdi.textContent = '\u05EA';
assert_false(bdi.matches(':dir(ltr)'));
assert_true(bdi.matches(':dir(rtl)'));
}, 'bdi element with dir=rtl content attribute');
</script>
</body>
</html>

View file

@ -0,0 +1,207 @@
<!DOCTYPE html>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#the-directionality">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<body>
<script>
test(() => {
const input = document.createElement('input');
input.type = 'tel';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
}, 'input element whose type attribute is in the telephone state');
test(() => {
const input = document.createElement('input');
input.type = 'tel';
const container = document.createElement('div');
container.setAttribute('dir', 'rtl');
container.appendChild(input);
// Insert the element into the document so that we can also check for
// 'direction' in computed style.
document.body.appendChild(container);
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
// Per https://html.spec.whatwg.org/multipage/rendering.html#bidi-rendering:
assert_equals(getComputedStyle(input).direction, 'ltr');
// Changing to a different type causes the special type=tel rule to no longer apply.
input.type = 'text';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
assert_equals(getComputedStyle(input).direction, 'rtl');
// And restoring type=tel brings back that behavior.
input.type = 'tel';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
assert_equals(getComputedStyle(input).direction, 'ltr');
document.body.removeChild(container);
}, 'input element whose type attribute is in the telephone state in a RTL block');
for (const type of ['password', 'text', 'search', 'url', 'email', 'submit', 'reset', 'button', 'hidden']) {
test(() => {
const input = document.createElement('input');
input.type = type;
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'))
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
}, `input element whose type attribute is in the ${type} state`);
}
test(() => {
const input = document.createElement('input');
input.type = 'text';
// bidirectional character type R
input.value = '\u05EA';
input.setAttribute('dir', 'auto');
const container = document.createElement('div');
container.appendChild(input);
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
// Changing to a different type that does't use value causes the bidi rule to no longer apply.
input.type = 'radio';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
// And restoring type=text brings back that behavior.
input.type = 'text';
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
}, 'dynamic changes to type of input elements affect whether value is used for dir=auto');
for (const type of ['date', 'time', 'number', 'range', 'color', 'checkbox', 'radio', 'image']) {
test(() => {
const input = document.createElement('input');
input.type = type;
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'foo');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'rtl');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'RTL');
assert_false(input.matches(':dir(ltr)'));
assert_true(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'ltr');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'LTR');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'auto');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.value = '\u05EA';
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
input.setAttribute('dir', 'AUTO');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'))
input.removeAttribute('dir');
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
let rtlParent = document.createElement("div");
rtlParent.dir = "rtl";
input.dir = "auto";
rtlParent.appendChild(input);
document.body.appendChild(rtlParent); // Just for good measure.
assert_true(input.matches(':dir(ltr)'));
assert_false(input.matches(':dir(rtl)'));
rtlParent.remove();
}, `input element whose type attribute is in the ${type} state`);
}
</script>
</body>

View file

@ -0,0 +1,93 @@
<!doctype html>
<html>
<head>
<link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
#div4_1 {
direction: rtl;
}
</style>
</head>
<!-- &#1514; is the Hebrew letter tav, i.e. RTL -->
<body>
<div id=testDivs>
<div id=div1 dir=auto>
<div id=div1_1>a</div>
</div>
<div id=div2 dir=auto>
<div id=div2_1>&#1514;</div>
</div>
<div id=div3 dir=auto>
<div id=div3_1 dir=rtl>&#1514;</div>
<div id=div3_2>a</div>
</div>
<div id=div4 dir=auto>
<div id=div4_1>
<div id=div4_1_1>a</div>
</div>
</div>
</div>
</body>
<script>
function test_directionality(message, element, expected) {
test(() => {
var isLTR = document.querySelector("#" + element.id + ":dir(ltr)") == element;
var isRTL = document.querySelector("#" + element.id + ":dir(rtl)") == element;
if (expected == "ltr") {
assert_true(isLTR);
assert_false(isRTL);
} else {
assert_false(isLTR);
assert_true(isRTL);
}
}, message + " directionality of element " + element.id + " is " + expected);
}
test_directionality("Initial ", div1, "ltr");
test_directionality("Initial ", div1_1, "ltr");
test_directionality("Initial ", div2, "rtl");
test_directionality("Initial ", div2_1, "rtl");
test_directionality("Initial ", div3, "ltr");
test_directionality("Initial ", div3_1, "rtl");
test_directionality("Initial ", div3_2, "ltr");
test_directionality("Initial ", div4, "ltr");
test_directionality("Initial ", div4_1, "ltr");
test_directionality("Initial ", div4_1_1, "ltr");
div1_1.innerText = "\u05EA";
div1_1.offsetTop;
test_directionality("Updated ", div1, "rtl");
test_directionality("Updated ", div1_1, "rtl");
div1_1.dir = "ltr";
div1_1.offsetTop;
test_directionality("Updated ", div1, "ltr");
test_directionality("Updated ", div1_1, "ltr");
div1_1.innerText = "a";
div1_1.offsetTop;
test_directionality("Reupdated ", div1, "ltr");
test_directionality("Reupdated ", div1_1, "ltr");
div2_1.remove();
div2.offsetTop;
test_directionality("Updated ", div2, "ltr");
div3_1.dir = "";
div3_1.offsetTop;
test_directionality("Updated ", div3, "rtl");
div3.appendChild(div3_1);
div3.offsetTop;
test_directionality("Updated ", div3, "ltr");
div4_1_1.innerText = "\u05EA";
div4_1_1.offsetTop;
test_directionality("Updated ", div4, "rtl");
test_directionality("Updated ", div4_1, "rtl");
test_directionality("Updated ", div4_1_1, "rtl");
</script>
</html>

View file

@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
<link rel="help" href="http://www.w3.org/TR/selectors4/#dir-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id=outer>
<div id=div1></div>
<div id=div2 dir=ltr>
<div id=div2_1></div>
<div id=div2_2 dir=ltr></div>
<div id=div2_3 dir=rtl></div>
</div>
<div id=div3 dir=rtl>
<div id=div3_1>
<div id=div3_1_1></div>
</div>
<div id=div3_2 dir=ltr></div>
<div id=div3_3 dir=rtl></div>
</div>
<div id=div4 dir=lol></div>
<div id=div5 dir=auto></div>
</div>
</body>
<script>
test(() => {
assert_equals(document.querySelector(":dir(lol)"), null);
assert_equals(document.querySelector(":dir(lol )"), null);
assert_equals(document.querySelector(":dir( auto)"), null);
assert_equals(document.querySelector(":dir(\nauto\t)"), null);
}, ":dir() allows any ident value but strings other than ltr/rtl don't match");
test(() => {
assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir()"); });
assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir(ltr, rtl)"); });
assert_throws_dom("SYNTAX_ERR", () => { document.querySelector(":dir('ltr')"); });
}, ":dir() requires exactly an ident argument");
test(() => {
assert_equals(document.querySelector(":dir(rtl)"), div2_3);
assert_equals(document.querySelector("*:dir(rtl)"), div2_3);
assert_equals(document.querySelector("div:dir(ltr)"), outer);
assert_equals(document.querySelector("div:dir(ltr):dir(ltr)"), outer);
assert_equals(document.querySelector(":dir(rtl)#div3_3"), div3_3);
assert_equals(document.querySelector(":nth-child(2):dir(rtl)"), null);
assert_equals(document.querySelector(":nth-child(3):dir(rtl)"), div2_3);
assert_equals(document.querySelector(":nth-child(4):dir(ltr)"), div4);
assert_equals(document.querySelector(":nth-last-child(3):dir(rtl)"), div3);
}, ":dir() works in compound selectors");
test(() => {
assert_equals(document.querySelector("#div2 :dir(ltr)"), div2_1);
assert_equals(document.querySelector(":dir(rtl) div"), div3_1);
assert_equals(document.querySelector("div + :dir(ltr)"), div2);
assert_equals(document.querySelector(":dir(ltr) + :dir(rtl)"), div2_3);
assert_equals(document.querySelector(":dir(rtl) :dir(rtl)"), div3_1);
assert_equals(document.querySelector(":dir(rtl) + :dir(ltr)"), div3_2);
assert_equals(document.querySelector(":dir(rtl) ~ :dir(rtl)"), div3_3);
assert_equals(document.querySelector(":dir(rtl) :dir(ltr)"), div3_2);
assert_equals(document.querySelector("* :dir(rtl) *"), div3_1);
assert_equals(document.querySelector("div :dir(rtl) div"), div3_1);
assert_equals(document.querySelector(":dir(ltr) :dir(rtl) + :dir(ltr)"), div3_2);
assert_equals(document.querySelector(":dir(ltr) + :dir(rtl) + * + *"), div5);
assert_equals(document.querySelector(":dir(rtl) > * > :dir(rtl)"), div3_1_1);
}, ":dir() works in complex selectors");
</script>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :first-child</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-first-child-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also:
* child-indexed-pseudo-class.html
* child-indexed-no-parent.html
* invalidation/first-child-last-child.html
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<div id="target2">There is the second child element.</div>
<blockquote></blockquote>
</div>
<div>
<!-- -->
<div id="target3">A comment node should be ignored.</div>
</div>
<div>
.
<div id="target4">Non-whitespace text node should be ignored.</div>
</div>
<div>
<blockquote></blockquote>
<div id="target5" data-expected="false">The second child should not be matched.</div>
</div>
<script>
for (let i = 1; i <= 5; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'false')
assert_false(target.matches(':first-child'));
else
assert_true(target.matches(':first-child'));
}, target.textContent);
}
</script>

View file

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :first-of-type</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-first-of-type-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also:
* of-type-selectors.html
* child-indexed-pseudo-class.html
* child-indexed-no-parent.html
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<div id="target2">Thre is another child element of the same type.</div>
<div></div>
</div>
<div>
<blockquote></blockquote>
<div id="target3">There is a prior child element of another type.</div>
</div>
<div>
<div></div>
<blockquote>
<div id="target4">A previous element of the parent should not affect.</div>
</blockquote>
</div>
<div>
<div>
<div id="target5">The parent element of the same type should not affect.</div>
</div>
</div>
<div>
<blockquote>
<div></div>
</blockquote>
<div id="target6">A child of the previous element should not affect.</div>
</div>
<div>
<div></div>
<div id="target7" data-expected="false">The second child element of the same
type should not match.</div>
</div>
<div>
<DIV></DIV>
<div id="target8" data-expected="false">The second child element of the same
type should not match, the first child has case-different tag name.</div>
</div>
<div>
<div id="insertBefore1"></div>
</div>
<script>
for (let i = 1; i <= 8; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'false')
assert_false(target.matches('div:first-of-type'));
else
assert_true(target.matches('div:first-of-type'));
}, target.textContent.replaceAll('\n', ' '));
}
test(() => {
const ib1 = document.querySelector('#insertBefore1');
const target = document.createElement('div');
assert_true(ib1.matches('div:first-of-type'));
ib1.parentNode.insertBefore(target, ib1);
assert_true(target.matches('div:first-of-type'));
assert_false(ib1.matches('div:first-of-type'));
target.remove();
assert_true(ib1.matches('div:first-of-type'));
}, 'Dynamic insertion and removal');
</script>

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Selectors Level 4: focus</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-pseudo">
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#focus-fixup-rule">
<meta name="assert" content="Checks ':focus' pseudo-class after 'display: none'.">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<div id="wrapper">
<input id="input">
</div>
<script>
"use strict";
const wrapper = document.getElementById("wrapper");
const input = document.getElementById("input");
async_test((t) => {
input.focus();
window.requestAnimationFrame(() => {
t.step(() => assert_true(input.matches(":focus"),
"Check input matches ':focus' after being focused"));
input.style.display = "none";
window.requestAnimationFrame(() => {
t.step(() => assert_false(input.matches(":focus"),
"Check input doesn't match ':focus' after getting 'display: none'"));
input.style.display = "inline";
t.done();
});
});
}, "Test ':focus' after 'display:none' on input");
async_test((t) => {
input.focus();
window.requestAnimationFrame(() => {
t.step(() => assert_true(input.matches(":focus"),
"Check input matches ':focus' after being focused"));
wrapper.style.display = "none";
window.requestAnimationFrame(() => {
t.step(() => assert_false(input.matches(":focus"),
"Check input doesn't match ':focus' after parent got 'display: none'"));
wrapper.style.display = "block";
t.done();
});
});
}, "Test ':focus' after 'display:none' on input's parent");
</script>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Selectors Level 4: :focus, :focus-visible and :focus-within in focus event</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-pseudo">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-visible-pseudo">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
<link rel="help" href="https://w3c.github.io/uievents/#event-type-focus">
<link rel="help" href="https://crbug.com/523126">
<meta name='author' title='Takayoshi Kochi' href='mailto:kochi@chromium.org'>
<meta name='author' title='Manuel Rego Casasnovas' href='mailto:rego@igalia.com'>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<input type="text">
<script>
var input = document.querySelector('input');
input.addEventListener('focus', function(e) {
test(() => {
try {
var focusPseudo = document.querySelector(':focus');
assert_equals(e.target, focusPseudo, "':focus' matches event.target");
} catch (error) {
assert_unreached("':focus' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus' pseudo-class matches inside 'focus' event handler");
test(() => {
try {
var focusVisiblePseudo = document.querySelector(':focus-visible');
assert_equals(e.target, focusVisiblePseudo, "':focus-visible' matches event.target");
} catch (error) {
assert_unreached("':focus-visible' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus-visible' pseudo-class matches inside 'focus' event handler");
test(() => {
try {
var focusWithinPseudo = document.querySelector(':focus-within');
assert_equals(document.documentElement, focusWithinPseudo, "':focus-within' matches document.documentElement");
} catch (error) {
assert_unreached("':focus-within' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus-within' pseudo-class matches inside 'focus' event handler");
}, false);
input.focus();
</script>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Selectors Level 4: :focus, :focus-visible and :focus-within in focusin event</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-pseudo">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-visible-pseudo">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
<link rel="help" href="https://w3c.github.io/uievents/#event-type-focusin">
<meta name='author' title='Manuel Rego Casasnovas' href='mailto:rego@igalia.com'>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<input type="text">
<script>
var input = document.querySelector('input');
input.addEventListener('focusin', function(e) {
test(() => {
try {
var focusPseudo = document.querySelector(':focus');
assert_equals(e.target, focusPseudo, "':focus' matches event.target");
} catch (error) {
assert_unreached("':focus' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus' pseudo-class matches inside 'focusin' event handler");
test(() => {
try {
var focusVisiblePseudo = document.querySelector(':focus-visible');
assert_equals(e.target, focusVisiblePseudo, "':focus-visible' matches event.target");
} catch (error) {
assert_unreached("':focus-visible' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus-visible' pseudo-class matches inside 'focusin' event handler");
test(() => {
try {
var focusWithinPseudo = document.querySelector(':focus-within');
assert_equals(document.documentElement, focusWithinPseudo, "':focus-within' matches document.documentElement");
} catch (error) {
assert_unreached("':focus-within' is an invalid selector. SyntaxError: " + error);
}
}, "Checks that ':focus-within' pseudo-class matches inside 'focusin' event handler");
}, false);
input.focus();
</script>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS Test (Selectors): Keyboard focus enables :focus-visible</title>
<link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org" />
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="/html/interaction/focus/the-autofocus-attribute/resources/utils.js"></script>
<style>
@supports not selector(:focus-visible) {
#button:focus {
outline: red solid 5px;
background-color: red;
}
}
:focus-visible {
outline: green solid 5px;
}
#button:focus:not(:focus-visible) {
background-color: red;
outline: 0;
}
</style>
</head>
<body>
This test checks that any element focused via an <code>autofocus</code> attribute will have <code>:focus-visible</code> matching enabled.
<ul id="instructions">
<li>If the button that says "I will be focused automatically" has a red background, then the test result is FAILURE. If it has a green outline, then the test result is SUCCESS.</li>
</ul>
<br />
<button id="button" autofocus tabindex="-1">I will be focused automatically.</button>
<script>
promise_test(async function() {
await waitUntilStableAutofocusState();
assert_equals(document.activeElement, button, "Should have correct focused element");
assert_equals(getComputedStyle(button).outlineColor, "rgb(0, 128, 0)", `outlineColor for ${button.tagName}#${button.id} should be green`);
assert_not_equals(getComputedStyle(button).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${button.tagName}#${button.id} should NOT be red`);
}, "Autofocus should match :focus-visible");
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS Test (Selectors): Keyboard focus enables :focus-visible</title>
<link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org" />
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
@supports not selector(:focus-visible) {
:focus {
outline: red solid 5px;
background-color: red;
}
}
:focus-visible {
outline: green solid 5px;
}
:focus:not(:focus-visible) {
background-color: red;
outline: 0;
}
</style>
</head>
<body>
This test checks that any element focused programmatically on page load will have <code>:focus-visible</code> matching enabled.
<ul id="instructions">
<li>If the element that says "I will be focused automatically" has a red background, then the test result is FAILURE. If the element has a green outline, then the test result is SUCCESS.</li>
</ul>
<br />
<div id="el" tabindex="-1">I will be focused automatically.</div>
<script>
window.addEventListener('load', () => {
el.focus();
});
async_test(function(t) {
el.addEventListener("focus", t.step_func(function() {
assert_equals(getComputedStyle(el).outlineColor, "rgb(0, 128, 0)", `outlineColor for ${el.tagName}#${el.id} should be green`);
assert_not_equals(getComputedStyle(el).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${el.tagName}#${el.id} should NOT be red`);
t.done();
}));
}, "Programmatic focus on page load should match :focus-visible");
</script>
</body>
</html>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Selectors Test: :focus-visible matches after script focus move</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<meta name="assert" content="This test checks that if the active element matches ':focus-visible' and a script causes focus to move elsewhere, the newly focused element should match ':focus-visible'.">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
@supports not selector(:focus-visible) {
:focus {
outline: red solid 5px;
background-color: red;
}
}
:focus-visible {
background: lime;
}
:focus:not(:focus-visible) {
background-color: red;
}
</style>
<input id="input"></input>
<div id="target" tabindex="0">Target</div>
<script>
async_test(function(t) {
input.addEventListener("focus", t.step_func(function() {
assert_equals(getComputedStyle(input).backgroundColor, "rgb(0, 255, 0)", `backgroundColor for ${input.tagName}#${input.id} should be lime`);
target.focus();
}));
target.addEventListener("focus", t.step_func(function() {
assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 255, 0)", `backgroundColor for ${target.tagName}#${target.id} should be lime`);
t.done();
}));
input.focus();
}, ":focus-visible matches after script focus move");
</script>

View file

@ -0,0 +1,93 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Test (Selectors): By default programatic focus matches :focus-visible and it shows an auto focus ring</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<link rel="help" href="https://html.spec.whatwg.org/#phrasing-content-3" />
<meta name="timeout" content="long">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../support/parsing-testcommon.js"></script>
<style>
#warning {
display: none;
background: red;
}
@supports not selector(:focus-visible) {
#instructions {
display: none;
}
#warning {
display: block;
}
}
</style>
<p>This test checks that by default, if using JavaScript to focus an element triggers <code>:focus-visible</code> matching, then the element should show a focus ring with <code>outline-style: auto</code>.</p>
<ol id="instructions">
<li>Focus the following elements with the keyaboard navigation (pressing TAB), if the elements show a focus ring with <code>outline-style: auto</code>, then the test result is SUCCESS.</li>
</ol>
<p id="warning">Your user-agent does not support <code>:focus-visible</code> pseudo-class, please SKIP this test.</p>
<abbr tabindex="0">abbr</abbr>
<address tabindex="0">address</address>
<a href="#">a</a>
<bdi tabindex="0">bdi</bdi>
<blockquote tabindex="0">blockquote</blockquote>
<code tabindex="0">code</code>
<dd tabindex="0">dd</dd>
<details open><summary tabindex="0">summary</summary></details>
<details tabindex="0"></details>
<div tabindex="0">div</div>
<dl tabindex="0">dl</dl>
<dt tabindex="0">dt</dt>
<em tabindex="0">em</em>
<fieldset><legend tabindex="0">legend</legend></fieldset>
<figcaption tabindex="0">figcaption</figcaption>
<figure tabindex="0">figure</figure>
<form tabindex="0">form</form>
<hr tabindex="0" />
<img tabindex="0" src="/images/green.png" />
<label tabindex="0">label</label>
<li tabindex="0">li</li>
<mark tabindex="0">mark</mark>
<meter tabindex="0"></meter>
<ol tabindex="0">ol</ol>
<pre tabindex="0">pre</pre>
<progress tabindex="0"></progress>
<p tabindex="0">p</p>
<small tabindex="0">small</small>
<s tabindex="0">s</s>
<strong tabindex="0">strong</strong>
<sub tabindex="0">sub</sub>
<sup tabindex="0">sup</sup>
<table><caption tabindex="0">caption</caption></table>
<table tabindex="0"><td>table</td></table>
<table><td tabindex="0">td</td></table>
<time tabindex="0">time</time>
<ul tabindex="0">ul</ul>
<u tabindex="0">u</u>
<script>
setup({ explicit_done: true });
// Check that :focus-visible is supported.
test_valid_selector(':focus-visible');
const elements = document.querySelectorAll("[tabindex]");
for (let i = 0; i < elements.length; i++) {
const target = elements[i];
promise_test(() => {
return new Promise(resolve => {
target.addEventListener("focus", resolve);
target.focus();
if (i == (elements.length - 1))
done();
}).then(() => {
assert_equals(getComputedStyle(target).outlineStyle, "auto", `outline-style for ${target.tagName} should be auto`);
});
}, `By default initial programatic focus matches ':focus-visible', so the element ${target.tagName} shows a focus ring with 'outline-style: auto'`);
}
</script>

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Test (Selectors): By default initial programatic focus matches :focus-visible and it shows an auto focus ring</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<link rel="help" href="https://html.spec.whatwg.org/#phrasing-content-3" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../support/parsing-testcommon.js"></script>
<style>
#warning {
display: none;
background: red;
}
@supports not selector(:focus-visible) {
#instructions {
display: none;
}
#warning {
display: block;
}
}
</style>
<p>This test checks that by default, if using JavaScript to focus an element triggers <code>:focus-visible</code> matching, then the element should show a focus ring with <code>outline-style: auto</code>.</p>
<ol id="instructions">
<li>If the element below that says "Target" show a focus ring with <code>outline-style: auto</code>, then the test result is SUCCESS.</li>
</ol>
<p id="warning">Your user-agent does not support <code>:focus-visible</code> pseudo-class, please SKIP this test.</p>
<div id="target" tabindex="0">Target</div>
<script>
// Check that :focus-visible is supported.
test_valid_selector(':focus-visible');
async_test(function(t) {
target.addEventListener("focus", t.step_func(function() {
assert_equals(getComputedStyle(target).outlineStyle, "auto", `outline-style for ${target.tagName}#${target.id} should be auto`);
t.done();
}));
target.focus();
}, "By default initial programatic focus matches ':focus-visible', so the element shows a focus ring with 'outline-style: auto'");
</script>

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Test (Selectors): :focus-visible doesn't match on ShadowRoot</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../support/parsing-testcommon.js"></script>
<style>
#warning {
display: none;
background: red;
}
@supports not selector(:focus-visible) {
#instructions {
display: none;
}
#warning {
display: block;
}
}
#host:focus-visible {
outline: 0;
background-color: red;
}
</style>
<p>This test checks that <code>:focus-visible</code> doesn't math on ShadowRoot.</p>
<ol id="instructions">
<li>The input should be focused on load, if it's not focused, focus it via mouse or keyboard.</li>
<li>If you see no red the test result is SUCCESS.</li>
</ol>
<p id="warning">Your user-agent does not support <code>:focus-visible</code> pseudo-class, please SKIP this test.</p>
<div id="host" style="height: 100px;"></div>
<script>
const shadowRoot = host.attachShadow({mode: 'open', delegatesFocus: true});
shadowRoot.innerHTML = '<input id="target" autofocus value="Focus me">';
// Check that :focus-visible is supported.
test_valid_selector(':focus-visible');
async_test((t) => {
host.focus();
window.requestAnimationFrame(t.step_func_done(() => {
assert_not_equals(getComputedStyle(host).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${host.tagName}#${host.id} should NOT be red`);
let focusVisiblePseudoAll = document.querySelectorAll(':focus-visible');
assert_equals(focusVisiblePseudoAll.length, 0, "No element matches ':focus-visible'");
let focusVisibleShadowDOMPseudoAll = shadowRoot.querySelectorAll(':focus-visible');
assert_equals(focusVisibleShadowDOMPseudoAll.length, 1, "Only one element matches ':focus-visible' in the Shadow DOM");
let target = shadowRoot.getElementById("target");
assert_equals(target, focusVisibleShadowDOMPseudoAll[0], "${target.tagName}#${target.id} matches ':focus-visible'");
}));
}, ":focus-visible doesn't match on ShadowRoot");
</script>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Test (Selectors): Script focus without any previous user interaction matches :focus-visible</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../support/parsing-testcommon.js"></script>
<style>
#warning {
display: none;
background: red;
}
@supports not selector(:focus-visible) {
#instructions {
display: none;
}
#warning {
display: block;
}
}
:focus-visible {
outline: solid thick green;
}
:focus:not(:focus-visible) {
background-color: red;
}
</style>
<p>This test checks that a script focus when the user hasn't interacted with the page yet, always matches <code>:focus-visible</code>.</p>
<ol id="instructions">
<li>If the element that says "Focused" has a red background then the test result is FAILURE, if it has a green outline then the test result is SUCCESS.</li>
</ol>
<p id="warning">Your user-agent does not support <code>:focus-visible</code> pseudo-class, please SKIP this test.</p>
<div id="target" tabindex="0">Focused</div>
<script>
// Check that :focus-visible is supported.
test_valid_selector(':focus-visible');
async_test(function(t) {
target.addEventListener("focus", t.step_func_done(function() {
assert_equals(getComputedStyle(target).outlineColor, "rgb(0, 128, 0)", `outlineColor for ${target.tagName}#${target.id} should be green`);
assert_not_equals(getComputedStyle(target).backgroundColor, "rgb(255, 0, 0)", `backgroundColor for ${target.tagName}#${target.id} should NOT be red`);
}));
}, "Script focus without any previous user interaction matches :focus-visible");
target.focus();
</script>

View file

@ -0,0 +1,158 @@
<!DOCTYPE html>
<html id="html">
<head>
<meta charset="utf-8">
<title>Selectors Level 4: focus-within</title>
<link rel="author" title="Benjamin Poulain" href="mailto:bpoulain@apple.com">
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
<meta name="assert" content="Checks the basic features of the ':focus-within' pseudo class.">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
* {
background-color: white;
}
:focus-within {
background-color: rgb(1, 2, 3);
}
</style>
</head>
<body id="body">
<div id="test">
<div id="container1">
<div id="sibling1"></div>
<div id="sibling2">
<input id="target1">
</div>
<div id="sibling3"></div>
</div>
<div id="container2">
<div id="sibling4"></div>
<div id="sibling5">
<textarea id="target2"></textarea>
</div>
<div id="sibling6"></div>
</div>
</div>
<div id=log></div>
<script>
"use strict";
function elementsStyledWithFocusWithinSelector() {
let elements = [];
for (let element of document.querySelectorAll("*")) {
if (getComputedStyle(element).backgroundColor === 'rgb(1, 2, 3)') {
elements.push(element.id);
}
}
return elements;
}
function elementsMatchingFocusWithinSelector() {
let elements = [];
for (let element of document.querySelectorAll(":focus-within")) {
elements.push(element.id);
}
return elements;
}
test(
function() {
assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
assert_array_equals(elementsMatchingFocusWithinSelector(), []);
}, "Initial State");
var container1 = document.getElementById("container1");
var container2 = document.getElementById("container2");
var target1 = document.getElementById("target1");
var target2 = document.getElementById("target2");
test(
function() {
target1.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
}, "Focus 'target1'");
test(
function() {
target2.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
}, "Focus 'target2'");
test(
function() {
target1.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
}, "Focus 'target1' again");
test(
function() {
target2.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
}, "Focus 'target2' again");
test(
function() {
target1.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
}, "Focus 'target1' once again");
test(
function() {
container1.parentElement.removeChild(container1);
assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
assert_array_equals(elementsMatchingFocusWithinSelector(), []);
assert_equals(container1.querySelectorAll(":focus-within").length, 0);
assert_false(target1.matches(":focus"));
assert_false(target2.matches(":focus"));
}, "Detach 'container1' from the document");
test(
function() {
target1.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
assert_array_equals(elementsMatchingFocusWithinSelector(), []);
assert_equals(container1.querySelectorAll(":focus-within").length, 0);
assert_false(target1.matches(":focus"));
assert_false(target2.matches(":focus"));
}, "Try to focus 'target1'");
test(
function() {
target2.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
}, "Focus 'target2' once again");
test(
function() {
container2.appendChild(container1);
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
}, "Attach 'container1' in 'container2'");
test(
function() {
target1.focus();
assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "container1", "sibling2", "target1"]);
assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "container1", "sibling2", "target1"]);
}, "Focus 'target1' for the last time");
test(
function() {
container2.appendChild(target1);
assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
assert_array_equals(elementsMatchingFocusWithinSelector(), []);
assert_false(target1.matches(":focus"));
assert_false(target2.matches(":focus"));
}, "Move 'target1' in 'container2'");
</script>
</body>
</html>

View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Selectors Level 4: focus-within</title>
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#focus-fixup-rule">
<meta name="assert" content="Checks ':focus-within' pseudo-class after 'display: none'.">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<div id="wrapper">
<input id="input">
</div>
<script>
"use strict";
const wrapper = document.getElementById("wrapper");
const input = document.getElementById("input");
async_test((t) => {
input.focus();
window.requestAnimationFrame(() => {
t.step(() => assert_true(input.matches(":focus-within"),
"Check input matches ':focus-within' after being focused"));
t.step(() => assert_true(wrapper.matches(":focus-within"),
"Check wrapper matches ':focus-within' after child was focused"));
input.style.display = "none";
window.requestAnimationFrame(() => {
t.step(() => assert_false(input.matches(":focus-within"),
"Check input doesn't match ':focus-within' after getting 'display: none'"));
t.step(() => assert_false(wrapper.matches(":focus-within"),
"Check wrapper doesn't match ':focus-within' after child got 'display: none'"));
input.style.display = "inline";
t.done();
});
});
}, "Test ':focus-within' after 'display:none' on input");
async_test((t) => {
input.focus();
window.requestAnimationFrame(() => {
t.step(() => assert_true(input.matches(":focus-within"),
"Check input matches ':focus-within' after being focused"));
t.step(() => assert_true(wrapper.matches(":focus-within"),
"Check wrapper matches ':focus-within' after child was focused"));
wrapper.style.display = "none";
window.requestAnimationFrame(() => {
t.step(() => assert_false(input.matches(":focus-within"),
"Check input doesn't match ':focus-within' after parent got 'display: none'"));
t.step(() => assert_false(wrapper.matches(":focus-within"),
"Check wrapper doesn't match ':focus-within' after getting 'display: none'"));
wrapper.style.display = "block";
t.done();
});
});
}, "Test ':focus-within' after 'display:none' on input's parent");
</script>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<title>Test string hash collision in bucketing</title>
<meta rel="author" href="mailto:sesse@chromium.org" title="Steinar H. Gunderson">
<link rel="help" href="https://www.w3.org/TR/css3-selectors/#selectors"/>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
/* These strings all collide in Blink's AtomicString hash function. */
.abetfx { --a: a; }
.adqcne { --b: b; }
.anztgy { --c: c; }
.jkeyea { --d: d; }
.ltjjvc { --e: e; }
.osniry { --f: f; }
.otgvil { --g: g; }
.ppvdzg { --h: h; }
.pwkbxn { --i: i; }
.rkefup { --j: j; }
.wsqwrf { --k: k; }
.zzpnvg { --l: l; }
</style>
</head>
<body>
<div id="d" class="abetfx adqcne anztgy jkeyea ltjjvc osniry otgvil ppvdzg pwkbxn rkefup wsqwrf zzpnvg">Some text</div>
<script>
test(() => {
const cs = getComputedStyle(d);
assert_equals('a', cs.getPropertyValue('--a'));
assert_equals('b', cs.getPropertyValue('--b'));
assert_equals('c', cs.getPropertyValue('--c'));
assert_equals('d', cs.getPropertyValue('--d'));
assert_equals('e', cs.getPropertyValue('--e'));
assert_equals('f', cs.getPropertyValue('--f'));
assert_equals('g', cs.getPropertyValue('--g'));
assert_equals('h', cs.getPropertyValue('--h'));
assert_equals('i', cs.getPropertyValue('--i'));
assert_equals('j', cs.getPropertyValue('--j'));
assert_equals('k', cs.getPropertyValue('--k'));
assert_equals('l', cs.getPropertyValue('--l'));
});
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :last-child</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-last-child-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also:
* child-indexed-pseudo-class.html
* child-indexed-no-parent.html
* invalidation/first-child-last-child.html
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<blockquote></blockquote>
<div id="target2">There is a prior child element.</div>
</div>
<div>
<div id="target3">A comment node should be ignored.</div>
<!-- -->
</div>
<div>
<div id="target4">Non-whitespace text node should be ignored.</div>
.
</div>
<div>
<div id="target5" data-expected="false">The first child should not be matched.</div>
<blockquote></blockquote>
</div>
<script>
for (let i = 1; i <= 5; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'false')
assert_false(target.matches(':last-child'));
else
assert_true(target.matches(':last-child'));
}, target.textContent);
}
</script>

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :last-of-type</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-last-of-type-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also:
* child-indexed-pseudo-class.html
* child-indexed-no-parent.html
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<div></div>
<div id="target2">Thre is another child element of the same type.</div>
</div>
<div>
<div id="target3">There is a posterior child element of another type.</div>
<blockquote></blockquote>
</div>
<div>
<blockquote>
<div id="target4">A next element of the parent should not affect.</div>
</blockquote>
<div></div>
</div>
<div>
<div>
<div id="target5">The parent element of the same type should not affect.</div>
</div>
</div>
<div>
<div id="target6">A child of the next element should not affect.</div>
<blockquote>
<div></div>
</blockquote>
</div>
<div>
<div id="target7" data-expected="false">The first child element of the same
type should not match.</div>
<div></div>
</div>
<div>
<div id="target8" data-expected="false">The first child element of the same
type should not match, the last child has a case-different tag name.</div>
<DIV></DIV>
</div>
<div>
<div id="insertAfter1"></div>
</div>
<script>
for (let i = 1; i <= 8; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'false')
assert_false(target.matches('div:last-of-type'));
else
assert_true(target.matches('div:last-of-type'));
}, target.textContent.replaceAll('\n', ' '));
}
test(() => {
const ia1 = document.querySelector('#insertAfter1');
const target = document.createElement('div');
assert_true(ia1.matches('div:last-of-type'));
ia1.parentNode.insertBefore(target, ia1.nextSibling);
assert_true(target.matches('div:last-of-type'));
assert_false(ia1.matches('div:last-of-type'));
target.remove();
assert_true(ia1.matches('div:last-of-type'));
}, 'Dynamic insertion and removal');
</script>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta id="expected" charset="utf-8">
<title>Selectors: attribute selectors with missing right token</title>
<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#attribute-selectors">
<link rel="help" href="https://drafts.csswg.org/css-syntax/#rule-defs">
<meta name="assert" content="Checks attribute selectors with missing right token are matched.">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="container">
<span></span>
<span class="cls"></span>
</div>
<script>
test(() => {
assert_equals(document.querySelector('meta[charset="utf-8"'), expected);
assert_equals(document.querySelector('meta[charset="utf-8'), expected);
assert_equals(container.querySelectorAll('span:not([class]').length, 1);
assert_equals(container.querySelectorAll('span:not([class').length, 1);
}, "attribute selectors with missing right tokens succeed");
</script>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<title>Matching behavior for :not with complex selector list</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#negation">
<main id=main>
<div id=a><div id=d></div></div>
<div id=b><div id=e></div></div>
<div id=c><div id=f></div></div>
</main>
<script>
function formatElements(elements) {
return elements.map(e => e.id).sort().join();
}
// Test that |selector| returns the given elements in #main.
function test_selector(selector, expected) {
test(function() {
let actual = Array.from(main.querySelectorAll(selector));
assert_equals(formatElements(actual), formatElements(expected));
}, `${selector} matches expected elements`);
}
test_selector(':not(#a)', [b, c, d, e, f]);
test_selector(':not(#a #d)', [a, b, c, e, f]);
test_selector(':not(#b div)', [a, b, c, d, f]);
test_selector(':not(div div)', [a, b, c]);
test_selector(':not(div + div)', [a, d, e, f]);
test_selector(':not(main > div)', [d, e, f]);
test_selector(':not(#a, #b)', [c, d, e, f]);
test_selector(':not(#f, main > div)', [d, e]);
test_selector(':not(div + div + div, div + div > div)', [a, b, d]);
test_selector(':not(div:nth-child(1))', [b, c]);
test_selector(':not(:not(div))', [a, b, c, d, e, f]);
test_selector(':not(:not(:not(div)))', []);
test_selector(':not(div, span)', []);
test_selector(':not(span, p)', [a, b, c, d, e, f]);
test_selector(':not(#unknown, .unknown)', [a, b, c, d, e, f]);
test_selector(':not(#unknown > div, span)', [a, b, c, d, e, f]);
test_selector(':not(#unknown ~ div, span)', [a, b, c, d, e, f]);
test_selector(':not(:hover div)', [a, b, c, d, e, f]);
test_selector(':not(:link div)', [a, b, c, d, e, f]);
test_selector(':not(:visited div)', [a, b, c, d, e, f]);
</script>

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<title>Specificity for complex :not selectors</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#negation">
<style>
main :not(#foo) { --t0:PASS; }
main :not(.foo) { --t0:FAIL; }
main :not(div#foo) { --t1:PASS; }
main :not(#foo) { --t1:FAIL; }
main :not(.bar, #foo) { --t2:FAIL; }
main :not(#foo, .bar) { --t2:PASS; }
main :not(.bar, #foo) { --t3:PASS; }
main :not(.foo, .bar) { --t3:FAIL; }
main :not(span + span) { --t4:PASS; }
main :not(span) { --t4:FAIL; }
main :not(span, li, #foo) { --t5:PASS; }
main :not(span, li, p) { --t5:FAIL; }
main :not(span, :not(:not(.a#foo)), p) { --t6:PASS; }
main :not(span, #foo, p) { --t6:FAIL; }
main :not(span, #foo, p) { --t7:PASS; }
main :not(span, :where(.a#foo), p) { --t7:FAIL; }
</style>
<main id=main>
<div id=div></div>
</main>
<script>
function test_value(name, description) {
test(function() {
let actual = getComputedStyle(div).getPropertyValue(name);
assert_equals(actual, 'PASS');
}, description);
}
test_value('--t0', ':not(#foo) wins over :not(.foo)');
test_value('--t1', ':not(div#foo) wins over :not(#foo)');
test_value('--t2', ':not(.bar, #foo) has same specificity as :not(#foo, .bar)');
test_value('--t3', ':not(.bar, #foo) wins over :not(.foo, .bar)');
test_value('--t4', ':not(span + span) wins over :not(span)');
test_value('--t5', ':not(span, li, p) wins over :not(span, lo, p)');
test_value('--t6', ':not(span, :not(:not(.a#foo)), p) wins over :not(span, #foo, p)');
test_value('--t7', ':not(span, #foo, p) wins over :not(span, :where(.a#foo), p)');
</script>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Selectors: :nth-last-child() with no argument</title>
<link rel="help" href="https://crbug.com/355451192">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#child-index">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
#target:nth-last-child() { color: red; }
#target { color: green; }
</style>
<head>
<body>
<body>
<div id="target">Test passes if this line is green.</div>
<script>
test(() => {
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
});
</script>
</body>
</html>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<title>CSS Selectors Test: :*-of-type with namespace</title>
<link rel="help" href="https://drafts.csswg.org/selectors/#typed-child-index">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
[test-span]:nth-of-type(100) {
color: green;
}
</style>
<div id="container"></div>
<script>
setup(() => {
function appendSpans(parent) {
for (let i = 0; i < 99; i++) {
parent.appendChild(document.createElement("span"));
}
const test_span = document.createElement("span");
test_span.setAttribute("test-span", "");
parent.appendChild(test_span);
}
function appendSpansNS(parent, namespace) {
for (let i = 0; i < 99; i++) {
parent.appendChild(document.createElementNS(namespace, "span"));
}
const test_span = document.createElementNS(namespace, "span");
test_span.setAttribute("test-span", "");
parent.appendChild(test_span);
}
appendSpans(container);
appendSpansNS(container, "http://dummy1/");
appendSpansNS(container, "http://dummy2/");
});
const green = "rgb(0, 128, 0)";
for (let span of container.querySelectorAll("[test-span]")) {
test(() => {
assert_equals(getComputedStyle(span).color, green,
"span with namespace: " + span.namespaceURI
+ " should have a green color");
}, ":nth-of-type selectors matching takes element namespace into account ("
+ span.namespaceURI + ")");
}
</script>

View file

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :only-child</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-only-child-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also child-indexed-pseudo-class.html.
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<div id="target2">A comment node should be ignored.</div>
<!-- -->
</div>
<div>
<div id="target3">Non-whitespace text node should be ignored.</div>
.
</div>
<div>
<blockquote></blockquote>
<div id="target4" data-expected="false">There is another child element.</div>
</div>
<div>
<div id="target5"></div>
</div>
<script>
for (let i = 1; i <= 4; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'false')
assert_false(target.matches(':only-child'));
else
assert_true(target.matches(':only-child'));
}, target.textContent);
}
test(() => {
const target = document.querySelector('#target5');
assert_true(target.matches(':only-child'));
const another = target.parentNode.appendChild(document.createElement('div'));
assert_false(target.matches(':only-child'));
assert_false(another.matches(':only-child'));
another.remove();
assert_true(target.matches(':only-child'));
}, 'Dynamic addition and removal');
</script>

View file

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Selectors :only-of-type</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-only-of-type-pseudo">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!--
See also child-indexed-pseudo-class.html.
-->
<body>
<div>
<div id="target1">Whitespace nodes should be ignored.</div>
</div>
<div>
<div id="target2">A comment node should be ignored.</div>
<!-- -->
</div>
<div>
<div id="target3">Non-whitespace text node should be ignored.</div>
.
</div>
<div>
<blockquote></blockquote>
<div id="target4" data-expected="false">There is another child element of a different type.</div>
</div>
<div>
<div id="target5"></div>
</div>
<script>
for (let i = 1; i <= 4; ++i) {
let target = document.querySelector(`#target${i}`);
test(() => {
if (target.dataset.expected == 'true')
assert_false(target.matches(':only-of-type'));
else
assert_true(target.matches(':only-of-type'));
}, target.textContent);
}
test(() => {
const target = document.querySelector('#target5');
assert_true(target.matches(':only-of-type'));
const of_different_type = target.parentNode.appendChild(document.createElement('span'));
assert_true(of_different_type.matches(':only-of-type'));
assert_true(target.matches(':only-of-type'));
const another_of_type = target.parentNode.appendChild(document.createElement('div'));
assert_false(target.matches(':only-of-type'));
assert_false(another_of_type.matches(':only-of-type'));
another_of_type.remove();
assert_true(target.matches(':only-of-type'));
}, 'Dynamic addition and removal');
</script>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<title>CSS Selectors Test: :placeholder-shown matching</title>
<link rel="help" href="https://drafts.csswg.org/selectors/#placeholder">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
:not(:placeholder-shown) + #t1,
:placeholder-shown + #t2,
:placeholder-shown + #t3,
:placeholder-shown + #t4,
:not(:placeholder-shown) + #t5,
:not(:placeholder-shown) + #t6,
:not(:placeholder-shown) + #t7 {
color: green;
}
</style>
<input type="text"><span id="t1">Should be green</span>
<input type="text" placeholder><span id="t2">Should be green</span>
<input type="text" placeholder=""><span id="t3">Should be green</span>
<input type="text" placeholder="placeholder"><span id="t4">Should be green</span>
<input type="text" placeholder value="value"><span id="t5">Should be green</span>
<input type="text" placeholder="" value="value"><span id="t6">Should be green</span>
<input type="text" placeholder="placeholder" value="value"><span id="t7">Should be green</span>
<script>
const green = "rgb(0, 128, 0)";
test(() => assert_equals(getComputedStyle(t1).color, green,
"No placeholder attribute"));
test(() => assert_equals(getComputedStyle(t2).color, green,
"Placeholder attribute without value"));
test(() => assert_equals(getComputedStyle(t3).color, green,
"Placeholder attribute - empty string"));
test(() => assert_equals(getComputedStyle(t4).color, green,
"Placeholder attribute - non-empty string"));
test(() => assert_equals(getComputedStyle(t5).color, green,
"Placeholder attribute without value - input text"));
test(() => assert_equals(getComputedStyle(t6).color, green,
"Placeholder attribute - empty string - input text"));
test(() => assert_equals(getComputedStyle(t7).color, green,
"Placeholder attribute - non-empty string - input text"));
</script>

View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#enableddisabled">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<body>
<div id="container">
<button id="button_enabled"></button>
<button id="button_disabled" disabled></button>
<input id="input_enabled">
<input id="input_disabled" disabled>
<select id="select_enabled"></select>
<select id="select_disabled" disabled></select>
<textarea id="textarea_enabled"></textarea>
<textarea id="textarea_disabled" disabled></textarea>
<span id="incapable"></span>
</div>
<script>
test(() => {
const container = document.querySelector('#container');
const matched = container.querySelectorAll(':enabled');
for (let element of matched) {
assert_true(element.id.endsWith('_enabled'), element.id);
}
}, ':enabeld should match to enabled controls');
test(() => {
const container = document.querySelector('#container');
const matched = container.querySelectorAll(':disabled');
for (let element of matched) {
assert_true(element.id.endsWith('_disabled'), element.id);
}
}, ':disabled should match to enabled controls');
test(() => {
const container = document.querySelector('#container');
const matched = container.querySelectorAll(':not(:enabled)');
for (let element of matched) {
assert_true(element.id.endsWith('_disabled') || element.id == 'incapable', element.id);
}
}, ':not(:enabeld) should match to disabled controls and non-controls');
test(() => {
const container = document.querySelector('#container');
const matched = container.querySelectorAll(':not(:disabled)');
for (let element of matched) {
assert_true(element.id.endsWith('_enabled') || element.id == 'incapable', element.id);
}
}, ':not(:disabled) should match to enabled controls and non-controls');
</script>
</body>

View file

@ -0,0 +1,37 @@
<!doctype html>
<link rel='help' href='https://drafts.csswg.org/selectors-4/#the-scope-pseudo'>
<meta name='description' content=':scope should match when context object is a ShadowRoot or a DocumentFragment'>
<script src='../../resources/testharness.js'></script>
<script src='../../resources/testharnessreport.js'></script>
<div id='shadowHost'></div>
<script>
'use strict'
const shadowHost = document.getElementById("shadowHost");
const shadowRoot = shadowHost.attachShadow({mode:'open'})
shadowRoot.appendChild(document.createElement("div"));
test (() => {
assert_equals(shadowRoot.querySelectorAll(':scope > div').length, 0, 'should not match in shadow root');
});
const documentFragment = document.createDocumentFragment();
documentFragment.appendChild(document.createElement("div"));
test(() => {
assert_equals(documentFragment.querySelectorAll(':scope > div').length, 0, 'should not match in document fragment');
});
test(() => {
assert_equals(shadowRoot.firstChild.querySelector(':scope'), null, 'should return null');
assert_equals(shadowRoot.firstChild.querySelectorAll(':scope').length, 0, 'should return 0');
assert_equals(shadowRoot.querySelector(':scope'), null, 'should return null');
assert_equals(shadowRoot.querySelectorAll(':scope').length, 0, 'should return 0');
assert_equals(documentFragment.querySelector(':scope'), null, 'should return null');
assert_equals(documentFragment.querySelectorAll(':scope').length, 0, 'should return 0');
assert_equals(document.querySelector(':scope'), document.documentElement, 'should return the document element');
assert_equals(document.querySelectorAll(':scope').length, 1, 'should return 1');
}, 'querySelector() with ":scope" should return the document element, if present in the subtree');
</script>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<title>When non-empty placeholder becomes empty, :placeholder-shown test</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#placeholder">
<input id="myinput" type="text" placeholder="FAIL">
<textarea id="mytextarea" placeholder="FAIL"></textarea>
<script>
test(() => {
const input = document.querySelector("input");
input.placeholder = "";
input.value = "NO RED";
assert_false(input.matches(":placeholder-shown"));
}, "input:placeholder-shown should not be matched");
test(() => {
const textarea = document.querySelector("textarea");
textarea.placeholder = "";
textarea.value = "No RED";
assert_false(textarea.matches(":placeholder-shown"));
}, "textarea:placeholder-shown should not be matched");
</script>

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<title>Test element names are case-insensitive only in ASCII range</title>
<link rel="help" href="https://www.w3.org/TR/selectors-4/#case-sensitive">
<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
<script src='../../resources/testharness.js'></script>
<script src='../../resources/testharnessreport.js'></script>
<style>
\212A {
display: block;
background: lime;
width: 200px;
height: 100px;
}
</style>
<body>
<p>You should see a green square below.</p>
<div id="container"></div>
<script>
// Insert from JavaScript to avoid parser doing something special.
let test_element = document.createElement('\u212A');
container.appendChild(test_element);
let test_element_with_ns = document.createElementNS('https://dummy.ns', '\u212A');
container.appendChild(test_element_with_ns);
test(() => {
assert_equals(test_element.offsetHeight, 100);
}, 'CSS selector should match for Unicode uppercase element');
test(() => {
// Elements in different namespace cannot compute style or height.
// Test the height of the container instead.
assert_equals(container.offsetHeight, 200);
}, 'Elements with namespace should work the same way');
test(() => {
let e = document.querySelector('k');
assert_equals(e, null);
}, '`querySelector` should not use Unicode case-folding');
</script>
</body>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<title>WebKit-prefixed pseudo-elements</title>
<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#compat">
<meta name="assert" content="WebKit-prefixed pseudo-elements should always be valid">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style id="style">
#test {
color: rgb(255, 0, 0);
}
span::-webkit-something-invalid, #test, ::-WeBkIt-sOmEtHiNg-NoNeXiSt123, ::-webkit-\ escaped {
color: rgb(0, 255, 0);
}
::-webkitfoo, #test {
color: rgb(255, 0, 0);
}
</style>
<body>
<div id="test"></div>
<script>
test(() => {
let elem = document.getElementById("test");
assert_equals(getComputedStyle(elem).color, "rgb(0, 255, 0)");
}, "rules include webkit-prefixed pseudo-element should be cascaded");
test(() => {
let sheet = document.getElementById("style").sheet;
assert_equals(sheet.cssRules[1].selectorText,
"span::-webkit-something-invalid, " +
"#test, ::-webkit-something-nonexist123, " +
"::-webkit-\\ escaped");
}, "webkit-prefixed pseudo-element selectors should be accessible from CSSOM");
test(() => {
document.querySelector("span::-webkit-something-invalid");
document.querySelectorAll("span::-webkit-something-invalid");
}, "qS and qSA shouldn't throw exception");
test(() => {
let sheet = document.getElementById("style").sheet;
assert_equals(sheet.cssRules.length, 2);
assert_throws_dom("SyntaxError", () => document.querySelector("span::-webkitfoo"));
assert_throws_dom("SyntaxError", () => document.querySelectorAll("span::-webkitfoo"));
}, "webkit-prefix without dash is invalid");
</script>
</body>

View file

@ -0,0 +1,22 @@
<!doctype html>
<title>CSS Test: 'x-' prefixed pseudo-elements don't parse correctly</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<link rel="help" href="https://drafts.csswg.org/selectors-4/#pseudo-elements">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
p {
color: green;
}
::x-something-nobody-would-think-of, p {
color: red;
}
</style>
<p>Should be green
<script>
test(function() {
let p = document.querySelector('p');
assert_equals(getComputedStyle(p).color, "rgb(0, 128, 0)");
}, "x-prefixed pseudo-elements should make the whole rule invalid")
</script>