LibWeb: Import a bunch of :has() selector tests from WPT

This commit is contained in:
Andreas Kling 2024-10-27 12:33:57 +01:00 committed by Andreas Kling
parent 9e080e197c
commit a640fcc693
Notes: github-actions[bot] 2024-10-27 12:34:43 +00:00
44 changed files with 4493 additions and 0 deletions

View file

@ -0,0 +1,24 @@
Summary
Harness status: OK
Rerun
Found 13 tests
12 Pass
1 Fail
Details
Result Test Name MessagePass :has(:scope) matches expected elements on scope1
Pass :has(:scope .c) matches expected elements on scope1
Pass :has(.a :scope) matches expected elements on scope1
Fail .a:has(:scope) .c matches expected elements on scope1 assert_equals: expected "d02,d03" but got ""
Pass .a:has(:scope) .c and :is(.a :scope .c) returns same elements on scope1
Pass .a:has(:scope) .c matches expected elements on scope2
Pass .a:has(:scope) .c and :is(.a :scope .c) returns same elements on scope2
Pass .c:has(:is(:scope .d)) matches expected elements on scope1
Pass .c:has(:is(:scope .d)) and :scope .c:has(.d) returns same elements on scope1
Pass .c:has(:is(:scope .d)) and .c:has(.d) returns same elements on scope1
Pass .c:has(:is(:scope .d)) matches expected elements on scope2
Pass .c:has(:is(:scope .d)) and :scope .c:has(.d) returns same elements on scope2
Pass .c:has(:is(:scope .d)) and .c:has(.d) returns same elements on scope2

View file

@ -0,0 +1,28 @@
Summary
Harness status: OK
Rerun
Found 18 tests
18 Pass
Details
Result Test Name MessagePass :has(#a) matches expected elements
Pass :has(.ancestor) matches expected elements
Pass :has(.target) matches expected elements
Pass :has(.descendant) matches expected elements
Pass .parent:has(.target) matches expected elements
Pass :has(.sibling ~ .target) matches expected elements
Pass .parent:has(.sibling ~ .target) matches expected elements
Pass :has(:is(.target ~ .sibling .descendant)) matches expected elements
Pass .parent:has(:is(.target ~ .sibling .descendant)) matches expected elements
Pass .sibling:has(.descendant) ~ .target matches expected elements
Pass :has(> .parent) matches expected elements
Pass :has(> .target) matches expected elements
Pass :has(> .parent, > .target) matches expected elements
Pass :has(+ #h) matches expected elements
Pass .parent:has(~ #h) matches expected elements
Pass .sibling:has(.descendant) matches expected element
Pass closest(.ancestor:has(.descendant)) returns expected element
Pass :has(.target ~ .sibling .descendant) matches expectedly

View file

@ -0,0 +1,22 @@
Summary
Harness status: OK
Rerun
Found 12 tests
12 Pass
Details
Result Test Name MessagePass :has(child) matches expectedly
Pass :has(> child) matches expectedly
Pass :has(descendant) matches expectedly
Pass :has(> descendant) matches expectedly
Pass :has(~ direct_sibling) matches expectedly
Pass :has(+ direct_sibling) matches expectedly
Pass :has(~ indirect_sibling) matches expectedly
Pass :has(+ indirect_sibling) matches expectedly
Pass :has(*) matches expectedly
Pass :has(> *) matches expectedly
Pass :has(~ *) matches expectedly
Pass :has(+ *) matches expectedly

View file

@ -0,0 +1,45 @@
Summary
Harness status: OK
Rerun
Found 35 tests
35 Pass
Details
Result Test Name MessagePass .x:has(.a) matches expected elements
Pass .x:has(.a > .b) matches expected elements
Pass .x:has(.a .b) matches expected elements
Pass .x:has(.a + .b) matches expected elements
Pass .x:has(.a ~ .b) matches expected elements
Pass .x:has(> .a) matches expected elements
Pass .x:has(> .a > .b) matches expected elements
Pass .x:has(> .a .b) matches expected elements
Pass .x:has(> .a + .b) matches expected elements
Pass .x:has(> .a ~ .b) matches expected elements
Pass .x:has(+ .a) matches expected elements
Pass .x:has(+ .a > .b) matches expected elements
Pass .x:has(+ .a .b) matches expected elements
Pass .x:has(+ .a + .b) matches expected elements
Pass .x:has(+ .a ~ .b) matches expected elements
Pass .x:has(~ .a) matches expected elements
Pass .x:has(~ .a > .b) matches expected elements
Pass .x:has(~ .a .b) matches expected elements
Pass .x:has(~ .a + .b) matches expected elements
Pass .x:has(~ .a + .b > .c) matches expected elements
Pass .x:has(~ .a + .b .c) matches expected elements
Pass .x:has(.d .e) matches expected elements
Pass .x:has(.d .e) .f matches expected elements
Pass .x:has(> .d) matches expected elements
Pass .x:has(> .d) .f matches expected elements
Pass .x:has(~ .d ~ .e) matches expected elements
Pass .x:has(~ .d ~ .e) ~ .f matches expected elements
Pass .x:has(+ .d ~ .e) matches expected elements
Pass .x:has(+ .d ~ .e) ~ .f matches expected elements
Pass .y:has(> .g .h) matches expected elements
Pass .y:has(.g .h) matches expected elements
Pass .y:has(> .g .h) .i matches expected elements
Pass .y:has(.g .h) .i matches expected elements
Pass .d .x:has(.e) matches expected elements
Pass .d ~ .x:has(~ .e) matches expected elements

View file

@ -0,0 +1,18 @@
Summary
Harness status: OK
Rerun
Found 8 tests
8 Fail
Details
Result Test Name MessageFail :has(#foo) wins over :has(.foo) assert_equals: expected "PASS" but got ""
Fail :has(span#foo) wins over :has(#foo) assert_equals: expected "PASS" but got ""
Fail :has(.bar, #foo) has same specificity as :has(#foo, .bar) assert_equals: expected "PASS" but got ""
Fail :has(.bar, #foo) wins over :has(.foo, .bar) assert_equals: expected "PASS" but got ""
Fail :has(span + span) wins over :has(span) assert_equals: expected "PASS" but got ""
Fail :has(span, li, p) wins over :has(span, lo, p) assert_equals: expected "PASS" but got ""
Fail latter .baz wins over :has(.foo) assert_equals: expected "PASS" but got ""
Fail latter :has(.foo) wins over .baz assert_equals: expected "PASS" but got ""

View file

@ -0,0 +1,22 @@
Summary
Harness status: OK
Rerun
Found 12 tests
12 Pass
Details
Result Test Name MessagePass add .test to trigger1 - check subject1_1
Pass add .test to trigger1 - check subject1_2
Pass remove .test from trigger1 - check subject1_1
Pass remove .test from trigger1 - check subject1_2
Pass add .test to trigger2 - check subject2_1
Pass add .test to trigger2 - check subject2_2
Pass remove .test from trigger2 - check subject2_1
Pass remove .test from trigger2 - check subject2_2
Pass add .test to trigger3 - check subject3_1
Pass add .test to trigger3 - check subject3_2
Pass remove .test from trigger3 - check subject3_1
Pass remove .test from trigger3 - check subject3_2

View file

@ -0,0 +1,305 @@
Summary
Harness status: OK
Rerun
Found 295 tests
295 Pass
Details
Result Test Name MessagePass Initial color
Pass add .test to previous_sibling
Pass remove .test from previous_sibling
Pass add .test to previous_sibling_child
Pass remove .test from previous_sibling_child
Pass add .test to previous_sibling_descendant
Pass remove .test from previous_sibling_descendant
Pass add .test to subject
Pass remove .test from subject
Pass add .test to next_sibling
Pass remove .test from next_sibling
Pass add .test to next_sibling_child
Pass remove .test from next_sibling_child
Pass add .test to next_sibling_descendant
Pass remove .test from next_sibling_descendant
Pass insert element div.test before previous_sibling
Pass remove the class 'test' from the element inserted before previous_sibling
Pass add the class 'test' again to the element inserted before previous_sibling
Pass remove element div.test before previous_sibling
Pass insert element div before previous_sibling
Pass add the class 'test' to the element inserted again before previous_sibling
Pass remove the class 'test' from the element inserted again before previous_sibling
Pass remove element div before previous_sibling
Pass insert element div[test_attr] before previous_sibling
Pass remove element div[test_attr] before previous_sibling
Pass insert element div.test before previous_sibling_child
Pass remove the class 'test' from the element inserted before previous_sibling_child
Pass add the class 'test' again to the element inserted before previous_sibling_child
Pass remove element div.test before previous_sibling_child
Pass insert element div before previous_sibling_child
Pass add the class 'test' to the element inserted again before previous_sibling_child
Pass remove the class 'test' from the element inserted again before previous_sibling_child
Pass remove element div before previous_sibling_child
Pass insert element div[test_attr] before previous_sibling_child
Pass remove element div[test_attr] before previous_sibling_child
Pass insert element div.test before previous_sibling_descendant
Pass remove the class 'test' from the element inserted before previous_sibling_descendant
Pass add the class 'test' again to the element inserted before previous_sibling_descendant
Pass remove element div.test before previous_sibling_descendant
Pass insert element div before previous_sibling_descendant
Pass add the class 'test' to the element inserted again before previous_sibling_descendant
Pass remove the class 'test' from the element inserted again before previous_sibling_descendant
Pass remove element div before previous_sibling_descendant
Pass insert element div[test_attr] before previous_sibling_descendant
Pass remove element div[test_attr] before previous_sibling_descendant
Pass insert element div.test before subject
Pass remove the class 'test' from the element inserted before subject
Pass add the class 'test' again to the element inserted before subject
Pass remove element div.test before subject
Pass insert element div before subject
Pass add the class 'test' to the element inserted again before subject
Pass remove the class 'test' from the element inserted again before subject
Pass remove element div before subject
Pass insert element div[test_attr] before subject
Pass remove element div[test_attr] before subject
Pass insert element div.test before next_sibling
Pass remove the class 'test' from the element inserted before next_sibling
Pass add the class 'test' again to the element inserted before next_sibling
Pass remove element div.test before next_sibling
Pass insert element div before next_sibling
Pass add the class 'test' to the element inserted again before next_sibling
Pass remove the class 'test' from the element inserted again before next_sibling
Pass remove element div before next_sibling
Pass insert element div[test_attr] before next_sibling
Pass remove element div[test_attr] before next_sibling
Pass insert element div.test before next_sibling_child
Pass remove the class 'test' from the element inserted before next_sibling_child
Pass add the class 'test' again to the element inserted before next_sibling_child
Pass remove element div.test before next_sibling_child
Pass insert element div before next_sibling_child
Pass add the class 'test' to the element inserted again before next_sibling_child
Pass remove the class 'test' from the element inserted again before next_sibling_child
Pass remove element div before next_sibling_child
Pass insert element div[test_attr] before next_sibling_child
Pass remove element div[test_attr] before next_sibling_child
Pass insert element div.test before next_sibling_descendant
Pass remove the class 'test' from the element inserted before next_sibling_descendant
Pass add the class 'test' again to the element inserted before next_sibling_descendant
Pass remove element div.test before next_sibling_descendant
Pass insert element div before next_sibling_descendant
Pass add the class 'test' to the element inserted again before next_sibling_descendant
Pass remove the class 'test' from the element inserted again before next_sibling_descendant
Pass remove element div before next_sibling_descendant
Pass insert element div[test_attr] before next_sibling_descendant
Pass remove element div[test_attr] before next_sibling_descendant
Pass insert element div.test after previous_sibling
Pass remove the class 'test' from the element inserted after previous_sibling
Pass add the class 'test' again to the element inserted after previous_sibling
Pass remove element div.test after previous_sibling
Pass insert element div after previous_sibling
Pass add the class 'test' to the element inserted again after previous_sibling
Pass remove the class 'test' from the element inserted again after previous_sibling
Pass remove element div after previous_sibling
Pass insert element div[test_attr] after previous_sibling
Pass remove element div[test_attr] after previous_sibling
Pass insert element div.test after previous_sibling_child
Pass remove the class 'test' from the element inserted after previous_sibling_child
Pass add the class 'test' again to the element inserted after previous_sibling_child
Pass remove element div.test after previous_sibling_child
Pass insert element div after previous_sibling_child
Pass add the class 'test' to the element inserted again after previous_sibling_child
Pass remove the class 'test' from the element inserted again after previous_sibling_child
Pass remove element div after previous_sibling_child
Pass insert element div[test_attr] after previous_sibling_child
Pass remove element div[test_attr] after previous_sibling_child
Pass insert element div.test after previous_sibling_descendant
Pass remove the class 'test' from the element inserted after previous_sibling_descendant
Pass add the class 'test' again to the element inserted after previous_sibling_descendant
Pass remove element div.test after previous_sibling_descendant
Pass insert element div after previous_sibling_descendant
Pass add the class 'test' to the element inserted again after previous_sibling_descendant
Pass remove the class 'test' from the element inserted again after previous_sibling_descendant
Pass remove element div after previous_sibling_descendant
Pass insert element div[test_attr] after previous_sibling_descendant
Pass remove element div[test_attr] after previous_sibling_descendant
Pass insert element div.test after subject
Pass remove the class 'test' from the element inserted after subject
Pass add the class 'test' again to the element inserted after subject
Pass remove element div.test after subject
Pass insert element div after subject
Pass add the class 'test' to the element inserted again after subject
Pass remove the class 'test' from the element inserted again after subject
Pass remove element div after subject
Pass insert element div[test_attr] after subject
Pass remove element div[test_attr] after subject
Pass insert element div.test after next_sibling
Pass remove the class 'test' from the element inserted after next_sibling
Pass add the class 'test' again to the element inserted after next_sibling
Pass remove element div.test after next_sibling
Pass insert element div after next_sibling
Pass add the class 'test' to the element inserted again after next_sibling
Pass remove the class 'test' from the element inserted again after next_sibling
Pass remove element div after next_sibling
Pass insert element div[test_attr] after next_sibling
Pass remove element div[test_attr] after next_sibling
Pass insert element div.test after next_sibling_child
Pass remove the class 'test' from the element inserted after next_sibling_child
Pass add the class 'test' again to the element inserted after next_sibling_child
Pass remove element div.test after next_sibling_child
Pass insert element div after next_sibling_child
Pass add the class 'test' to the element inserted again after next_sibling_child
Pass remove the class 'test' from the element inserted again after next_sibling_child
Pass remove element div after next_sibling_child
Pass insert element div[test_attr] after next_sibling_child
Pass remove element div[test_attr] after next_sibling_child
Pass insert element div.test after next_sibling_descendant
Pass remove the class 'test' from the element inserted after next_sibling_descendant
Pass add the class 'test' again to the element inserted after next_sibling_descendant
Pass remove element div.test after next_sibling_descendant
Pass insert element div after next_sibling_descendant
Pass add the class 'test' to the element inserted again after next_sibling_descendant
Pass remove the class 'test' from the element inserted again after next_sibling_descendant
Pass remove element div after next_sibling_descendant
Pass insert element div[test_attr] after next_sibling_descendant
Pass remove element div[test_attr] after next_sibling_descendant
Pass insert tree div>div.test before previous_sibling
Pass remove the class 'test' from the element in the tree inserted before previous_sibling
Pass add the class 'test' again to the element in the tree inserted before previous_sibling
Pass remove tree div>div.test before previous_sibling
Pass insert tree div>div before previous_sibling
Pass add the class 'test' to the element in the tree inserted again before previous_sibling
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling
Pass remove tree div>div before previous_sibling
Pass insert element div>div[test_attr] before previous_sibling
Pass remove element div>div[test_attr] before previous_sibling
Pass insert tree div>div.test before previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted before previous_sibling_child
Pass add the class 'test' again to the element in the tree inserted before previous_sibling_child
Pass remove tree div>div.test before previous_sibling_child
Pass insert tree div>div before previous_sibling_child
Pass add the class 'test' to the element in the tree inserted again before previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling_child
Pass remove tree div>div before previous_sibling_child
Pass insert element div>div[test_attr] before previous_sibling_child
Pass remove element div>div[test_attr] before previous_sibling_child
Pass insert tree div>div.test before previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted before previous_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted before previous_sibling_descendant
Pass remove tree div>div.test before previous_sibling_descendant
Pass insert tree div>div before previous_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again before previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling_descendant
Pass remove tree div>div before previous_sibling_descendant
Pass insert element div>div[test_attr] before previous_sibling_descendant
Pass remove element div>div[test_attr] before previous_sibling_descendant
Pass insert tree div>div.test before subject
Pass remove the class 'test' from the element in the tree inserted before subject
Pass add the class 'test' again to the element in the tree inserted before subject
Pass remove tree div>div.test before subject
Pass insert tree div>div before subject
Pass add the class 'test' to the element in the tree inserted again before subject
Pass remove the class 'test' from the element in the tree inserted again before subject
Pass remove tree div>div before subject
Pass insert element div>div[test_attr] before subject
Pass remove element div>div[test_attr] before subject
Pass insert tree div>div.test before next_sibling
Pass remove the class 'test' from the element in the tree inserted before next_sibling
Pass add the class 'test' again to the element in the tree inserted before next_sibling
Pass remove tree div>div.test before next_sibling
Pass insert tree div>div before next_sibling
Pass add the class 'test' to the element in the tree inserted again before next_sibling
Pass remove the class 'test' from the element in the tree inserted again before next_sibling
Pass remove tree div>div before next_sibling
Pass insert element div>div[test_attr] before next_sibling
Pass remove element div>div[test_attr] before next_sibling
Pass insert tree div>div.test before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted before next_sibling_child
Pass add the class 'test' again to the element in the tree inserted before next_sibling_child
Pass remove tree div>div.test before next_sibling_child
Pass insert tree div>div before next_sibling_child
Pass add the class 'test' to the element in the tree inserted again before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_child
Pass remove tree div>div before next_sibling_child
Pass insert element div>div[test_attr] before next_sibling_child
Pass remove element div>div[test_attr] before next_sibling_child
Pass insert tree div>div.test before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted before next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted before next_sibling_descendant
Pass remove tree div>div.test before next_sibling_descendant
Pass insert tree div>div before next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_descendant
Pass remove tree div>div before next_sibling_descendant
Pass insert element div>div[test_attr] before next_sibling_descendant
Pass remove element div>div[test_attr] before next_sibling_descendant
Pass insert tree div>div.test after previous_sibling
Pass remove the class 'test' from the element in the tree inserted after previous_sibling
Pass add the class 'test' again to the element in the tree inserted after previous_sibling
Pass remove tree div>div.test after previous_sibling
Pass insert tree div>div after previous_sibling
Pass add the class 'test' to the element in the tree inserted again after previous_sibling
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling
Pass remove tree div>div after previous_sibling
Pass insert element div>div[test_attr] after previous_sibling
Pass remove element div>div[test_attr] after previous_sibling
Pass insert tree div>div.test after previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted after previous_sibling_child
Pass add the class 'test' again to the element in the tree inserted after previous_sibling_child
Pass remove tree div>div.test after previous_sibling_child
Pass insert tree div>div after previous_sibling_child
Pass add the class 'test' to the element in the tree inserted again after previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling_child
Pass remove tree div>div after previous_sibling_child
Pass insert element div>div[test_attr] after previous_sibling_child
Pass remove element div>div[test_attr] after previous_sibling_child
Pass insert tree div>div.test after previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted after previous_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted after previous_sibling_descendant
Pass remove tree div>div.test after previous_sibling_descendant
Pass insert tree div>div after previous_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again after previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling_descendant
Pass remove tree div>div after previous_sibling_descendant
Pass insert element div>div[test_attr] after previous_sibling_descendant
Pass remove element div>div[test_attr] after previous_sibling_descendant
Pass insert tree div>div.test after subject
Pass remove the class 'test' from the element in the tree inserted after subject
Pass add the class 'test' again to the element in the tree inserted after subject
Pass remove tree div>div.test after subject
Pass insert tree div>div after subject
Pass add the class 'test' to the element in the tree inserted again after subject
Pass remove the class 'test' from the element in the tree inserted again after subject
Pass remove tree div>div after subject
Pass insert element div>div[test_attr] after subject
Pass remove element div>div[test_attr] after subject
Pass insert tree div>div.test after next_sibling
Pass remove the class 'test' from the element in the tree inserted after next_sibling
Pass add the class 'test' again to the element in the tree inserted after next_sibling
Pass remove tree div>div.test after next_sibling
Pass insert tree div>div after next_sibling
Pass add the class 'test' to the element in the tree inserted again after next_sibling
Pass remove the class 'test' from the element in the tree inserted again after next_sibling
Pass remove tree div>div after next_sibling
Pass insert element div>div[test_attr] after next_sibling
Pass remove element div>div[test_attr] after next_sibling
Pass insert tree div>div.test after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted after next_sibling_child
Pass add the class 'test' again to the element in the tree inserted after next_sibling_child
Pass remove tree div>div.test after next_sibling_child
Pass insert tree div>div after next_sibling_child
Pass add the class 'test' to the element in the tree inserted again after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_child
Pass remove tree div>div after next_sibling_child
Pass insert element div>div[test_attr] after next_sibling_child
Pass remove element div>div[test_attr] after next_sibling_child
Pass insert tree div>div.test after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted after next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted after next_sibling_descendant
Pass remove tree div>div.test after next_sibling_descendant
Pass insert tree div>div after next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_descendant
Pass remove tree div>div after next_sibling_descendant
Pass insert element div>div[test_attr] after next_sibling_descendant
Pass remove element div>div[test_attr] after next_sibling_descendant

View file

@ -0,0 +1,347 @@
Summary
Harness status: OK
Rerun
Found 337 tests
337 Pass
Details
Result Test Name MessagePass Initial color
Pass add .test to subject_ancestor
Pass remove .test from subject_ancestor
Pass add .test to subject_parent
Pass remove .test from subject_parent
Pass add .test to subject
Pass remove .test from subject
Pass add .test to subject_child
Pass remove .test from subject_child
Pass add .test to subject_descendant
Pass remove .test from subject_descendant
Pass add .test to next_sibling
Pass remove .test from next_sibling
Pass add .test to next_sibling_child
Pass remove .test from next_sibling_child
Pass add .test to next_sibling_descendant
Pass remove .test from next_sibling_descendant
Pass insert element div.test before subject_ancestor
Pass remove the class 'test' from the element inserted before subject_ancestor
Pass add the class 'test' again to the element inserted before subject_ancestor
Pass remove element div.test before subject_ancestor
Pass insert element div before subject_ancestor
Pass add the class 'test' to the element inserted again before subject_ancestor
Pass remove the class 'test' from the element inserted again before subject_ancestor
Pass remove element div before subject_ancestor
Pass insert element div[test_attr] before subject_ancestor
Pass remove element div[test_attr] before subject_ancestor
Pass insert element div.test before subject_parent
Pass remove the class 'test' from the element inserted before subject_parent
Pass add the class 'test' again to the element inserted before subject_parent
Pass remove element div.test before subject_parent
Pass insert element div before subject_parent
Pass add the class 'test' to the element inserted again before subject_parent
Pass remove the class 'test' from the element inserted again before subject_parent
Pass remove element div before subject_parent
Pass insert element div[test_attr] before subject_parent
Pass remove element div[test_attr] before subject_parent
Pass insert element div.test before subject
Pass remove the class 'test' from the element inserted before subject
Pass add the class 'test' again to the element inserted before subject
Pass remove element div.test before subject
Pass insert element div before subject
Pass add the class 'test' to the element inserted again before subject
Pass remove the class 'test' from the element inserted again before subject
Pass remove element div before subject
Pass insert element div[test_attr] before subject
Pass remove element div[test_attr] before subject
Pass insert element div.test before subject_child
Pass remove the class 'test' from the element inserted before subject_child
Pass add the class 'test' again to the element inserted before subject_child
Pass remove element div.test before subject_child
Pass insert element div before subject_child
Pass add the class 'test' to the element inserted again before subject_child
Pass remove the class 'test' from the element inserted again before subject_child
Pass remove element div before subject_child
Pass insert element div[test_attr] before subject_child
Pass remove element div[test_attr] before subject_child
Pass insert element div.test before subject_descendant
Pass remove the class 'test' from the element inserted before subject_descendant
Pass add the class 'test' again to the element inserted before subject_descendant
Pass remove element div.test before subject_descendant
Pass insert element div before subject_descendant
Pass add the class 'test' to the element inserted again before subject_descendant
Pass remove the class 'test' from the element inserted again before subject_descendant
Pass remove element div before subject_descendant
Pass insert element div[test_attr] before subject_descendant
Pass remove element div[test_attr] before subject_descendant
Pass insert element div.test before next_sibling
Pass remove the class 'test' from the element inserted before next_sibling
Pass add the class 'test' again to the element inserted before next_sibling
Pass remove element div.test before next_sibling
Pass insert element div before next_sibling
Pass add the class 'test' to the element inserted again before next_sibling
Pass remove the class 'test' from the element inserted again before next_sibling
Pass remove element div before next_sibling
Pass insert element div[test_attr] before next_sibling
Pass remove element div[test_attr] before next_sibling
Pass insert element div.test before next_sibling_child
Pass remove the class 'test' from the element inserted before next_sibling_child
Pass add the class 'test' again to the element inserted before next_sibling_child
Pass remove element div.test before next_sibling_child
Pass insert element div before next_sibling_child
Pass add the class 'test' to the element inserted again before next_sibling_child
Pass remove the class 'test' from the element inserted again before next_sibling_child
Pass remove element div before next_sibling_child
Pass insert element div[test_attr] before next_sibling_child
Pass remove element div[test_attr] before next_sibling_child
Pass insert element div.test before next_sibling_descendant
Pass remove the class 'test' from the element inserted before next_sibling_descendant
Pass add the class 'test' again to the element inserted before next_sibling_descendant
Pass remove element div.test before next_sibling_descendant
Pass insert element div before next_sibling_descendant
Pass add the class 'test' to the element inserted again before next_sibling_descendant
Pass remove the class 'test' from the element inserted again before next_sibling_descendant
Pass remove element div before next_sibling_descendant
Pass insert element div[test_attr] before next_sibling_descendant
Pass remove element div[test_attr] before next_sibling_descendant
Pass insert element div.test after subject_ancestor
Pass remove the class 'test' from the element inserted after subject_ancestor
Pass add the class 'test' again to the element inserted after subject_ancestor
Pass remove element div.test after subject_ancestor
Pass insert element div after subject_ancestor
Pass add the class 'test' to the element inserted again after subject_ancestor
Pass remove the class 'test' from the element inserted again after subject_ancestor
Pass remove element div after subject_ancestor
Pass insert element div[test_attr] after subject_ancestor
Pass remove element div[test_attr] after subject_ancestor
Pass insert element div.test after subject_parent
Pass remove the class 'test' from the element inserted after subject_parent
Pass add the class 'test' again to the element inserted after subject_parent
Pass remove element div.test after subject_parent
Pass insert element div after subject_parent
Pass add the class 'test' to the element inserted again after subject_parent
Pass remove the class 'test' from the element inserted again after subject_parent
Pass remove element div after subject_parent
Pass insert element div[test_attr] after subject_parent
Pass remove element div[test_attr] after subject_parent
Pass insert element div.test after subject
Pass remove the class 'test' from the element inserted after subject
Pass add the class 'test' again to the element inserted after subject
Pass remove element div.test after subject
Pass insert element div after subject
Pass add the class 'test' to the element inserted again after subject
Pass remove the class 'test' from the element inserted again after subject
Pass remove element div after subject
Pass insert element div[test_attr] after subject
Pass remove element div[test_attr] after subject
Pass insert element div.test after subject_child
Pass remove the class 'test' from the element inserted after subject_child
Pass add the class 'test' again to the element inserted after subject_child
Pass remove element div.test after subject_child
Pass insert element div after subject_child
Pass add the class 'test' to the element inserted again after subject_child
Pass remove the class 'test' from the element inserted again after subject_child
Pass remove element div after subject_child
Pass insert element div[test_attr] after subject_child
Pass remove element div[test_attr] after subject_child
Pass insert element div.test after subject_descendant
Pass remove the class 'test' from the element inserted after subject_descendant
Pass add the class 'test' again to the element inserted after subject_descendant
Pass remove element div.test after subject_descendant
Pass insert element div after subject_descendant
Pass add the class 'test' to the element inserted again after subject_descendant
Pass remove the class 'test' from the element inserted again after subject_descendant
Pass remove element div after subject_descendant
Pass insert element div[test_attr] after subject_descendant
Pass remove element div[test_attr] after subject_descendant
Pass insert element div.test after next_sibling
Pass remove the class 'test' from the element inserted after next_sibling
Pass add the class 'test' again to the element inserted after next_sibling
Pass remove element div.test after next_sibling
Pass insert element div after next_sibling
Pass add the class 'test' to the element inserted again after next_sibling
Pass remove the class 'test' from the element inserted again after next_sibling
Pass remove element div after next_sibling
Pass insert element div[test_attr] after next_sibling
Pass remove element div[test_attr] after next_sibling
Pass insert element div.test after next_sibling_child
Pass remove the class 'test' from the element inserted after next_sibling_child
Pass add the class 'test' again to the element inserted after next_sibling_child
Pass remove element div.test after next_sibling_child
Pass insert element div after next_sibling_child
Pass add the class 'test' to the element inserted again after next_sibling_child
Pass remove the class 'test' from the element inserted again after next_sibling_child
Pass remove element div after next_sibling_child
Pass insert element div[test_attr] after next_sibling_child
Pass remove element div[test_attr] after next_sibling_child
Pass insert element div.test after next_sibling_descendant
Pass remove the class 'test' from the element inserted after next_sibling_descendant
Pass add the class 'test' again to the element inserted after next_sibling_descendant
Pass remove element div.test after next_sibling_descendant
Pass insert element div after next_sibling_descendant
Pass add the class 'test' to the element inserted again after next_sibling_descendant
Pass remove the class 'test' from the element inserted again after next_sibling_descendant
Pass remove element div after next_sibling_descendant
Pass insert element div[test_attr] after next_sibling_descendant
Pass remove element div[test_attr] after next_sibling_descendant
Pass insert tree div>div.test before subject_ancestor
Pass remove the class 'test' from the element in the tree inserted before subject_ancestor
Pass add the class 'test' again to the element in the tree inserted before subject_ancestor
Pass remove tree div>div.test before subject_ancestor
Pass insert tree div>div before subject_ancestor
Pass add the class 'test' to the element in the tree inserted again before subject_ancestor
Pass remove the class 'test' from the element in the tree inserted again before subject_ancestor
Pass remove tree div>div before subject_ancestor
Pass insert element div>div[test_attr] before subject_ancestor
Pass remove element div>div[test_attr] before subject_ancestor
Pass insert tree div>div.test before subject_parent
Pass remove the class 'test' from the element in the tree inserted before subject_parent
Pass add the class 'test' again to the element in the tree inserted before subject_parent
Pass remove tree div>div.test before subject_parent
Pass insert tree div>div before subject_parent
Pass add the class 'test' to the element in the tree inserted again before subject_parent
Pass remove the class 'test' from the element in the tree inserted again before subject_parent
Pass remove tree div>div before subject_parent
Pass insert element div>div[test_attr] before subject_parent
Pass remove element div>div[test_attr] before subject_parent
Pass insert tree div>div.test before subject
Pass remove the class 'test' from the element in the tree inserted before subject
Pass add the class 'test' again to the element in the tree inserted before subject
Pass remove tree div>div.test before subject
Pass insert tree div>div before subject
Pass add the class 'test' to the element in the tree inserted again before subject
Pass remove the class 'test' from the element in the tree inserted again before subject
Pass remove tree div>div before subject
Pass insert element div>div[test_attr] before subject
Pass remove element div>div[test_attr] before subject
Pass insert tree div>div.test before subject_child
Pass remove the class 'test' from the element in the tree inserted before subject_child
Pass add the class 'test' again to the element in the tree inserted before subject_child
Pass remove tree div>div.test before subject_child
Pass insert tree div>div before subject_child
Pass add the class 'test' to the element in the tree inserted again before subject_child
Pass remove the class 'test' from the element in the tree inserted again before subject_child
Pass remove tree div>div before subject_child
Pass insert element div>div[test_attr] before subject_child
Pass remove element div>div[test_attr] before subject_child
Pass insert tree div>div.test before subject_descendant
Pass remove the class 'test' from the element in the tree inserted before subject_descendant
Pass add the class 'test' again to the element in the tree inserted before subject_descendant
Pass remove tree div>div.test before subject_descendant
Pass insert tree div>div before subject_descendant
Pass add the class 'test' to the element in the tree inserted again before subject_descendant
Pass remove the class 'test' from the element in the tree inserted again before subject_descendant
Pass remove tree div>div before subject_descendant
Pass insert element div>div[test_attr] before subject_descendant
Pass remove element div>div[test_attr] before subject_descendant
Pass insert tree div>div.test before next_sibling
Pass remove the class 'test' from the element in the tree inserted before next_sibling
Pass add the class 'test' again to the element in the tree inserted before next_sibling
Pass remove tree div>div.test before next_sibling
Pass insert tree div>div before next_sibling
Pass add the class 'test' to the element in the tree inserted again before next_sibling
Pass remove the class 'test' from the element in the tree inserted again before next_sibling
Pass remove tree div>div before next_sibling
Pass insert element div>div[test_attr] before next_sibling
Pass remove element div>div[test_attr] before next_sibling
Pass insert tree div>div.test before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted before next_sibling_child
Pass add the class 'test' again to the element in the tree inserted before next_sibling_child
Pass remove tree div>div.test before next_sibling_child
Pass insert tree div>div before next_sibling_child
Pass add the class 'test' to the element in the tree inserted again before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_child
Pass remove tree div>div before next_sibling_child
Pass insert element div>div[test_attr] before next_sibling_child
Pass remove element div>div[test_attr] before next_sibling_child
Pass insert tree div>div.test before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted before next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted before next_sibling_descendant
Pass remove tree div>div.test before next_sibling_descendant
Pass insert tree div>div before next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_descendant
Pass remove tree div>div before next_sibling_descendant
Pass insert element div>div[test_attr] before next_sibling_descendant
Pass remove element div>div[test_attr] before next_sibling_descendant
Pass insert tree div>div.test after subject_ancestor
Pass remove the class 'test' from the element in the tree inserted after subject_ancestor
Pass add the class 'test' again to the element in the tree inserted after subject_ancestor
Pass remove tree div>div.test after subject_ancestor
Pass insert tree div>div after subject_ancestor
Pass add the class 'test' to the element in the tree inserted again after subject_ancestor
Pass remove the class 'test' from the element in the tree inserted again after subject_ancestor
Pass remove tree div>div after subject_ancestor
Pass insert element div>div[test_attr] after subject_ancestor
Pass remove element div>div[test_attr] after subject_ancestor
Pass insert tree div>div.test after subject_parent
Pass remove the class 'test' from the element in the tree inserted after subject_parent
Pass add the class 'test' again to the element in the tree inserted after subject_parent
Pass remove tree div>div.test after subject_parent
Pass insert tree div>div after subject_parent
Pass add the class 'test' to the element in the tree inserted again after subject_parent
Pass remove the class 'test' from the element in the tree inserted again after subject_parent
Pass remove tree div>div after subject_parent
Pass insert element div>div[test_attr] after subject_parent
Pass remove element div>div[test_attr] after subject_parent
Pass insert tree div>div.test after subject
Pass remove the class 'test' from the element in the tree inserted after subject
Pass add the class 'test' again to the element in the tree inserted after subject
Pass remove tree div>div.test after subject
Pass insert tree div>div after subject
Pass add the class 'test' to the element in the tree inserted again after subject
Pass remove the class 'test' from the element in the tree inserted again after subject
Pass remove tree div>div after subject
Pass insert element div>div[test_attr] after subject
Pass remove element div>div[test_attr] after subject
Pass insert tree div>div.test after subject_child
Pass remove the class 'test' from the element in the tree inserted after subject_child
Pass add the class 'test' again to the element in the tree inserted after subject_child
Pass remove tree div>div.test after subject_child
Pass insert tree div>div after subject_child
Pass add the class 'test' to the element in the tree inserted again after subject_child
Pass remove the class 'test' from the element in the tree inserted again after subject_child
Pass remove tree div>div after subject_child
Pass insert element div>div[test_attr] after subject_child
Pass remove element div>div[test_attr] after subject_child
Pass insert tree div>div.test after subject_descendant
Pass remove the class 'test' from the element in the tree inserted after subject_descendant
Pass add the class 'test' again to the element in the tree inserted after subject_descendant
Pass remove tree div>div.test after subject_descendant
Pass insert tree div>div after subject_descendant
Pass add the class 'test' to the element in the tree inserted again after subject_descendant
Pass remove the class 'test' from the element in the tree inserted again after subject_descendant
Pass remove tree div>div after subject_descendant
Pass insert element div>div[test_attr] after subject_descendant
Pass remove element div>div[test_attr] after subject_descendant
Pass insert tree div>div.test after next_sibling
Pass remove the class 'test' from the element in the tree inserted after next_sibling
Pass add the class 'test' again to the element in the tree inserted after next_sibling
Pass remove tree div>div.test after next_sibling
Pass insert tree div>div after next_sibling
Pass add the class 'test' to the element in the tree inserted again after next_sibling
Pass remove the class 'test' from the element in the tree inserted again after next_sibling
Pass remove tree div>div after next_sibling
Pass insert element div>div[test_attr] after next_sibling
Pass remove element div>div[test_attr] after next_sibling
Pass insert tree div>div.test after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted after next_sibling_child
Pass add the class 'test' again to the element in the tree inserted after next_sibling_child
Pass remove tree div>div.test after next_sibling_child
Pass insert tree div>div after next_sibling_child
Pass add the class 'test' to the element in the tree inserted again after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_child
Pass remove tree div>div after next_sibling_child
Pass insert element div>div[test_attr] after next_sibling_child
Pass remove element div>div[test_attr] after next_sibling_child
Pass insert tree div>div.test after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted after next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted after next_sibling_descendant
Pass remove tree div>div.test after next_sibling_descendant
Pass insert tree div>div after next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_descendant
Pass remove tree div>div after next_sibling_descendant
Pass insert element div>div[test_attr] after next_sibling_descendant
Pass remove element div>div[test_attr] after next_sibling_descendant

View file

@ -0,0 +1,221 @@
Summary
Harness status: OK
Rerun
Found 211 tests
211 Pass
Details
Result Test Name MessagePass Initial color
Pass add .test to subject_ancestor
Pass remove .test from subject_ancestor
Pass add .test to subject_parent
Pass remove .test from subject_parent
Pass add .test to subject
Pass remove .test from subject
Pass add .test to subject_child
Pass remove .test from subject_child
Pass add .test to subject_descendant
Pass remove .test from subject_descendant
Pass insert element div.test before subject_ancestor
Pass remove the class 'test' from the element inserted before subject_ancestor
Pass add the class 'test' again to the element inserted before subject_ancestor
Pass remove element div.test before subject_ancestor
Pass insert element div before subject_ancestor
Pass add the class 'test' to the element inserted again before subject_ancestor
Pass remove the class 'test' from the element inserted again before subject_ancestor
Pass remove element div before subject_ancestor
Pass insert element div[test_attr] before subject_ancestor
Pass remove element div[test_attr] before subject_ancestor
Pass insert element div.test before subject_parent
Pass remove the class 'test' from the element inserted before subject_parent
Pass add the class 'test' again to the element inserted before subject_parent
Pass remove element div.test before subject_parent
Pass insert element div before subject_parent
Pass add the class 'test' to the element inserted again before subject_parent
Pass remove the class 'test' from the element inserted again before subject_parent
Pass remove element div before subject_parent
Pass insert element div[test_attr] before subject_parent
Pass remove element div[test_attr] before subject_parent
Pass insert element div.test before subject
Pass remove the class 'test' from the element inserted before subject
Pass add the class 'test' again to the element inserted before subject
Pass remove element div.test before subject
Pass insert element div before subject
Pass add the class 'test' to the element inserted again before subject
Pass remove the class 'test' from the element inserted again before subject
Pass remove element div before subject
Pass insert element div[test_attr] before subject
Pass remove element div[test_attr] before subject
Pass insert element div.test before subject_child
Pass remove the class 'test' from the element inserted before subject_child
Pass add the class 'test' again to the element inserted before subject_child
Pass remove element div.test before subject_child
Pass insert element div before subject_child
Pass add the class 'test' to the element inserted again before subject_child
Pass remove the class 'test' from the element inserted again before subject_child
Pass remove element div before subject_child
Pass insert element div[test_attr] before subject_child
Pass remove element div[test_attr] before subject_child
Pass insert element div.test before subject_descendant
Pass remove the class 'test' from the element inserted before subject_descendant
Pass add the class 'test' again to the element inserted before subject_descendant
Pass remove element div.test before subject_descendant
Pass insert element div before subject_descendant
Pass add the class 'test' to the element inserted again before subject_descendant
Pass remove the class 'test' from the element inserted again before subject_descendant
Pass remove element div before subject_descendant
Pass insert element div[test_attr] before subject_descendant
Pass remove element div[test_attr] before subject_descendant
Pass insert element div.test after subject_ancestor
Pass remove the class 'test' from the element inserted after subject_ancestor
Pass add the class 'test' again to the element inserted after subject_ancestor
Pass remove element div.test after subject_ancestor
Pass insert element div after subject_ancestor
Pass add the class 'test' to the element inserted again after subject_ancestor
Pass remove the class 'test' from the element inserted again after subject_ancestor
Pass remove element div after subject_ancestor
Pass insert element div[test_attr] after subject_ancestor
Pass remove element div[test_attr] after subject_ancestor
Pass insert element div.test after subject_parent
Pass remove the class 'test' from the element inserted after subject_parent
Pass add the class 'test' again to the element inserted after subject_parent
Pass remove element div.test after subject_parent
Pass insert element div after subject_parent
Pass add the class 'test' to the element inserted again after subject_parent
Pass remove the class 'test' from the element inserted again after subject_parent
Pass remove element div after subject_parent
Pass insert element div[test_attr] after subject_parent
Pass remove element div[test_attr] after subject_parent
Pass insert element div.test after subject
Pass remove the class 'test' from the element inserted after subject
Pass add the class 'test' again to the element inserted after subject
Pass remove element div.test after subject
Pass insert element div after subject
Pass add the class 'test' to the element inserted again after subject
Pass remove the class 'test' from the element inserted again after subject
Pass remove element div after subject
Pass insert element div[test_attr] after subject
Pass remove element div[test_attr] after subject
Pass insert element div.test after subject_child
Pass remove the class 'test' from the element inserted after subject_child
Pass add the class 'test' again to the element inserted after subject_child
Pass remove element div.test after subject_child
Pass insert element div after subject_child
Pass add the class 'test' to the element inserted again after subject_child
Pass remove the class 'test' from the element inserted again after subject_child
Pass remove element div after subject_child
Pass insert element div[test_attr] after subject_child
Pass remove element div[test_attr] after subject_child
Pass insert element div.test after subject_descendant
Pass remove the class 'test' from the element inserted after subject_descendant
Pass add the class 'test' again to the element inserted after subject_descendant
Pass remove element div.test after subject_descendant
Pass insert element div after subject_descendant
Pass add the class 'test' to the element inserted again after subject_descendant
Pass remove the class 'test' from the element inserted again after subject_descendant
Pass remove element div after subject_descendant
Pass insert element div[test_attr] after subject_descendant
Pass remove element div[test_attr] after subject_descendant
Pass insert tree div>div.test before subject_ancestor
Pass remove the class 'test' from the element in the tree inserted before subject_ancestor
Pass add the class 'test' again to the element in the tree inserted before subject_ancestor
Pass remove tree div>div.test before subject_ancestor
Pass insert tree div>div before subject_ancestor
Pass add the class 'test' to the element in the tree inserted again before subject_ancestor
Pass remove the class 'test' from the element in the tree inserted again before subject_ancestor
Pass remove tree div>div before subject_ancestor
Pass insert element div>div[test_attr] before subject_ancestor
Pass remove element div>div[test_attr] before subject_ancestor
Pass insert tree div>div.test before subject_parent
Pass remove the class 'test' from the element in the tree inserted before subject_parent
Pass add the class 'test' again to the element in the tree inserted before subject_parent
Pass remove tree div>div.test before subject_parent
Pass insert tree div>div before subject_parent
Pass add the class 'test' to the element in the tree inserted again before subject_parent
Pass remove the class 'test' from the element in the tree inserted again before subject_parent
Pass remove tree div>div before subject_parent
Pass insert element div>div[test_attr] before subject_parent
Pass remove element div>div[test_attr] before subject_parent
Pass insert tree div>div.test before subject
Pass remove the class 'test' from the element in the tree inserted before subject
Pass add the class 'test' again to the element in the tree inserted before subject
Pass remove tree div>div.test before subject
Pass insert tree div>div before subject
Pass add the class 'test' to the element in the tree inserted again before subject
Pass remove the class 'test' from the element in the tree inserted again before subject
Pass remove tree div>div before subject
Pass insert element div>div[test_attr] before subject
Pass remove element div>div[test_attr] before subject
Pass insert tree div>div.test before subject_child
Pass remove the class 'test' from the element in the tree inserted before subject_child
Pass add the class 'test' again to the element in the tree inserted before subject_child
Pass remove tree div>div.test before subject_child
Pass insert tree div>div before subject_child
Pass add the class 'test' to the element in the tree inserted again before subject_child
Pass remove the class 'test' from the element in the tree inserted again before subject_child
Pass remove tree div>div before subject_child
Pass insert element div>div[test_attr] before subject_child
Pass remove element div>div[test_attr] before subject_child
Pass insert tree div>div.test before subject_descendant
Pass remove the class 'test' from the element in the tree inserted before subject_descendant
Pass add the class 'test' again to the element in the tree inserted before subject_descendant
Pass remove tree div>div.test before subject_descendant
Pass insert tree div>div before subject_descendant
Pass add the class 'test' to the element in the tree inserted again before subject_descendant
Pass remove the class 'test' from the element in the tree inserted again before subject_descendant
Pass remove tree div>div before subject_descendant
Pass insert element div>div[test_attr] before subject_descendant
Pass remove element div>div[test_attr] before subject_descendant
Pass insert tree div>div.test after subject_ancestor
Pass remove the class 'test' from the element in the tree inserted after subject_ancestor
Pass add the class 'test' again to the element in the tree inserted after subject_ancestor
Pass remove tree div>div.test after subject_ancestor
Pass insert tree div>div after subject_ancestor
Pass add the class 'test' to the element in the tree inserted again after subject_ancestor
Pass remove the class 'test' from the element in the tree inserted again after subject_ancestor
Pass remove tree div>div after subject_ancestor
Pass insert element div>div[test_attr] after subject_ancestor
Pass remove element div>div[test_attr] after subject_ancestor
Pass insert tree div>div.test after subject_parent
Pass remove the class 'test' from the element in the tree inserted after subject_parent
Pass add the class 'test' again to the element in the tree inserted after subject_parent
Pass remove tree div>div.test after subject_parent
Pass insert tree div>div after subject_parent
Pass add the class 'test' to the element in the tree inserted again after subject_parent
Pass remove the class 'test' from the element in the tree inserted again after subject_parent
Pass remove tree div>div after subject_parent
Pass insert element div>div[test_attr] after subject_parent
Pass remove element div>div[test_attr] after subject_parent
Pass insert tree div>div.test after subject
Pass remove the class 'test' from the element in the tree inserted after subject
Pass add the class 'test' again to the element in the tree inserted after subject
Pass remove tree div>div.test after subject
Pass insert tree div>div after subject
Pass add the class 'test' to the element in the tree inserted again after subject
Pass remove the class 'test' from the element in the tree inserted again after subject
Pass remove tree div>div after subject
Pass insert element div>div[test_attr] after subject
Pass remove element div>div[test_attr] after subject
Pass insert tree div>div.test after subject_child
Pass remove the class 'test' from the element in the tree inserted after subject_child
Pass add the class 'test' again to the element in the tree inserted after subject_child
Pass remove tree div>div.test after subject_child
Pass insert tree div>div after subject_child
Pass add the class 'test' to the element in the tree inserted again after subject_child
Pass remove the class 'test' from the element in the tree inserted again after subject_child
Pass remove tree div>div after subject_child
Pass insert element div>div[test_attr] after subject_child
Pass remove element div>div[test_attr] after subject_child
Pass insert tree div>div.test after subject_descendant
Pass remove the class 'test' from the element in the tree inserted after subject_descendant
Pass add the class 'test' again to the element in the tree inserted after subject_descendant
Pass remove tree div>div.test after subject_descendant
Pass insert tree div>div after subject_descendant
Pass add the class 'test' to the element in the tree inserted again after subject_descendant
Pass remove the class 'test' from the element in the tree inserted again after subject_descendant
Pass remove tree div>div after subject_descendant
Pass insert element div>div[test_attr] after subject_descendant
Pass remove element div>div[test_attr] after subject_descendant

View file

@ -0,0 +1,305 @@
Summary
Harness status: OK
Rerun
Found 295 tests
295 Pass
Details
Result Test Name MessagePass Initial color
Pass add .test to previous_sibling
Pass remove .test from previous_sibling
Pass add .test to previous_sibling_child
Pass remove .test from previous_sibling_child
Pass add .test to previous_sibling_descendant
Pass remove .test from previous_sibling_descendant
Pass add .test to subject
Pass remove .test from subject
Pass add .test to next_sibling
Pass remove .test from next_sibling
Pass add .test to next_sibling_child
Pass remove .test from next_sibling_child
Pass add .test to next_sibling_descendant
Pass remove .test from next_sibling_descendant
Pass insert element div.test before previous_sibling
Pass remove the class 'test' from the element inserted before previous_sibling
Pass add the class 'test' again to the element inserted before previous_sibling
Pass remove element div.test before previous_sibling
Pass insert element div before previous_sibling
Pass add the class 'test' to the element inserted again before previous_sibling
Pass remove the class 'test' from the element inserted again before previous_sibling
Pass remove element div before previous_sibling
Pass insert element div[test_attr] before previous_sibling
Pass remove element div[test_attr] before previous_sibling
Pass insert element div.test before previous_sibling_child
Pass remove the class 'test' from the element inserted before previous_sibling_child
Pass add the class 'test' again to the element inserted before previous_sibling_child
Pass remove element div.test before previous_sibling_child
Pass insert element div before previous_sibling_child
Pass add the class 'test' to the element inserted again before previous_sibling_child
Pass remove the class 'test' from the element inserted again before previous_sibling_child
Pass remove element div before previous_sibling_child
Pass insert element div[test_attr] before previous_sibling_child
Pass remove element div[test_attr] before previous_sibling_child
Pass insert element div.test before previous_sibling_descendant
Pass remove the class 'test' from the element inserted before previous_sibling_descendant
Pass add the class 'test' again to the element inserted before previous_sibling_descendant
Pass remove element div.test before previous_sibling_descendant
Pass insert element div before previous_sibling_descendant
Pass add the class 'test' to the element inserted again before previous_sibling_descendant
Pass remove the class 'test' from the element inserted again before previous_sibling_descendant
Pass remove element div before previous_sibling_descendant
Pass insert element div[test_attr] before previous_sibling_descendant
Pass remove element div[test_attr] before previous_sibling_descendant
Pass insert element div.test before subject
Pass remove the class 'test' from the element inserted before subject
Pass add the class 'test' again to the element inserted before subject
Pass remove element div.test before subject
Pass insert element div before subject
Pass add the class 'test' to the element inserted again before subject
Pass remove the class 'test' from the element inserted again before subject
Pass remove element div before subject
Pass insert element div[test_attr] before subject
Pass remove element div[test_attr] before subject
Pass insert element div.test before next_sibling
Pass remove the class 'test' from the element inserted before next_sibling
Pass add the class 'test' again to the element inserted before next_sibling
Pass remove element div.test before next_sibling
Pass insert element div before next_sibling
Pass add the class 'test' to the element inserted again before next_sibling
Pass remove the class 'test' from the element inserted again before next_sibling
Pass remove element div before next_sibling
Pass insert element div[test_attr] before next_sibling
Pass remove element div[test_attr] before next_sibling
Pass insert element div.test before next_sibling_child
Pass remove the class 'test' from the element inserted before next_sibling_child
Pass add the class 'test' again to the element inserted before next_sibling_child
Pass remove element div.test before next_sibling_child
Pass insert element div before next_sibling_child
Pass add the class 'test' to the element inserted again before next_sibling_child
Pass remove the class 'test' from the element inserted again before next_sibling_child
Pass remove element div before next_sibling_child
Pass insert element div[test_attr] before next_sibling_child
Pass remove element div[test_attr] before next_sibling_child
Pass insert element div.test before next_sibling_descendant
Pass remove the class 'test' from the element inserted before next_sibling_descendant
Pass add the class 'test' again to the element inserted before next_sibling_descendant
Pass remove element div.test before next_sibling_descendant
Pass insert element div before next_sibling_descendant
Pass add the class 'test' to the element inserted again before next_sibling_descendant
Pass remove the class 'test' from the element inserted again before next_sibling_descendant
Pass remove element div before next_sibling_descendant
Pass insert element div[test_attr] before next_sibling_descendant
Pass remove element div[test_attr] before next_sibling_descendant
Pass insert element div.test after previous_sibling
Pass remove the class 'test' from the element inserted after previous_sibling
Pass add the class 'test' again to the element inserted after previous_sibling
Pass remove element div.test after previous_sibling
Pass insert element div after previous_sibling
Pass add the class 'test' to the element inserted again after previous_sibling
Pass remove the class 'test' from the element inserted again after previous_sibling
Pass remove element div after previous_sibling
Pass insert element div[test_attr] after previous_sibling
Pass remove element div[test_attr] after previous_sibling
Pass insert element div.test after previous_sibling_child
Pass remove the class 'test' from the element inserted after previous_sibling_child
Pass add the class 'test' again to the element inserted after previous_sibling_child
Pass remove element div.test after previous_sibling_child
Pass insert element div after previous_sibling_child
Pass add the class 'test' to the element inserted again after previous_sibling_child
Pass remove the class 'test' from the element inserted again after previous_sibling_child
Pass remove element div after previous_sibling_child
Pass insert element div[test_attr] after previous_sibling_child
Pass remove element div[test_attr] after previous_sibling_child
Pass insert element div.test after previous_sibling_descendant
Pass remove the class 'test' from the element inserted after previous_sibling_descendant
Pass add the class 'test' again to the element inserted after previous_sibling_descendant
Pass remove element div.test after previous_sibling_descendant
Pass insert element div after previous_sibling_descendant
Pass add the class 'test' to the element inserted again after previous_sibling_descendant
Pass remove the class 'test' from the element inserted again after previous_sibling_descendant
Pass remove element div after previous_sibling_descendant
Pass insert element div[test_attr] after previous_sibling_descendant
Pass remove element div[test_attr] after previous_sibling_descendant
Pass insert element div.test after subject
Pass remove the class 'test' from the element inserted after subject
Pass add the class 'test' again to the element inserted after subject
Pass remove element div.test after subject
Pass insert element div after subject
Pass add the class 'test' to the element inserted again after subject
Pass remove the class 'test' from the element inserted again after subject
Pass remove element div after subject
Pass insert element div[test_attr] after subject
Pass remove element div[test_attr] after subject
Pass insert element div.test after next_sibling
Pass remove the class 'test' from the element inserted after next_sibling
Pass add the class 'test' again to the element inserted after next_sibling
Pass remove element div.test after next_sibling
Pass insert element div after next_sibling
Pass add the class 'test' to the element inserted again after next_sibling
Pass remove the class 'test' from the element inserted again after next_sibling
Pass remove element div after next_sibling
Pass insert element div[test_attr] after next_sibling
Pass remove element div[test_attr] after next_sibling
Pass insert element div.test after next_sibling_child
Pass remove the class 'test' from the element inserted after next_sibling_child
Pass add the class 'test' again to the element inserted after next_sibling_child
Pass remove element div.test after next_sibling_child
Pass insert element div after next_sibling_child
Pass add the class 'test' to the element inserted again after next_sibling_child
Pass remove the class 'test' from the element inserted again after next_sibling_child
Pass remove element div after next_sibling_child
Pass insert element div[test_attr] after next_sibling_child
Pass remove element div[test_attr] after next_sibling_child
Pass insert element div.test after next_sibling_descendant
Pass remove the class 'test' from the element inserted after next_sibling_descendant
Pass add the class 'test' again to the element inserted after next_sibling_descendant
Pass remove element div.test after next_sibling_descendant
Pass insert element div after next_sibling_descendant
Pass add the class 'test' to the element inserted again after next_sibling_descendant
Pass remove the class 'test' from the element inserted again after next_sibling_descendant
Pass remove element div after next_sibling_descendant
Pass insert element div[test_attr] after next_sibling_descendant
Pass remove element div[test_attr] after next_sibling_descendant
Pass insert tree div>div.test before previous_sibling
Pass remove the class 'test' from the element in the tree inserted before previous_sibling
Pass add the class 'test' again to the element in the tree inserted before previous_sibling
Pass remove tree div>div.test before previous_sibling
Pass insert tree div>div before previous_sibling
Pass add the class 'test' to the element in the tree inserted again before previous_sibling
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling
Pass remove tree div>div before previous_sibling
Pass insert element div>div[test_attr] before previous_sibling
Pass remove element div>div[test_attr] before previous_sibling
Pass insert tree div>div.test before previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted before previous_sibling_child
Pass add the class 'test' again to the element in the tree inserted before previous_sibling_child
Pass remove tree div>div.test before previous_sibling_child
Pass insert tree div>div before previous_sibling_child
Pass add the class 'test' to the element in the tree inserted again before previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling_child
Pass remove tree div>div before previous_sibling_child
Pass insert element div>div[test_attr] before previous_sibling_child
Pass remove element div>div[test_attr] before previous_sibling_child
Pass insert tree div>div.test before previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted before previous_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted before previous_sibling_descendant
Pass remove tree div>div.test before previous_sibling_descendant
Pass insert tree div>div before previous_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again before previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again before previous_sibling_descendant
Pass remove tree div>div before previous_sibling_descendant
Pass insert element div>div[test_attr] before previous_sibling_descendant
Pass remove element div>div[test_attr] before previous_sibling_descendant
Pass insert tree div>div.test before subject
Pass remove the class 'test' from the element in the tree inserted before subject
Pass add the class 'test' again to the element in the tree inserted before subject
Pass remove tree div>div.test before subject
Pass insert tree div>div before subject
Pass add the class 'test' to the element in the tree inserted again before subject
Pass remove the class 'test' from the element in the tree inserted again before subject
Pass remove tree div>div before subject
Pass insert element div>div[test_attr] before subject
Pass remove element div>div[test_attr] before subject
Pass insert tree div>div.test before next_sibling
Pass remove the class 'test' from the element in the tree inserted before next_sibling
Pass add the class 'test' again to the element in the tree inserted before next_sibling
Pass remove tree div>div.test before next_sibling
Pass insert tree div>div before next_sibling
Pass add the class 'test' to the element in the tree inserted again before next_sibling
Pass remove the class 'test' from the element in the tree inserted again before next_sibling
Pass remove tree div>div before next_sibling
Pass insert element div>div[test_attr] before next_sibling
Pass remove element div>div[test_attr] before next_sibling
Pass insert tree div>div.test before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted before next_sibling_child
Pass add the class 'test' again to the element in the tree inserted before next_sibling_child
Pass remove tree div>div.test before next_sibling_child
Pass insert tree div>div before next_sibling_child
Pass add the class 'test' to the element in the tree inserted again before next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_child
Pass remove tree div>div before next_sibling_child
Pass insert element div>div[test_attr] before next_sibling_child
Pass remove element div>div[test_attr] before next_sibling_child
Pass insert tree div>div.test before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted before next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted before next_sibling_descendant
Pass remove tree div>div.test before next_sibling_descendant
Pass insert tree div>div before next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again before next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again before next_sibling_descendant
Pass remove tree div>div before next_sibling_descendant
Pass insert element div>div[test_attr] before next_sibling_descendant
Pass remove element div>div[test_attr] before next_sibling_descendant
Pass insert tree div>div.test after previous_sibling
Pass remove the class 'test' from the element in the tree inserted after previous_sibling
Pass add the class 'test' again to the element in the tree inserted after previous_sibling
Pass remove tree div>div.test after previous_sibling
Pass insert tree div>div after previous_sibling
Pass add the class 'test' to the element in the tree inserted again after previous_sibling
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling
Pass remove tree div>div after previous_sibling
Pass insert element div>div[test_attr] after previous_sibling
Pass remove element div>div[test_attr] after previous_sibling
Pass insert tree div>div.test after previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted after previous_sibling_child
Pass add the class 'test' again to the element in the tree inserted after previous_sibling_child
Pass remove tree div>div.test after previous_sibling_child
Pass insert tree div>div after previous_sibling_child
Pass add the class 'test' to the element in the tree inserted again after previous_sibling_child
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling_child
Pass remove tree div>div after previous_sibling_child
Pass insert element div>div[test_attr] after previous_sibling_child
Pass remove element div>div[test_attr] after previous_sibling_child
Pass insert tree div>div.test after previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted after previous_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted after previous_sibling_descendant
Pass remove tree div>div.test after previous_sibling_descendant
Pass insert tree div>div after previous_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again after previous_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again after previous_sibling_descendant
Pass remove tree div>div after previous_sibling_descendant
Pass insert element div>div[test_attr] after previous_sibling_descendant
Pass remove element div>div[test_attr] after previous_sibling_descendant
Pass insert tree div>div.test after subject
Pass remove the class 'test' from the element in the tree inserted after subject
Pass add the class 'test' again to the element in the tree inserted after subject
Pass remove tree div>div.test after subject
Pass insert tree div>div after subject
Pass add the class 'test' to the element in the tree inserted again after subject
Pass remove the class 'test' from the element in the tree inserted again after subject
Pass remove tree div>div after subject
Pass insert element div>div[test_attr] after subject
Pass remove element div>div[test_attr] after subject
Pass insert tree div>div.test after next_sibling
Pass remove the class 'test' from the element in the tree inserted after next_sibling
Pass add the class 'test' again to the element in the tree inserted after next_sibling
Pass remove tree div>div.test after next_sibling
Pass insert tree div>div after next_sibling
Pass add the class 'test' to the element in the tree inserted again after next_sibling
Pass remove the class 'test' from the element in the tree inserted again after next_sibling
Pass remove tree div>div after next_sibling
Pass insert element div>div[test_attr] after next_sibling
Pass remove element div>div[test_attr] after next_sibling
Pass insert tree div>div.test after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted after next_sibling_child
Pass add the class 'test' again to the element in the tree inserted after next_sibling_child
Pass remove tree div>div.test after next_sibling_child
Pass insert tree div>div after next_sibling_child
Pass add the class 'test' to the element in the tree inserted again after next_sibling_child
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_child
Pass remove tree div>div after next_sibling_child
Pass insert element div>div[test_attr] after next_sibling_child
Pass remove element div>div[test_attr] after next_sibling_child
Pass insert tree div>div.test after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted after next_sibling_descendant
Pass add the class 'test' again to the element in the tree inserted after next_sibling_descendant
Pass remove tree div>div.test after next_sibling_descendant
Pass insert tree div>div after next_sibling_descendant
Pass add the class 'test' to the element in the tree inserted again after next_sibling_descendant
Pass remove the class 'test' from the element in the tree inserted again after next_sibling_descendant
Pass remove tree div>div after next_sibling_descendant
Pass insert element div>div[test_attr] after next_sibling_descendant
Pass remove element div>div[test_attr] after next_sibling_descendant

View file

@ -0,0 +1,12 @@
Summary
Harness status: OK
Rerun
Found 2 tests
2 Pass
Details
Result Test Name MessagePass initial_color: div#subject.color
Pass remove descendant: div#subject.color

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass initial color: div#subject.color
Pass color after inserting text and div > .descendant: div#subject.color
Pass color after wiping #child to remove div > .descendant: div#subject.color
Pass color after inserting text and #child > .descendant: div#subject.color
Pass color after wiping #child to remove .descendant: div#subject.color

View file

@ -0,0 +1,38 @@
Summary
Harness status: OK
Rerun
Found 28 tests
28 Pass
Details
Result Test Name MessagePass subject1: initial color should be rgb(128, 128, 128)
Pass subject1: color after #sibling1_1 inserted should be rgb(255, 0, 0)
Pass subject2: initial color should be rgb(128, 128, 128)
Pass subject2: color after #sibling2_1 removed should be rgb(0, 128, 0)
Pass subject3: initial color should be rgb(128, 128, 128)
Pass subject3: color after #sibling3_1 inserted should be rgb(0, 0, 255)
Pass subject4: initial color should be rgb(128, 128, 128)
Pass subject4: color after #sibling4_1 removed should be rgb(255, 255, 0)
Pass subject5: initial color should be rgb(255, 0, 0)
Pass subject5: color after #sibling5_1 removed should be rgb(128, 128, 128)
Pass subject6: initial color should be rgb(0, 128, 0)
Pass subject6: color after #sibling6_1 inserted should be rgb(128, 128, 128)
Pass subject7: initial color should be rgb(0, 0, 255)
Pass subject7: color after #sibling7_1 removed should be rgb(128, 128, 128)
Pass subject8: initial color should be rgb(255, 255, 0)
Pass subject8: color after #sibling8_1 inserted should be rgb(128, 128, 128)
Pass subject9: initial color should be rgb(128, 128, 128)
Pass subject9: color after #sibling9_1 inserted should be rgb(255, 0, 0)
Pass subject10: initial color should be rgb(128, 128, 128)
Pass subject10: color after #sibling10_1 removed should be rgb(0, 128, 0)
Pass subject11: initial color should be rgb(128, 128, 128)
Pass subject11: color after #sibling11_1 inserted should be rgb(0, 0, 255)
Pass subject12: initial color should be rgb(128, 128, 128)
Pass subject12: color after #sibling12_1 removed should be rgb(255, 255, 0)
Pass subject13: initial color should be rgb(128, 128, 128)
Pass subject13: color after #sibling12_1 removed should be rgb(0, 128, 0)
Pass subject14: initial color should be rgb(0, 128, 0)
Pass subject14: color after #sibling14_2 removed should be rgb(128, 128, 128)

View file

@ -0,0 +1,81 @@
Summary
Harness status: OK
Rerun
Found 71 tests
71 Pass
Details
Result Test Name MessagePass initial_color
Pass add .test to first_sibling
Pass remove .test from first_sibling
Pass add .test to second_sibling
Pass remove .test from second_sibling
Pass add .test to third_sibling
Pass remove .test from third_sibling
Pass add .test to first_sibling_child
Pass remove .test from first_sibling_child
Pass add .test to first_sibling_descendant
Pass remove .test from first_sibling_descendant
Pass add .test to third_sibling_child
Pass remove .test from third_sibling_child
Pass add .test to third_sibling_descendant
Pass remove .test from third_sibling_descendant
Pass insert element div.test before first_sibling
Pass remove element div.test before first_sibling
Pass insert element div.test before second_sibling
Pass remove element div.test before second_sibling
Pass insert element div.test before third_sibling
Pass remove element div.test before third_sibling
Pass insert element div.test before first_sibling_child
Pass remove element div.test before first_sibling_child
Pass insert element div.test before first_sibling_descendant
Pass remove element div.test before first_sibling_descendant
Pass insert element div.test before third_sibling_child
Pass remove element div.test before third_sibling_child
Pass insert element div.test before third_sibling_descendant
Pass remove element div.test before third_sibling_descendant
Pass insert element div.test after first_sibling
Pass remove element div.test after first_sibling
Pass insert element div.test after second_sibling
Pass remove element div.test after second_sibling
Pass insert element div.test after third_sibling
Pass remove element div.test after third_sibling
Pass insert element div.test after first_sibling_child
Pass remove element div.test after first_sibling_child
Pass insert element div.test after first_sibling_descendant
Pass remove element div.test after first_sibling_descendant
Pass insert element div.test after third_sibling_child
Pass remove element div.test after third_sibling_child
Pass insert element div.test after third_sibling_descendant
Pass remove element div.test after third_sibling_descendant
Pass insert tree div>div.test before first_sibling
Pass remove tree div>div.test before first_sibling
Pass insert tree div>div.test before second_sibling
Pass remove tree div>div.test before second_sibling
Pass insert tree div>div.test before third_sibling
Pass remove tree div>div.test before third_sibling
Pass insert tree div>div.test before first_sibling_child
Pass remove tree div>div.test before first_sibling_child
Pass insert tree div>div.test before first_sibling_descendant
Pass remove tree div>div.test before first_sibling_descendant
Pass insert tree div>div.test before third_sibling_child
Pass remove tree div>div.test before third_sibling_child
Pass insert tree div>div.test before third_sibling_descendant
Pass remove tree div>div.test before third_sibling_descendant
Pass insert tree div>div.test after first_sibling
Pass remove tree div>div.test after first_sibling
Pass insert tree div>div.test after second_sibling
Pass remove tree div>div.test after second_sibling
Pass insert tree div>div.test after third_sibling
Pass remove tree div>div.test after third_sibling
Pass insert tree div>div.test after first_sibling_child
Pass remove tree div>div.test after first_sibling_child
Pass insert tree div>div.test after first_sibling_descendant
Pass remove tree div>div.test after first_sibling_descendant
Pass insert tree div>div.test after third_sibling_child
Pass remove tree div>div.test after third_sibling_child
Pass insert tree div>div.test after third_sibling_descendant
Pass remove tree div>div.test after third_sibling_descendant

View file

@ -0,0 +1,13 @@
Summary
Harness status: OK
Rerun
Found 3 tests
3 Pass
Details
Result Test Name MessagePass Initial colors
Pass Matches after #blocks_match removed
Pass Does not match after #blocks_match added

View file

@ -0,0 +1,19 @@
Summary
Harness status: OK
Rerun
Found 9 tests
9 Pass
Details
Result Test Name MessagePass Initial color
Pass add test to subject_descendant
Pass remove test from subject_descendant
Pass add test to sibling_descendant
Pass remove test from sibling_descendant
Pass add test_inner to subject_child
Pass remove test_inner from subject_child
Pass add test_inner to sibling_child
Pass remove test_inner from sibling_child

View file

@ -0,0 +1,47 @@
Summary
Harness status: OK
Rerun
Found 37 tests
37 Pass
Details
Result Test Name MessagePass #anchor1 initially white
Pass #anchor1 becomes rgb(0, 0, 255) after adding .ancestor to #grand_parent1
Pass #anchor1 becomes rgb(255, 255, 255) after removing .ancestor from #grand_parent1
Pass #anchor1 becomes rgb(0, 0, 255) after adding .ancestor to #parent1
Pass #anchor1 becomes rgb(255, 255, 255) after removing .ancestor from #parent1
Pass #anchor2 initially white
Pass #anchor2 becomes rgb(173, 216, 230) after adding .ancestor to #grand_parent2
Pass #anchor2 becomes rgb(255, 255, 255) after removing .ancestor from #grand_parent2
Pass #anchor2 becomes rgb(173, 216, 230) after adding .ancestor to #parent2
Pass #anchor2 becomes rgb(255, 255, 255) after removing .ancestor from #parent2
Pass #anchor3 initially white
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #grand_parent_indirect_prev3
Pass #anchor3 becomes rgb(154, 205, 50) after adding .ancestor to #grand_parent3
Pass #anchor3 becomes rgb(255, 255, 0) after removing .ancestor from #grand_parent3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #grand_parent_indirect_prev3
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #grand_parent_direct_prev3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #grand_parent_direct_prev3
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #parent_indirect_prev3
Pass #anchor3 becomes rgb(154, 205, 50) after adding .ancestor to #parent3
Pass #anchor3 becomes rgb(255, 255, 0) after removing .ancestor from #parent3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #parent_indirect_prev3
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #parent_direct_prev3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #parent_direct_prev3
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #anchor_indirect_prev3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #anchor_indirect_prev3
Pass #anchor3 becomes rgb(255, 255, 0) after adding .ancestor_prev to #anchor_direct_prev3
Pass #anchor3 becomes rgb(255, 255, 255) after removing .ancestor_prev from #anchor_direct_prev3
Pass #anchor4 initially white
Pass #anchor4 becomes rgb(0, 128, 0) after adding .prev to #indirect_prev4
Pass #anchor4 becomes rgb(255, 255, 255) after removing .prev from #indirect_prev4
Pass #anchor4 becomes rgb(0, 128, 0) after adding .prev to #direct_prev4
Pass #anchor4 becomes rgb(255, 255, 255) after removing .prev from #direct_prev4
Pass #anchor5 initially white
Pass #anchor5 becomes rgb(144, 238, 144) after adding .prev to #indirect_prev5
Pass #anchor5 becomes rgb(255, 255, 255) after removing .prev from #indirect_prev5
Pass #anchor5 becomes rgb(144, 238, 144) after adding .prev to #direct_prev5
Pass #anchor5 becomes rgb(255, 255, 255) after removing .prev from #direct_prev5

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Fail
Details
Result Test Name MessageFail CSS Selector Invalidation: :has() with nesting parent containing :hover promise_test: Unhandled rejection with value: object "ReferenceError: 'test_driver' is not defined"

View file

@ -0,0 +1,31 @@
Summary
Harness status: OK
Rerun
Found 21 tests
21 Pass
Details
Result Test Name MessagePass Initial color
Pass remove .test to subject_child
Pass add .test from subject_child
Pass remove .test to subject_descendant
Pass add .test from subject_descendant
Pass insert element div before subject_child
Pass remove element div before subject_child
Pass insert element div before subject_descendant
Pass remove element div before subject_descendant
Pass insert element div after subject_child
Pass remove element div after subject_child
Pass insert element div after subject_descendant
Pass remove element div after subject_descendant
Pass insert tree div>div before subject_child
Pass remove tree div>div before subject_child
Pass insert tree div>div before subject_descendant
Pass remove tree div>div before subject_descendant
Pass insert tree div.test after subject_child
Pass remove tree div.test after subject_child
Pass insert tree div.test after subject_descendant
Pass remove tree div.test after subject_descendant

View file

@ -0,0 +1,15 @@
Summary
Harness status: OK
Rerun
Found 5 tests
5 Pass
Details
Result Test Name MessagePass Initially red
Pass :nth-child() no longer matching after removal
Pass :nth-last-child() no longer matching after removal
Pass :nth-child() in non-subject no longer matching after removal
Pass :nth-last-child() in non-subject no longer matching after removal

View file

@ -0,0 +1,52 @@
Summary
Harness status: OK
Rerun
Found 41 tests
22 Pass
19 Fail
Details
Result Test Name MessagePass Before set checked on checkbox, testing subject
Fail Set checked on checkbox, testing subject assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)"
Pass Unset checked on checkbox, testing subject
Fail Set select on option assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)"
Pass Reset select
Pass Before set disabled on checkbox, testing subject
Pass Set disabled on checkbox, testing subject
Fail Unset disabled on checkbox, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Pass Before set disabled on checkbox, testing subject3
Pass Set disabled on checkbox, testing subject3
Pass Unset disabled on checkbox, testing subject3
Fail Before set disabled on option, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Pass Set disabled on option, testing subject
Fail Unset disabled on option, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Pass Before set disabled on option, testing subject3
Pass Set disabled on option, testing subject3
Pass Unset disabled on option, testing subject3
Fail Before set disabled on optgroup, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Pass Set disabled on optgroup, testing subject
Fail Unset disabled on optgroup, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Fail Before set disabled on optgroup, testing subject2 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Set disabled on optgroup, testing subject2
Fail Unset disabled on optgroup, testing subject2 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Before set disabled on optgroup, testing subject3
Pass Set disabled on optgroup, testing subject3
Pass Unset disabled on optgroup, testing subject3
Fail Before set disabled on optgroup, testing subject4 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Set disabled on optgroup, testing subject4
Fail Unset disabled on optgroup, testing subject4 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Fail Before setting value of text_input, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Fail Set value of text_input, testing subject assert_equals: expected "rgb(255, 255, 0)" but got "rgb(255, 0, 0)"
Fail Clear value of text_input, testing subject assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)"
Fail Before setting value of text_input, testing subject2 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Set value of text_input, testing subject2
Fail Clear value of text_input, testing subject2 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Before setting value of text_input, testing subject3
Fail Set value of text_input, testing subject3 assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)"
Pass Clear value of text_input, testing subject3
Fail Before setting value of text_input, testing subject4 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"
Pass Set value of text_input, testing subject4
Fail Clear value of text_input, testing subject4 assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 255, 0)"

View file

@ -0,0 +1,69 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has pseudo class behavior with explicit ':scope' in its argument</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<main>
<div id=d01 class="a">
<div id=scope1 class="b">
<div id=d02 class="c">
<div id=d03 class="c">
<div id=d04 class="d"></div>
</div>
</div>
<div id=d05 class="e"></div>
</div>
</div>
<div id=d06>
<div id=scope2 class="b">
<div id=d07 class="c">
<div id=d08 class="c">
<div id=d09></div>
</div>
</div>
</div>
</div>
</div>
<script>
function formatElements(elements) {
return elements.map(e => e.id).sort().join();
}
// Test that |selector| returns the given elements in the given scope element
function test_selector_all(scope, selector, expected) {
test(function() {
let actual = Array.from(scope.querySelectorAll(selector));
assert_equals(formatElements(actual), formatElements(expected));
}, `${selector} matches expected elements on ${scope.id}`);
}
// Test that |selector1| and |selector2| returns same elements in the given scope element
function compare_selector_all(scope, selector1, selector2) {
test(function() {
let result1 = Array.from(scope.querySelectorAll(selector1));
let result2 = Array.from(scope.querySelectorAll(selector2));
assert_equals(formatElements(result1), formatElements(result2));
}, `${selector1} and ${selector2} returns same elements on ${scope.id}`);
}
// descendants of a scope element cannot have the scope element as its descendant
test_selector_all(scope1, ':has(:scope)', []);
test_selector_all(scope1, ':has(:scope .c)', []);
test_selector_all(scope1, ':has(.a :scope)', []);
// there can be more simple and efficient alternative for a ':scope' in ':has'
test_selector_all(scope1, '.a:has(:scope) .c', [d02, d03]);
compare_selector_all(scope1, '.a:has(:scope) .c', ':is(.a :scope .c)');
test_selector_all(scope2, '.a:has(:scope) .c', []);
compare_selector_all(scope2, '.a:has(:scope) .c', ':is(.a :scope .c)');
test_selector_all(scope1, '.c:has(:is(:scope .d))', [d02, d03]);
compare_selector_all(scope1, '.c:has(:is(:scope .d))', ':scope .c:has(.d)');
compare_selector_all(scope1, '.c:has(:is(:scope .d))', '.c:has(.d)');
test_selector_all(scope2, '.c:has(:is(:scope .d))', []);
compare_selector_all(scope2, '.c:has(:is(:scope .d))', ':scope .c:has(.d)');
compare_selector_all(scope2, '.c:has(:is(:scope .d))', '.c:has(.d)');
</script>

View file

@ -0,0 +1,81 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Basic matching behavior of :has pseudo class</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<main id=main>
<div id=a class="ancestor">
<div id=b class="parent ancestor">
<div id=c class="sibling descendant">
<div id=d class="descendant"></div>
</div>
<div id=e class="target descendant"></div>
</div>
<div id=f class="parent ancestor">
<div id=g class="target descendant"></div>
</div>
<div id=h class="parent ancestor">
<div id=i class="target descendant"></div>
<div id=j class="sibling descendant">
<div id=k class="descendant"></div>
</div>
</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_all(selector, expected) {
test(function() {
let actual = Array.from(main.querySelectorAll(selector));
assert_equals(formatElements(actual), formatElements(expected));
}, `${selector} matches expected elements`);
}
// Test that |selector| returns the given element in #main.
function test_selector(selector, expected) {
test(function() {
assert_equals(main.querySelector(selector), expected);
}, `${selector} matches expected element`);
}
// Test that |selector| returns the given closest element.
function test_closest(node, selector, expected) {
test(function() {
assert_equals(node.closest(selector), expected);
}, `closest(${selector}) returns expected element`);
}
// Test that |selector| returns matching status.
function test_matches(node, selector, expected) {
test(function() {
assert_equals(node.matches(selector), expected);
}, `${selector} matches expectedly`);
}
test_selector_all(':has(#a)', []);
test_selector_all(':has(.ancestor)', [a]);
test_selector_all(':has(.target)', [a, b, f, h]);
test_selector_all(':has(.descendant)', [a, b, c, f, h, j]);
test_selector_all('.parent:has(.target)', [b, f, h]);
test_selector_all(':has(.sibling ~ .target)', [a, b]);
test_selector_all('.parent:has(.sibling ~ .target)', [b]);
test_selector_all(':has(:is(.target ~ .sibling .descendant))', [a, h, j]);
test_selector_all('.parent:has(:is(.target ~ .sibling .descendant))', [h]);
test_selector_all('.sibling:has(.descendant) ~ .target', [e]);
test_selector_all(':has(> .parent)', [a]);
test_selector_all(':has(> .target)', [b, f, h]);
test_selector_all(':has(> .parent, > .target)', [a, b, f, h]);
test_selector_all(':has(+ #h)', [f]);
test_selector_all('.parent:has(~ #h)', [b, f]);
test_selector('.sibling:has(.descendant)', c);
test_closest(k, '.ancestor:has(.descendant)', h);
test_matches(h, ':has(.target ~ .sibling .descendant)', true);
</script>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Matches :has pseudo class to uninserted elements</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<script>
// Test that |selector| returns matching status.
function test_matches(node, selector, expected) {
test(function() {
assert_equals(node.matches(selector), expected);
}, `${selector} matches expectedly`);
}
subject = document.createElement('subject');
subject.innerHTML = '<child></child>';
test_matches(subject, ':has(child)', true);
test_matches(subject, ':has(> child)', true);
subject.innerHTML = '<child><descendant></descendant></child>';
test_matches(subject, ':has(descendant)', true);
test_matches(subject, ':has(> descendant)', false);
subject.innerHTML = '<child></child><direct_sibling></direct_sibling><indirect_sibling></indirect_sibling>';
test_matches(subject.firstChild, ':has(~ direct_sibling)', true);
test_matches(subject.firstChild, ':has(+ direct_sibling)', true);
test_matches(subject.firstChild, ':has(~ indirect_sibling)', true);
test_matches(subject.firstChild, ':has(+ indirect_sibling)', false);
test_matches(subject, ':has(*)', true);
test_matches(subject, ':has(> *)', true);
test_matches(subject, ':has(~ *)', false);
test_matches(subject, ':has(+ *)', false);
</script>

View file

@ -0,0 +1,184 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has pseudo class behavior with various relative arguments</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<main id=main>
<div id=d01>
<div id=d02 class="x">
<div id=d03 class="a"></div>
<div id=d04></div>
<div id=d05 class="b"></div>
</div>
<div id=d06 class="x">
<div id=d07 class="x">
<div id=d08 class="a"></div>
</div>
</div>
<div id=d09 class="x">
<div id=d10 class="a">
<div id=d11 class="b"></div>
</div>
</div>
<div id=d12 class="x">
<div id=d13 class="a">
<div id=d14>
<div id=d15 class="b"></div>
</div>
</div>
<div id=d16 class="b"></div>
</div>
</div>
<div id=d17>
<div id=d18 class="x"></div>
<div id=d19 class="x"></div>
<div id=d20 class="a"></div>
<div id=d21 class="x"></div>
<div id=d22 class="a">
<div id=d23 class="b"></div>
</div>
<div id=d24 class="x"></div>
<div id=d25 class="a">
<div id=d26>
<div id=d27 class="b"></div>
</div>
</div>
<div id=d28 class="x"></div>
<div id=d29 class="a"></div>
<div id=d30 class="b">
<div id=d31 class="c"></div>
</div>
<div id=d32 class="x"></div>
<div id=d33 class="a"></div>
<div id=d34 class="b">
<div id=d35>
<div id=d36 class="c"></div>
</div>
</div>
<div id=d37 class="x"></div>
<div id=d38 class="a"></div>
<div id=d39 class="b"></div>
<div id=d40 class="x"></div>
<div id=d41 class="a"></div>
<div id=d42></div>
<div id=d43 class="b">
<div id=d44 class="x">
<div id=d45 class="c"></div>
</div>
</div>
<div id=d46 class="x"></div>
<div id=d47 class="a">
</div>
</div>
<div>
<div id=d48 class="x">
<div id=d49 class="x">
<div id=d50 class="x d">
<div id=d51 class="x d">
<div id=d52 class="x">
<div id=d53 class="x e">
<div id=d54 class="f"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id=d55 class="x"></div>
<div id=d56 class="x d"></div>
<div id=d57 class="x d"></div>
<div id=d58 class="x"></div>
<div id=d59 class="x e"></div>
<div id=d60 class="f"></div>
</div>
<div>
<div id=d61 class="x"></div>
<div id=d62 class="x y"></div>
<div id=d63 class="x y">
<div id=d64 class="y g">
<div id=d65 class="y">
<div id=d66 class="y h">
<div id=d67 class="i"></div>
</div>
</div>
</div>
</div>
<div id=d68 class="x y">
<div id=d69 class="x"></div>
<div id=d70 class="x"></div>
<div id=d71 class="x y">
<div id=d72 class="y g">
<div id=d73 class="y">
<div id=d74 class="y h">
<div id=d75 class="i"></div>
</div>
</div>
</div>
</div>
<div id=d76 class="x"></div>
<div id=d77 class="j"><div id=d78><div id=d79></div></div></div>
</div>
<div id=d80 class="j"></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_all(selector, expected) {
test(function() {
let actual = Array.from(main.querySelectorAll(selector));
assert_equals(formatElements(actual), formatElements(expected));
}, `${selector} matches expected elements`);
}
test_selector_all('.x:has(.a)', [d02, d06, d07, d09, d12]);
test_selector_all('.x:has(.a > .b)', [d09]);
test_selector_all('.x:has(.a .b)', [d09, d12]);
test_selector_all('.x:has(.a + .b)', [d12]);
test_selector_all('.x:has(.a ~ .b)', [d02, d12]);
test_selector_all('.x:has(> .a)', [d02, d07, d09, d12]);
test_selector_all('.x:has(> .a > .b)', [d09]);
test_selector_all('.x:has(> .a .b)', [d09, d12]);
test_selector_all('.x:has(> .a + .b)', [d12]);
test_selector_all('.x:has(> .a ~ .b)', [d02, d12]);
test_selector_all('.x:has(+ .a)', [d19, d21, d24, d28, d32, d37, d40, d46]);
test_selector_all('.x:has(+ .a > .b)', [d21]);
test_selector_all('.x:has(+ .a .b)', [d21, d24]);
test_selector_all('.x:has(+ .a + .b)', [d28, d32, d37]);
test_selector_all('.x:has(+ .a ~ .b)', [d19, d21, d24, d28, d32, d37, d40]);
test_selector_all('.x:has(~ .a)', [d18, d19, d21, d24, d28, d32, d37, d40, d46]);
test_selector_all('.x:has(~ .a > .b)', [d18, d19, d21]);
test_selector_all('.x:has(~ .a .b)', [d18, d19, d21, d24]);
test_selector_all('.x:has(~ .a + .b)', [d18, d19, d21, d24, d28, d32, d37]);
test_selector_all('.x:has(~ .a + .b > .c)', [d18, d19, d21, d24, d28]);
test_selector_all('.x:has(~ .a + .b .c)', [d18, d19, d21, d24, d28, d32]);
test_selector_all('.x:has(.d .e)', [d48, d49, d50]);
test_selector_all('.x:has(.d .e) .f', [d54]);
test_selector_all('.x:has(> .d)', [d49, d50]);
test_selector_all('.x:has(> .d) .f', [d54]);
test_selector_all('.x:has(~ .d ~ .e)', [d48, d55, d56]);
test_selector_all('.x:has(~ .d ~ .e) ~ .f', [d60]);
test_selector_all('.x:has(+ .d ~ .e)', [d55, d56]);
test_selector_all('.x:has(+ .d ~ .e) ~ .f', [d60]);
test_selector_all('.y:has(> .g .h)', [d63, d71])
test_selector_all('.y:has(.g .h)', [d63, d68, d71])
test_selector_all('.y:has(> .g .h) .i', [d67, d75])
test_selector_all('.y:has(.g .h) .i', [d67, d75])
test_selector_all('.d .x:has(.e)', [d51, d52])
test_selector_all('.d ~ .x:has(~ .e)', [d57, d58])
</script>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<title>CSS Selectors Test: Chrome crash issue 1470477</title>
<link rel="help" href="https://crbug.com/1470477">
<style>
:has(> :where(label:first-child + [a="a"]:only-of-type,
[a="a"]:only-of-type + label:last-child)) label:last-child {
margin-inline: 1em;
}
</style>
<p>PASS if this tests does not crash</p>
<script>
if (window.internals)
window.internals.signalTextTestIsDone("PASS");
</script>

View file

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

View file

@ -0,0 +1,105 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has() invalidation with nesting where the selector is shared</title>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#outer1:has(.test) {
& #subject1_1 {
color: red;
}
& + #subject1_2 {
color: orangered;
}
}
#outer2:has(.test) {
& .ancestor {
& #subject2_1 {
color: green;
}
& + #subject2_2 {
color: lightgreen;
}
}
}
#outer3:is(:has(.test) .outer) {
& #subject3_1 {
color: blue;
}
& + #subject3_2 {
color: skyblue;
}
}
</style>
<main id="main">
<div>
<div id="outer1">
<div id="trigger1"></div>
<div id="subject1_1"></div>
</div>
<div id="subject1_2"></div>
</div>
<div id="outer2">
<div id="trigger2"></div>
<div class="ancestor">
<div id="subject2_1"></div>
</div>
<div id="subject2_2"></div>
</div>
<div id="trigger3">
<div id="outer3" class="outer">
<div id="subject3_1"></div>
</div>
<div id="subject3_2"></div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const orangered = 'rgb(255, 69, 0)';
const green = 'rgb(0, 128, 0)';
const lightgreen = 'rgb(144, 238, 144)';
const blue = 'rgb(0, 0, 255)';
const skyblue = 'rgb(135, 206, 235)';
const colors = {
red: {
descendant: red,
sibling: orangered,
},
green: {
descendant: green,
sibling: lightgreen,
},
blue: {
descendant: blue,
sibling: skyblue,
},
};
function testColor(testName, element, color) {
test(function() {
assert_equals(getComputedStyle(element).color, color);
}, testName);
}
function testClassChange(trigger, targetDescendant, targetSibling, expected)
{
trigger.classList.add('test');
testColor(`add .test to ${trigger.id} - check ${targetDescendant.id}`, targetDescendant, colors[expected].descendant);
testColor(`add .test to ${trigger.id} - check ${targetSibling.id}`, targetSibling, colors[expected].sibling);
trigger.classList.remove('test');
testColor(`remove .test from ${trigger.id} - check ${targetDescendant.id}`, targetDescendant, grey);
testColor(`remove .test from ${trigger.id} - check ${targetSibling.id}`, targetSibling, grey);
}
testClassChange(trigger1, subject1_1, subject1_2, 'red');
testClassChange(trigger2, subject2_1, subject2_2, 'green');
testClassChange(trigger3, subject3_1, subject3_2, 'blue');
</script>

View file

@ -0,0 +1,312 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() in adjacent position</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
div:has(.test) + #subject { color: red }
div:has([test_attr]) + #subject { color: orangered }
div:has(> .test) + #subject { color: green }
div:has(> [test_attr]) + #subject { color: lightgreen }
div:has(~ .test) + #subject { color: yellow }
div:has(~ [test_attr]) + #subject { color: ivory }
div:has(+ .test) + #subject { color: blue }
div:has(+ [test_attr]) + #subject { color: skyblue }
div:has(~ div .test) + #subject { color: purple }
div:has(~ div [test_attr]) + #subject { color: violet }
div:has(+ div .test) + #subject { color: pink }
div:has(+ div [test_attr]) + #subject { color: lightpink }
</style>
<main id=main>
<div id=previous_sibling>
<div id=previous_sibling_child>
<div id=previous_sibling_descendant></div>
</div>
</div>
<div id=subject></div>
<div id=next_sibling>
<div id=next_sibling_child>
<div id=next_sibling_descendant></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const orangered = 'rgb(255, 69, 0)';
const green = 'rgb(0, 128, 0)';
const lightgreen = 'rgb(144, 238, 144)';
const blue = 'rgb(0, 0, 255)';
const skyblue = 'rgb(135, 206, 235)';
const yellow = 'rgb(255, 255, 0)';
const ivory = 'rgb(255, 255, 240)';
const purple = 'rgb(128, 0, 128)';
const violet = 'rgb(238, 130, 238)';
const pink = 'rgb(255, 192, 203)';
const lightpink = 'rgb(255, 182, 193)';
const colors = {
grey: {
classTest: grey,
attributeTest: grey,
},
red: {
classTest: red,
attributeTest: orangered,
},
green: {
classTest: green,
attributeTest: lightgreen,
},
blue: {
classTest: blue,
attributeTest: skyblue,
},
yellow: {
classTest: yellow,
attributeTest: ivory,
},
purple: {
classTest: purple,
attributeTest: violet,
},
pink: {
classTest: pink,
attributeTest: lightpink,
},
};
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
element.classList.add('test');
testColor(`add .test to ${element.id}`, expectedColorForClassTest);
element.classList.remove('test');
testColor(`remove .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
beforeElement.before(newElement);
testColor(`insert element div.test before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test before ${beforeElement.id}`, grey);
newElement.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert element div before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove element div before ${beforeElement.id}`, grey);
newElement.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
afterElement.after(newElement);
testColor(`insert element div.test after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test after ${afterElement.id}`, grey);
newElement.classList.remove('test');
afterElement.after(newElement);
testColor(`insert element div after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove element div after ${afterElement.id}`, grey);
newElement.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
newChild.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert tree div>div before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div before ${beforeElement.id}`, grey);
newChild.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div>div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
newChild.classList.remove('test');
afterElement.after(newElement);
testColor(`insert tree div>div after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div after ${afterElement.id}`, grey);
newChild.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div>div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] after ${afterElement.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(previous_sibling, "grey");
testClassChange(previous_sibling_child, "green");
testClassChange(previous_sibling_descendant, "red");
testClassChange(subject, "blue");
testClassChange(next_sibling, "yellow");
testClassChange(next_sibling_child, "purple");
testClassChange(next_sibling_descendant, "purple");
testElementInsertionBefore(previous_sibling, "grey");
testElementInsertionBefore(previous_sibling_child, "green");
testElementInsertionBefore(previous_sibling_descendant, "red");
testElementInsertionBefore(subject, "grey");
testElementInsertionBefore(next_sibling, "yellow");
testElementInsertionBefore(next_sibling_child, "purple");
testElementInsertionBefore(next_sibling_descendant, "purple");
testElementInsertionAfter(previous_sibling, "grey");
testElementInsertionAfter(previous_sibling_child, "green");
testElementInsertionAfter(previous_sibling_descendant, "red");
testElementInsertionAfter(subject, "yellow");
testElementInsertionAfter(next_sibling, "yellow");
testElementInsertionAfter(next_sibling_child, "purple");
testElementInsertionAfter(next_sibling_descendant, "purple");
testTreeInsertionBefore(previous_sibling, "grey");
testTreeInsertionBefore(previous_sibling_child, "red");
testTreeInsertionBefore(previous_sibling_descendant, "red");
testTreeInsertionBefore(subject, "green");
testTreeInsertionBefore(next_sibling, "purple");
testTreeInsertionBefore(next_sibling_child, "purple");
testTreeInsertionBefore(next_sibling_descendant, "purple");
testTreeInsertionAfter(previous_sibling, "green");
testTreeInsertionAfter(previous_sibling_child, "red");
testTreeInsertionAfter(previous_sibling_descendant, "red");
testTreeInsertionAfter(subject, "purple");
testTreeInsertionAfter(next_sibling, "purple");
testTreeInsertionAfter(next_sibling_child, "purple");
testTreeInsertionAfter(next_sibling_descendant, "purple");
</script>

View file

@ -0,0 +1,320 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() in ancestor position</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
div:has(.test) #subject { color: red }
div:has([test_attr]) #subject { color: orangered }
div:has(> .test) #subject { color: green }
div:has(> [test_attr]) #subject { color: lightgreen }
div:has(~ .test) #subject { color: yellow }
div:has(~ [test_attr]) #subject { color: ivory }
div:has(+ .test) #subject { color: blue }
div:has(+ [test_attr]) #subject { color: skyblue }
div:has(~ div .test) #subject { color: purple }
div:has(~ div [test_attr]) #subject { color: violet }
div:has(+ div .test) #subject { color: pink }
div:has(+ div [test_attr]) #subject { color: lightpink }
</style>
<main id=main>
<div id=subject_ancestor>
<div id=subject_parent>
<div id=subject>
<div id=subject_child>
<div id=subject_descendant></div>
</div>
</div>
</div>
</div>
<div id=next_sibling>
<div id=next_sibling_child>
<div id=next_sibling_descendant></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const orangered = 'rgb(255, 69, 0)';
const green = 'rgb(0, 128, 0)';
const lightgreen = 'rgb(144, 238, 144)';
const blue = 'rgb(0, 0, 255)';
const skyblue = 'rgb(135, 206, 235)';
const yellow = 'rgb(255, 255, 0)';
const ivory = 'rgb(255, 255, 240)';
const purple = 'rgb(128, 0, 128)';
const violet = 'rgb(238, 130, 238)';
const pink = 'rgb(255, 192, 203)';
const lightpink = 'rgb(255, 182, 193)';
const colors = {
grey: {
classTest: grey,
attributeTest: grey,
},
red: {
classTest: red,
attributeTest: orangered,
},
green: {
classTest: green,
attributeTest: lightgreen,
},
blue: {
classTest: blue,
attributeTest: skyblue,
},
yellow: {
classTest: yellow,
attributeTest: ivory,
},
purple: {
classTest: purple,
attributeTest: violet,
},
pink: {
classTest: pink,
attributeTest: lightpink,
},
};
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
element.classList.add('test');
testColor(`add .test to ${element.id}`, expectedColorForClassTest);
element.classList.remove('test');
testColor(`remove .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
beforeElement.before(newElement);
testColor(`insert element div.test before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test before ${beforeElement.id}`, grey);
newElement.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert element div before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove element div before ${beforeElement.id}`, grey);
newElement.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
afterElement.after(newElement);
testColor(`insert element div.test after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test after ${afterElement.id}`, grey);
newElement.classList.remove('test');
afterElement.after(newElement);
testColor(`insert element div after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove element div after ${afterElement.id}`, grey);
newElement.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
newChild.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert tree div>div before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div before ${beforeElement.id}`, grey);
newChild.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div>div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
newChild.classList.remove('test');
afterElement.after(newElement);
testColor(`insert tree div>div after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div after ${afterElement.id}`, grey);
newChild.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div>div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] after ${afterElement.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(subject_ancestor, "grey");
testClassChange(subject_parent, "green");
testClassChange(subject, "green");
testClassChange(subject_child, "red");
testClassChange(subject_descendant, "red");
testClassChange(next_sibling, "blue");
testClassChange(next_sibling_child, "pink");
testClassChange(next_sibling_descendant, "pink");
testElementInsertionBefore(subject_ancestor, "grey");
testElementInsertionBefore(subject_parent, "green");
testElementInsertionBefore(subject, "green");
testElementInsertionBefore(subject_child, "red");
testElementInsertionBefore(subject_descendant, "red");
testElementInsertionBefore(next_sibling, "blue");
testElementInsertionBefore(next_sibling_child, "pink");
testElementInsertionBefore(next_sibling_descendant, "pink");
testElementInsertionAfter(subject_ancestor, "blue");
testElementInsertionAfter(subject_parent, "blue");
testElementInsertionAfter(subject, "green");
testElementInsertionAfter(subject_child, "red");
testElementInsertionAfter(subject_descendant, "red");
testElementInsertionAfter(next_sibling, "yellow");
testElementInsertionAfter(next_sibling_child, "pink");
testElementInsertionAfter(next_sibling_descendant, "pink");
testTreeInsertionBefore(subject_ancestor, "grey");
testTreeInsertionBefore(subject_parent, "red");
testTreeInsertionBefore(subject, "red");
testTreeInsertionBefore(subject_child, "red");
testTreeInsertionBefore(subject_descendant, "red");
testTreeInsertionBefore(next_sibling, "pink");
testTreeInsertionBefore(next_sibling_child, "pink");
testTreeInsertionBefore(next_sibling_descendant, "pink");
testTreeInsertionAfter(subject_ancestor, "pink");
testTreeInsertionAfter(subject_parent, "pink");
testTreeInsertionAfter(subject, "red");
testTreeInsertionAfter(subject_child, "red");
testTreeInsertionAfter(subject_descendant, "red");
testTreeInsertionAfter(next_sibling, "purple");
testTreeInsertionAfter(next_sibling_child, "pink");
testTreeInsertionAfter(next_sibling_descendant, "pink");
</script>

View file

@ -0,0 +1,300 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() in parent position</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
div:has(.test) > #subject { color: red }
div:has([test_attr]) > #subject { color: orangered }
div:has(> .test) > #subject { color: green }
div:has(> [test_attr]) > #subject { color: lightgreen }
div:has(~ .test) > #subject { color: yellow }
div:has(~ [test_attr]) > #subject { color: ivory }
div:has(+ .test) > #subject { color: blue }
div:has(+ [test_attr]) > #subject { color: skyblue }
div:has(~ div .test) > #subject { color: purple }
div:has(~ div [test_attr]) > #subject { color: violet }
div:has(+ div .test) > #subject { color: pink }
div:has(+ div [test_attr]) > #subject { color: lightpink }
</style>
<main id=main>
<div id=subject_ancestor>
<div id=subject_parent>
<div id=subject>
<div id=subject_child>
<div id=subject_descendant></div>
</div>
</div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const orangered = 'rgb(255, 69, 0)';
const green = 'rgb(0, 128, 0)';
const lightgreen = 'rgb(144, 238, 144)';
const blue = 'rgb(0, 0, 255)';
const skyblue = 'rgb(135, 206, 235)';
const yellow = 'rgb(255, 255, 0)';
const ivory = 'rgb(255, 255, 240)';
const purple = 'rgb(128, 0, 128)';
const violet = 'rgb(238, 130, 238)';
const pink = 'rgb(255, 192, 203)';
const lightpink = 'rgb(255, 182, 193)';
const colors = {
grey: {
classTest: grey,
attributeTest: grey,
},
red: {
classTest: red,
attributeTest: orangered,
},
green: {
classTest: green,
attributeTest: lightgreen,
},
blue: {
classTest: blue,
attributeTest: skyblue,
},
yellow: {
classTest: yellow,
attributeTest: ivory,
},
purple: {
classTest: purple,
attributeTest: violet,
},
pink: {
classTest: pink,
attributeTest: lightpink,
},
};
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
element.classList.add('test');
testColor(`add .test to ${element.id}`, expectedColorForClassTest);
element.classList.remove('test');
testColor(`remove .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test');
beforeElement.before(newElement);
testColor(`insert element div.test before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test before ${beforeElement.id}`, grey);
newElement.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert element div before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove element div before ${beforeElement.id}`, grey);
newElement.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test');
afterElement.after(newElement);
testColor(`insert element div.test after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test after ${afterElement.id}`, grey);
newElement.classList.remove('test');
afterElement.after(newElement);
testColor(`insert element div after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove element div after ${afterElement.id}`, grey);
newElement.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
newChild.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert tree div>div before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div before ${beforeElement.id}`, grey);
newChild.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div>div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
newChild.classList.remove('test');
afterElement.after(newElement);
testColor(`insert tree div>div after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div after ${afterElement.id}`, grey);
newChild.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div>div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] after ${afterElement.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(subject_ancestor, "grey");
testClassChange(subject_parent, "grey");
testClassChange(subject, "green");
testClassChange(subject_child, "red");
testClassChange(subject_descendant, "red");
testElementInsertionBefore(subject_ancestor, "grey");
testElementInsertionBefore(subject_parent, "grey");
testElementInsertionBefore(subject, "green");
testElementInsertionBefore(subject_child, "red");
testElementInsertionBefore(subject_descendant, "red");
testElementInsertionAfter(subject_ancestor, "grey");
testElementInsertionAfter(subject_parent, "blue");
testElementInsertionAfter(subject, "green");
testElementInsertionAfter(subject_child, "red");
testElementInsertionAfter(subject_descendant, "red");
testTreeInsertionBefore(subject_ancestor, "grey");
testTreeInsertionBefore(subject_parent, "grey");
testTreeInsertionBefore(subject, "red");
testTreeInsertionBefore(subject_child, "red");
testTreeInsertionBefore(subject_descendant, "red");
testTreeInsertionAfter(subject_ancestor, "grey");
testTreeInsertionAfter(subject_parent, "pink");
testTreeInsertionAfter(subject, "red");
testTreeInsertionAfter(subject_child, "red");
testTreeInsertionAfter(subject_descendant, "red");
</script>

View file

@ -0,0 +1,312 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() in sibling position</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
div:has(.test) ~ #subject { color: red }
div:has([test_attr]) ~ #subject { color: orangered }
div:has(> .test) ~ #subject { color: green }
div:has(> [test_attr]) ~ #subject { color: lightgreen }
div:has(~ .test) ~ #subject { color: yellow }
div:has(~ [test_attr]) ~ #subject { color: ivory }
div:has(+ .test) ~ #subject { color: blue }
div:has(+ [test_attr]) ~ #subject { color: skyblue }
div:has(~ div .test) ~ #subject { color: purple }
div:has(~ div [test_attr]) ~ #subject { color: violet }
div:has(+ div .test) ~ #subject { color: pink }
div:has(+ div [test_attr]) ~ #subject { color: lightpink }
</style>
<main id=main>
<div id=previous_sibling>
<div id=previous_sibling_child>
<div id=previous_sibling_descendant></div>
</div>
</div>
<div id=subject></div>
<div id=next_sibling>
<div id=next_sibling_child>
<div id=next_sibling_descendant></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const orangered = 'rgb(255, 69, 0)';
const green = 'rgb(0, 128, 0)';
const lightgreen = 'rgb(144, 238, 144)';
const blue = 'rgb(0, 0, 255)';
const skyblue = 'rgb(135, 206, 235)';
const yellow = 'rgb(255, 255, 0)';
const ivory = 'rgb(255, 255, 240)';
const purple = 'rgb(128, 0, 128)';
const violet = 'rgb(238, 130, 238)';
const pink = 'rgb(255, 192, 203)';
const lightpink = 'rgb(255, 182, 193)';
const colors = {
grey: {
classTest: grey,
attributeTest: grey,
},
red: {
classTest: red,
attributeTest: orangered,
},
green: {
classTest: green,
attributeTest: lightgreen,
},
blue: {
classTest: blue,
attributeTest: skyblue,
},
yellow: {
classTest: yellow,
attributeTest: ivory,
},
purple: {
classTest: purple,
attributeTest: violet,
},
pink: {
classTest: pink,
attributeTest: lightpink,
},
};
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
element.classList.add('test');
testColor(`add .test to ${element.id}`, expectedColorForClassTest);
element.classList.remove('test');
testColor(`remove .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
beforeElement.before(newElement);
testColor(`insert element div.test before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test before ${beforeElement.id}`, grey);
newElement.classList.remove('test')
beforeElement.before(newElement);
testColor(`insert element div before ${beforeElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove element div before ${beforeElement.id}`, grey);
newElement.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
newElement.classList.add('test')
afterElement.after(newElement);
testColor(`insert element div.test after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' again to the element inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove element div.test after ${afterElement.id}`, grey);
newElement.classList.remove('test');
afterElement.after(newElement);
testColor(`insert element div after ${afterElement.id}`, grey);
newElement.classList.add('test');
testColor(`add the class 'test' to the element inserted again after ${afterElement.id}`, expectedColorForClassTest);
newElement.classList.remove('test');
testColor(`remove the class 'test' from the element inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove element div after ${afterElement.id}`, grey);
newElement.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div[test_attr] after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted before ${beforeElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
newChild.classList.remove('test');
beforeElement.before(newElement);
testColor(`insert tree div>div before ${beforeElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again before ${beforeElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again before ${beforeElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div before ${beforeElement.id}`, grey);
newChild.setAttribute('test_attr', '');
beforeElement.before(newElement);
testColor(`insert element div>div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' again to the element in the tree inserted after ${afterElement.id}`, expectedColorForClassTest);
newElement.remove();
testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
newChild.classList.remove('test');
afterElement.after(newElement);
testColor(`insert tree div>div after ${afterElement.id}`, grey);
newChild.classList.add('test');
testColor(`add the class 'test' to the element in the tree inserted again after ${afterElement.id}`, expectedColorForClassTest);
newChild.classList.remove('test');
testColor(`remove the class 'test' from the element in the tree inserted again after ${afterElement.id}`, grey);
newElement.remove();
testColor(`remove tree div>div after ${afterElement.id}`, grey);
newChild.setAttribute('test_attr', '');
afterElement.after(newElement);
testColor(`insert element div>div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
newElement.remove();
testColor(`remove element div>div[test_attr] after ${afterElement.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(previous_sibling, "grey");
testClassChange(previous_sibling_child, "green");
testClassChange(previous_sibling_descendant, "red");
testClassChange(subject, "blue");
testClassChange(next_sibling, "yellow");
testClassChange(next_sibling_child, "purple");
testClassChange(next_sibling_descendant, "purple");
testElementInsertionBefore(previous_sibling, "grey");
testElementInsertionBefore(previous_sibling_child, "green");
testElementInsertionBefore(previous_sibling_descendant, "red");
testElementInsertionBefore(subject, "blue");
testElementInsertionBefore(next_sibling, "yellow");
testElementInsertionBefore(next_sibling_child, "purple");
testElementInsertionBefore(next_sibling_descendant, "purple");
testElementInsertionAfter(previous_sibling, "blue");
testElementInsertionAfter(previous_sibling_child, "green");
testElementInsertionAfter(previous_sibling_descendant, "red");
testElementInsertionAfter(subject, "yellow");
testElementInsertionAfter(next_sibling, "yellow");
testElementInsertionAfter(next_sibling_child, "purple");
testElementInsertionAfter(next_sibling_descendant, "purple");
testTreeInsertionBefore(previous_sibling, "green");
testTreeInsertionBefore(previous_sibling_child, "red");
testTreeInsertionBefore(previous_sibling_descendant, "red");
testTreeInsertionBefore(subject, "pink");
testTreeInsertionBefore(next_sibling, "purple");
testTreeInsertionBefore(next_sibling_child, "purple");
testTreeInsertionBefore(next_sibling_descendant, "purple");
testTreeInsertionAfter(previous_sibling, "pink");
testTreeInsertionAfter(previous_sibling_child, "red");
testTreeInsertionAfter(previous_sibling_descendant, "red");
testTreeInsertionAfter(subject, "purple");
testTreeInsertionAfter(next_sibling, "purple");
testTreeInsertionAfter(next_sibling_child, "purple");
testTreeInsertionAfter(next_sibling_descendant, "purple");
</script>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has() invalidation after removing non-first element</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#subject:has(descendant) { color: red }
</style>
<main id="main">
<div id="subject">
<div></div>
<descendant id="descendant"></descendant>
</div>
</main>
<script>
let grey = 'rgb(128, 128, 128)';
let red = 'rgb(255, 0, 0)';
function test_div(test_name, el, color) {
test(function() {
assert_equals(getComputedStyle(el).color, color);
}, test_name + ': div#' + el.id + '.color');
}
test_div('initial_color', subject, red);
subject.removeChild(descendant);
test_div('remove descendant', subject, grey);
</script>

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has() invalidation for wiping an element by means of innerHTML</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
.subject:has(.descendant) { color: green}
</style>
<main id=main>
<div id="subject" class="subject"></div>
</main>
<script>
let grey = 'rgb(128, 128, 128)';
let green = 'rgb(0, 128, 0)';
function test_div(test_name, el, color) {
test(function() {
assert_equals(getComputedStyle(el).color, color);
}, test_name + ': div#' + el.id + '.color');
}
test_div('initial color', subject, grey);
subject.innerHTML = "This is a text <div><div class='descendant'></div></div>";
test_div('color after inserting text and div > .descendant', subject, green);
subject.innerHTML = "This is a text";
test_div('color after wiping #child to remove div > .descendant', subject, grey);
subject.innerHTML = "<div id='child'> This is a text <div class='descendant'></div></div>";
test_div('color after inserting text and #child > .descendant', subject, green);
child.innerHTML = "This is a text";
test_div('color after wiping #child to remove .descendant', subject, grey);
</script>

View file

@ -0,0 +1,209 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>:has() invalidation for sibling insertion and removal</title>
<link rel="author" title="Byungwoo Lee" href="mailto:blee@igalia.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#subject1:has(+ #sibling1_1 + #sibling1_2) { color: red }
#subject2:has(+ #sibling2_2) { color: green }
#subject3:has(+ #sibling3_1 + #sibling3_2 > #siblingchild3_2_1) { color: blue }
#subject4:has(+ #sibling4_2 > #siblingchild4_2_1) { color: yellow }
#subject5:has(+ #sibling5_1 + #sibling5_2) { color: red }
#subject6:has(+ #sibling6_2) { color: green }
#subject7:has(+ #sibling7_1 + #sibling7_2 > #siblingchild7_2_1) { color: blue }
#subject8:has(+ #sibling8_2 > #siblingchild8_2_1) { color: yellow }
#subject9:has(+ #sibling9_1 + #sibling9_2 ~ #sibling9_3) { color: red }
#subject10:has(+ #sibling10_2 ~ #sibling10_3) { color: green }
#subject11:has(+ #sibling11_1 + #sibling11_2 ~ #sibling11_3 > #siblingchild11_3_1) { color: blue }
#subject12:has(+ #sibling12_2 ~ #sibling12_3 > #siblingchild12_3_1) { color: yellow }
.sibling13:has(~ .sibling13) { color: green }
#subject14:has(~ #sibling14_1 ~ #sibling14_2 ~ #sibling14_3) { color: green }
</style>
<main id="main">
<div id="parent1">
<div id="subject1"></div>
<div id="sibling1_2"></div>
<div id="sibling1_3"></div>
</div>
<div id="parent2">
<div id="subject2"></div>
<div id="sibling2_1"></div>
<div id="sibling2_2"></div>
<div id="sibling2_3""></div>
</div>
<div id="parent3">
<div id="subject3"></div>
<div id="sibling3_2">
<div id="siblingchild3_2_1"></div>
</div>
<div id="sibling3_3"></div>
</div>
<div id="parent4">
<div id="subject4"></div>
<div id="sibling4_1"></div>
<div id="sibling4_2">
<div id="siblingchild4_2_1"></div>
</div>
<div id="sibling4_3"></div>
</div>
<div id="parent5">
<div id="subject5"></div>
<div id="sibling5_1"></div>
<div id="sibling5_2"></div>
<div id="sibling5_3""></div>
</div>
<div id="parent6">
<div id="subject6"></div>
<div id="sibling6_2"></div>
<div id="sibling6_3"></div>
</div>
<div id="parent7">
<div id="subject7"></div>
<div id="sibling7_1"></div>
<div id="sibling7_2">
<div id="siblingchild7_2_1"></div>
</div>
<div id="sibling7_3"></div>
<div id="parent8">
<div id="subject8"></div>
<div id="sibling8_2">
<div id="siblingchild8_2_1"></div>
</div>
<div id="sibling8_3"></div>
</div>
<div id="parent9">
<div id="subject9"></div>
<div id="sibling9_2"></div>
<div id="sibling9_3"></div>
<div id="sibling9_4"></div>
</div>
<div id="parent10">
<div id="subject10"></div>
<div id="sibling10_1"></div>
<div id="sibling10_2"></div>
<div id="sibling10_3""></div>
<div id="sibling10_4""></div>
</div>
<div id="parent11">
<div id="subject11"></div>
<div id="sibling11_2"></div>
<div id="sibling11_3">
<div id="siblingchild11_3_1"></div>
</div>
<div id="sibling11_4"></div>
</div>
<div id="parent12">
<div id="subject12"></div>
<div id="sibling12_1"></div>
<div id="sibling12_2"></div>
<div id="sibling12_3">
<div id="siblingchild12_3_1"></div>
</div>
<div id="sibling12_4"></div>
</div>
<div id="parent13">
<div class="sibling13"></div>
<div id="subject13" class="sibling13"></div>
</div>
<div id="parent14">
<div id="subject14"></div>
<div id="sibling14_1"></div>
<div id="sibling14_2"></div>
<div id="sibling14_3"></div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
const blue = 'rgb(0, 0, 255)';
const yellow = 'rgb(255, 255, 0)';
function testColor(test_name, element, color) {
test(function() {
assert_equals(getComputedStyle(element).color, color);
}, test_name);
}
function insertBefore(parent, reference, child_id) {
var child = document.createElement("div");
child.id = child_id;
parent.insertBefore(child, reference);
}
testColor(`subject1: initial color should be ${grey}`, subject1, grey);
insertBefore(parent1, sibling1_2, "sibling1_1");
testColor(`subject1: color after #sibling1_1 inserted should be ${red}`,
subject1, red);
testColor(`subject2: initial color should be ${grey}`, subject2, grey);
sibling2_1.remove();
testColor(`subject2: color after #sibling2_1 removed should be ${green}`,
subject2, green);
testColor(`subject3: initial color should be ${grey}`, subject3, grey);
insertBefore(parent3, sibling3_2, "sibling3_1");
testColor(`subject3: color after #sibling3_1 inserted should be ${blue}`,
subject3, blue);
testColor(`subject4: initial color should be ${grey}`, subject4, grey);
sibling4_1.remove();
testColor(`subject4: color after #sibling4_1 removed should be ${yellow}`,
subject4, yellow);
testColor(`subject5: initial color should be ${red}`, subject5, red);
sibling5_1.remove();
testColor(`subject5: color after #sibling5_1 removed should be ${grey}`,
subject5, grey);
testColor(`subject6: initial color should be ${green}`, subject6, green);
insertBefore(parent6, sibling6_2, "sibling6_1");
testColor(`subject6: color after #sibling6_1 inserted should be ${grey}`,
subject6, grey);
testColor(`subject7: initial color should be ${blue}`, subject7, blue);
sibling7_1.remove();
testColor(`subject7: color after #sibling7_1 removed should be ${grey}`,
subject7, grey);
testColor(`subject8: initial color should be ${yellow}`, subject8, yellow);
insertBefore(parent8, sibling8_2, "sibling8_1");
testColor(`subject8: color after #sibling8_1 inserted should be ${grey}`,
subject8, grey);
testColor(`subject9: initial color should be ${grey}`, subject9, grey);
insertBefore(parent9, sibling9_2, "sibling9_1");
testColor(`subject9: color after #sibling9_1 inserted should be ${red}`,
subject1, red);
testColor(`subject10: initial color should be ${grey}`, subject10, grey);
sibling10_1.remove();
testColor(`subject10: color after #sibling10_1 removed should be ${green}`,
subject10, green);
testColor(`subject11: initial color should be ${grey}`, subject11, grey);
insertBefore(parent11, sibling11_2, "sibling11_1");
testColor(`subject11: color after #sibling11_1 inserted should be ${blue}`,
subject11, blue);
testColor(`subject12: initial color should be ${grey}`, subject12, grey);
sibling12_1.remove();
testColor(`subject12: color after #sibling12_1 removed should be ${yellow}`,
subject12, yellow);
testColor(`subject13: initial color should be ${grey}`, subject13, grey);
const d = document.createElement("div");
d.classList.add("sibling13");
parent13.appendChild(d);
testColor(`subject13: color after #sibling12_1 removed should be ${green}`,
subject13, green);
testColor(`subject14: initial color should be ${green}`, subject14, green);
sibling14_2.remove();
testColor(`subject14: color after #sibling14_2 removed should be ${grey}`, subject14, grey);
</script>

View file

@ -0,0 +1,149 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() with sibling combinator argument</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#subject:has(~ .test) { color: red }
#subject:has(+ .test) { color: green }
#subject:has(~ div .test) { color: blue }
#subject:has(~ div > .test) { color: purple }
#subject:has(+ div .test) { color: yellow }
#subject:has(+ div > .test) { color: pink }
</style>
<main id=main>
<div id=subject></div>
<div id=first_sibling>
<div id=first_sibling_child>
<div id=first_sibling_descendant></div>
</div>
</div>
<div id=second_sibling></div>
<div id=third_sibling>
<div id=third_sibling_child>
<div id=third_sibling_descendant></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
const blue = 'rgb(0, 0, 255)';
const yellow = 'rgb(255, 255, 0)';
const purple = 'rgb(128, 0, 128)';
const pink = 'rgb(255, 192, 203)';
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColor)
{
element.classList.add('test');
testColor(`add .test to ${element.id}`, expectedColor);
element.classList.remove('test');
testColor(`remove .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColor)
{
const newElement = document.createElement('div');
newElement.classList.add('test')
beforeElement.before(newElement);
testColor(`insert element div.test before ${beforeElement.id}`, expectedColor);
newElement.remove();
testColor(`remove element div.test before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColor)
{
const newElement = document.createElement('div');
newElement.classList.add('test')
afterElement.after(newElement);
testColor(`insert element div.test after ${afterElement.id}`, expectedColor);
newElement.remove();
testColor(`remove element div.test after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColor)
{
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColor);
newElement.remove();
testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColor)
{
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newChild.classList.add('test');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColor);
newElement.remove();
testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
}
testColor('initial_color', grey);
testClassChange(first_sibling, green);
testClassChange(second_sibling, red);
testClassChange(third_sibling, red);
testClassChange(first_sibling_child, pink);
testClassChange(first_sibling_descendant, yellow);
testClassChange(third_sibling_child, purple);
testClassChange(third_sibling_descendant, blue);
testElementInsertionBefore(first_sibling, green);
testElementInsertionBefore(second_sibling, red);
testElementInsertionBefore(third_sibling, red);
testElementInsertionBefore(first_sibling_child, pink);
testElementInsertionBefore(first_sibling_descendant, yellow);
testElementInsertionBefore(third_sibling_child, purple);
testElementInsertionBefore(third_sibling_descendant, blue);
testElementInsertionAfter(first_sibling, red);
testElementInsertionAfter(second_sibling, red);
testElementInsertionAfter(third_sibling, red);
testElementInsertionAfter(first_sibling_child, pink);
testElementInsertionAfter(first_sibling_descendant, yellow);
testElementInsertionAfter(third_sibling_child, purple);
testElementInsertionAfter(third_sibling_descendant, blue);
testTreeInsertionBefore(first_sibling, pink);
testTreeInsertionBefore(second_sibling, purple);
testTreeInsertionBefore(third_sibling, purple);
testTreeInsertionBefore(first_sibling_child, yellow);
testTreeInsertionBefore(first_sibling_descendant, yellow);
testTreeInsertionBefore(third_sibling_child, blue);
testTreeInsertionBefore(third_sibling_descendant, blue);
testTreeInsertionAfter(first_sibling, purple);
testTreeInsertionAfter(second_sibling, purple);
testTreeInsertionAfter(third_sibling, purple);
testTreeInsertionAfter(first_sibling_child, yellow);
testTreeInsertionAfter(first_sibling_descendant, yellow);
testTreeInsertionAfter(third_sibling_child, blue);
testTreeInsertionAfter(third_sibling_descendant, blue);
</script>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: Invalidate :has() as result of insertion/removal</title>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#subject:has(+ #next_sibling) { color: red; }
#prev_sibling:has(+ #subject + #next_sibling) { color: green; }
</style>
<main id=main>
<div id=prev_sibling></div>
<div id=subject></div>
<div id=blocks_match></div>
<div id=next_sibling></div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
function testColors(test_name, subject_color, prev_sibling_color) {
test(function() {
assert_equals(getComputedStyle(subject).color, subject_color);
assert_equals(getComputedStyle(prev_sibling).color, prev_sibling_color);
}, test_name);
}
testColors('Initial colors', grey, grey);
const d = blocks_match;
d.remove();
testColors('Matches after #blocks_match removed', red, green);
subject.after(d);
testColors('Does not match after #blocks_match added', grey, grey);
</script>

View file

@ -0,0 +1,77 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() affected by unstyled elements</title>
<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
.none { display: none; }
#subject:has(.test) { color: red; }
#subject:has(~ #sibling .test) { color: green; }
#subject:has(:is(.test_inner #subject_descendant)) { color: blue; }
#subject:has(~ #sibling :is(.test_inner #sibling_descendant)) { color: yellow; }
</style>
<main id=main>
<div id=subject>
<div id=subject_child class="none">
<div id=subject_descendant></div>
</div>
</div>
<div id=sibling class="none">
<div id=sibling_child>
<div id=sibling_descendant></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
const blue = 'rgb(0, 0, 255)';
const yellow = "rgb(255, 255, 0)";
const colors = {
grey: {
classTest: grey,
},
red: {
classTest: red,
},
green: {
classTest: green,
},
blue: {
classTest: blue,
},
yellow: {
classTest: yellow,
},
};
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, cls, expectedColorName)
{
const expectedColorForClassTest = colors[expectedColorName].classTest;
element.classList.add(cls);
testColor(`add ${cls} to ${element.id}`, expectedColorForClassTest);
element.classList.remove(cls);
testColor(`remove ${cls} from ${element.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(subject_descendant, 'test', 'red');
testClassChange(sibling_descendant, 'test', 'green');
testClassChange(subject_child, 'test_inner', 'blue');
testClassChange(sibling_child, 'test_inner', 'yellow');
</script>

View file

@ -0,0 +1,158 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() with nesting parent containing complex selector</title>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/testdriver.js"></script>
<script src="../../../resources/testdriver-actions.js"></script>
<script src="../../../resources/testdriver-vendor.js"></script>
<style>
.anchor { background-color: white; }
.ancestor .descendant {
.anchor:has(&) { background-color: blue; }
}
.ancestor .child {
.anchor:has(> &) { background-color: lightblue; }
}
.ancestor_prev ~ div .descendant {
.anchor:has(&) { background-color: yellow; }
}
.ancestor_prev ~ div.ancestor .descendant {
.anchor:has(&) { background-color: yellowgreen; }
}
.prev ~ .indirect_next {
.anchor:has(~ &) { background-color: green; }
}
.prev ~ .direct_next {
.anchor:has(+ &) { background-color: lightgreen; }
}
</style>
<div><div id="grand_parent1">
<div id="parent1">
<div id="anchor1" class="anchor">
<div><div class="descendant"></div></div>
</div>
</div>
</div></div>
<div><div id="grand_parent2">
<div id="parent2">
<div id="anchor2" class="anchor">
<div class="child"></div>
</div>
</div>
</div></div>
<div><div id="grand_parent_indirect_prev3"></div>
<div id="grand_parent_direct_prev3"></div>
<div id="grand_parent3">
<div id="parent_indirect_prev3"></div>
<div id="parent_direct_prev3"></div>
<div id="parent3">
<div id="anchor_indirect_prev3"></div>
<div id="anchor_direct_prev3"></div>
<div id="anchor3" class="anchor">
<div><div class="descendant"></div></div>
</div>
</div>
</div></div>
<div><div id="indirect_prev4"></div>
<div id="direct_prev4"></div>
<div id="anchor4" class="anchor"></div>
<div></div><div class="indirect_next">
</div></div>
<div><div id="indirect_prev5"></div>
<div id="direct_prev5"></div>
<div id="anchor5" class="anchor"></div>
<div class="direct_next">
</div></div>
<script>
const white = "rgb(255, 255, 255)";
const blue = "rgb(0, 0, 255)";
const lightblue = "rgb(173, 216, 230)";
const yellow = "rgb(255, 255, 0)";
const yellowgreen = "rgb(154, 205, 50)";
const green = "rgb(0, 128, 0)";
const lightgreen = "rgb(144, 238, 144)";
function bg_color(element, color, message) {
promise_test(async () => {
assert_equals(getComputedStyle(element)['background-color'], color);
}, message);
}
function add_class_and_check_bg_color(
element_to_add, class_name, has_anchor, color) {
promise_test(async () => {
element_to_add.classList.add(class_name);
assert_equals(getComputedStyle(has_anchor)['background-color'], color);
}, `#${has_anchor.id} becomes ${color} after adding .${class_name} to #${element_to_add.id}`);
}
function remove_class_and_check_bg_color(
element_to_remove, class_name, has_anchor, color) {
promise_test(async () => {
element_to_remove.classList.remove(class_name);
assert_equals(getComputedStyle(has_anchor)['background-color'], color);
}, `#${has_anchor.id} becomes ${color} after removing .${class_name} from #${element_to_remove.id}`);
}
bg_color(anchor1, white, "#anchor1 initially white");
add_class_and_check_bg_color(grand_parent1, "ancestor", anchor1, blue);
remove_class_and_check_bg_color(grand_parent1, "ancestor", anchor1, white);
add_class_and_check_bg_color(parent1, "ancestor", anchor1, blue);
remove_class_and_check_bg_color(parent1, "ancestor", anchor1, white);
bg_color(anchor2, white, "#anchor2 initially white");
add_class_and_check_bg_color(grand_parent2, "ancestor", anchor2, lightblue);
remove_class_and_check_bg_color(grand_parent2, "ancestor", anchor2, white);
add_class_and_check_bg_color(parent2, "ancestor", anchor2, lightblue);
remove_class_and_check_bg_color(parent2, "ancestor", anchor2, white);
bg_color(anchor3, white, "#anchor3 initially white");
add_class_and_check_bg_color(grand_parent_indirect_prev3, "ancestor_prev",
anchor3, yellow);
add_class_and_check_bg_color(grand_parent3, "ancestor", anchor3, yellowgreen);
remove_class_and_check_bg_color(grand_parent3, "ancestor", anchor3, yellow);
remove_class_and_check_bg_color(grand_parent_indirect_prev3, "ancestor_prev",
anchor3, white);
add_class_and_check_bg_color(grand_parent_direct_prev3, "ancestor_prev",
anchor3, yellow);
remove_class_and_check_bg_color(grand_parent_direct_prev3, "ancestor_prev",
anchor3, white);
add_class_and_check_bg_color(parent_indirect_prev3, "ancestor_prev",
anchor3, yellow);
add_class_and_check_bg_color(parent3, "ancestor", anchor3, yellowgreen);
remove_class_and_check_bg_color(parent3, "ancestor", anchor3, yellow);
remove_class_and_check_bg_color(parent_indirect_prev3, "ancestor_prev",
anchor3, white);
add_class_and_check_bg_color(parent_direct_prev3, "ancestor_prev",
anchor3, yellow);
remove_class_and_check_bg_color(parent_direct_prev3, "ancestor_prev",
anchor3, white);
add_class_and_check_bg_color(anchor_indirect_prev3, "ancestor_prev",
anchor3, yellow);
remove_class_and_check_bg_color(anchor_indirect_prev3, "ancestor_prev",
anchor3, white);
add_class_and_check_bg_color(anchor_direct_prev3, "ancestor_prev",
anchor3, yellow);
remove_class_and_check_bg_color(anchor_direct_prev3, "ancestor_prev",
anchor3, white);
bg_color(anchor4, white, "#anchor4 initially white");
add_class_and_check_bg_color(indirect_prev4, "prev", anchor4, green);
remove_class_and_check_bg_color(indirect_prev4, "prev", anchor4, white);
add_class_and_check_bg_color(direct_prev4, "prev", anchor4, green);
remove_class_and_check_bg_color(direct_prev4, "prev", anchor4, white);
bg_color(anchor5, white, "#anchor5 initially white");
add_class_and_check_bg_color(indirect_prev5, "prev", anchor5, lightgreen);
remove_class_and_check_bg_color(indirect_prev5, "prev", anchor5, white);
add_class_and_check_bg_color(direct_prev5, "prev", anchor5, lightgreen);
remove_class_and_check_bg_color(direct_prev5, "prev", anchor5, white);
</script>

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() with nesting parent containing :hover</title>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/testdriver.js"></script>
<script src="../../../resources/testdriver-actions.js"></script>
<script src="../../../resources/testdriver-vendor.js"></script>
<style>
dd, dt { background: white; }
dd:hover {
dt:has(~ &) { background: lime; }
}
</style>
<dt id=dt1>#dt1</dt>
<dd id=dd1>#dd1, Hover me, the DT above should go lime</dd>
<dt id=dt2>#dt2</dt>
<dd id=dd2>#dd2, Hover me, both DTs above should go lime</dd>
<script>
const white = 'rgb(255, 255, 255)';
const lime = 'rgb(0, 255, 0)';
function bg_color(element, color, message) {
assert_equals(getComputedStyle(element)['background-color'], color, message);
}
promise_test(async () => {
bg_color(dt1, white, "#dt1 initially white");
bg_color(dd1, white, "#dd1 initially white");
bg_color(dt2, white, "#dt2 initially white");
bg_color(dd2, white, "#dd2 initially white");
await new test_driver.Actions().pointerMove(0, 0, {origin: dd1}).send();
bg_color(dt1, lime, "#dt1 should go lime when hover #dd1");
bg_color(dd1, white, "#dd1 doesn't change when hover #dd1");
bg_color(dt2, white, "#dt2 doesn't change when hover #dd1");
bg_color(dd2, white, "#dd2 doesn't change when hover #dd1");
await new test_driver.Actions().pointerMove(0, 0, {origin: dt1}).send();
bg_color(dt1, white, "#dt1 should go white when hover #dt2");
bg_color(dd1, white, "#dd1 doesn't change when hover #dt2");
bg_color(dt2, white, "#dt2 doesn't change when hover #dt2");
bg_color(dd2, white, "#dd2 doesn't change when hover #dt2");
await new test_driver.Actions().pointerMove(0, 0, {origin: dd2}).send();
bg_color(dt1, lime, "#dt1 should go lime when hover #dd2");
bg_color(dd1, white, "#dd1 doesn't change when hover #dd2");
bg_color(dt2, lime, "#dt2 should go lime when hover #dd2");
bg_color(dd2, white, "#dd2 doesn't change when hover #dd2");
});
</script>

View file

@ -0,0 +1,107 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() with :not()</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
div, main { color: grey }
#subject:has(:not(.test)) { color: green }
#subject:has(.test :not(.test)) { color: red }
</style>
<main id=main>
<div id=subject>
<div id=subject_child class=test>
<div id=subject_descendant class=test></div>
</div>
</div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
const blue = 'rgb(0, 0, 255)';
function testColor(test_name, color) {
test(function() {
assert_equals(getComputedStyle(subject).color, color);
}, test_name);
}
function testClassChange(element, expectedColor)
{
element.classList.remove('test');
testColor(`remove .test to ${element.id}`, expectedColor);
element.classList.add('test');
testColor(`add .test from ${element.id}`, grey);
}
function testElementInsertionBefore(beforeElement, expectedColor)
{
const newElement = document.createElement('div');
beforeElement.before(newElement);
testColor(`insert element div before ${beforeElement.id}`, expectedColor);
newElement.remove();
testColor(`remove element div before ${beforeElement.id}`, grey);
}
function testElementInsertionAfter(afterElement, expectedColor)
{
const newElement = document.createElement('div');
afterElement.after(newElement);
testColor(`insert element div after ${afterElement.id}`, expectedColor);
newElement.remove();
testColor(`remove element div after ${afterElement.id}`, grey);
}
function testTreeInsertionBefore(beforeElement, expectedColor)
{
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newElement.appendChild(newChild);
beforeElement.before(newElement);
testColor(`insert tree div>div before ${beforeElement.id}`, expectedColor);
newElement.remove();
testColor(`remove tree div>div before ${beforeElement.id}`, grey);
}
function testTreeInsertionAfter(afterElement, expectedColor)
{
const newElement = document.createElement('div');
const newChild = document.createElement('div');
newElement.appendChild(newChild);
afterElement.after(newElement);
testColor(`insert tree div.test after ${afterElement.id}`, expectedColor);
newElement.remove();
testColor(`remove tree div.test after ${afterElement.id}`, grey);
}
testColor('Initial color', grey);
testClassChange(subject_child, green);
testClassChange(subject_descendant, red);
testElementInsertionBefore(subject_child, green);
testElementInsertionBefore(subject_descendant, red);
testElementInsertionAfter(subject_child, green);
testElementInsertionAfter(subject_descendant, red);
testTreeInsertionBefore(subject_child, green);
testTreeInsertionBefore(subject_descendant, red);
testTreeInsertionAfter(subject_child, green);
testTreeInsertionAfter(subject_descendant, red);
</script>

View file

@ -0,0 +1,67 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selectors Test: :has(:nth-child()) invalidation for sibling change</title>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
#test-container > div { background-color: green; }
#target1:has(.item:nth-child(3)) { background-color: red; }
#target2:has(.item:nth-last-child(3)) { background-color: red; }
#target3:has(.item:nth-child(3) > .child) { background-color: red; }
#target4:has(.item:nth-last-child(3) > .child) { background-color: red; }
</style>
<div id="test-container">
<div id="target1">
<div class="item" id="item1">FAIL if you see this text</div>
<div class="item"></div>
<div class="item">This text should have a green background</div>
</div>
<div id="target2">
<div class="item">This text should have a green background</div>
<div class="item"></div>
<div class="item" id="item2">FAIL if you see this text</div>
</div>
<div id="target3">
<div class="item" id="item3">FAIL if you see this text</div>
<div class="item"></div>
<div class="item">
<span class="child">This text should have a green background<span>
</div>
</div>
<div id="target4">
<div class="item">
<span class="child">This text should have a green background<span>
</div>
<div class="item"></div>
<div class="item" id="item4">FAIL if you see this text</div>
</div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(target1).backgroundColor, "rgb(255, 0, 0)");
assert_equals(getComputedStyle(target2).backgroundColor, "rgb(255, 0, 0)");
assert_equals(getComputedStyle(target3).backgroundColor, "rgb(255, 0, 0)");
assert_equals(getComputedStyle(target4).backgroundColor, "rgb(255, 0, 0)");
}, "Initially red");
test(() => {
item1.remove();
assert_equals(getComputedStyle(target1).backgroundColor, "rgb(0, 128, 0)");
}, ":nth-child() no longer matching after removal");
test(() => {
item2.remove();
assert_equals(getComputedStyle(target2).backgroundColor, "rgb(0, 128, 0)");
}, ":nth-last-child() no longer matching after removal");
test(() => {
item3.remove();
assert_equals(getComputedStyle(target3).backgroundColor, "rgb(0, 128, 0)");
}, ":nth-child() in non-subject no longer matching after removal");
test(() => {
item4.remove();
assert_equals(getComputedStyle(target4).backgroundColor, "rgb(0, 128, 0)");
}, ":nth-last-child() in non-subject no longer matching after removal");
</script>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Selector Invalidation: :has() with pseudo-classes</title>
<link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
<style>
main:has(input) div { color: grey }
main:has(#checkbox:checked) > #subject { color: red }
main:has(#option:checked) > #subject { color: red }
main:has(#checkbox:disabled) > #subject { color: green }
main:has(#option:disabled) > :is(#subject, #subject2) { color: green }
main:has(#optgroup:disabled) > #subject { color: blue }
main:not(:has(#checkbox:enabled)) > #subject3 { color: green }
main:not(:has(#option:enabled)) :is(#subject3, #subject4) { color: green }
main:not(:has(#optgroup:enabled)) > #subject3 { color: blue }
main:has(#text_input:valid) > #subject { color: yellow }
main:not(:has(#text_input:invalid)) > #subject2 { color: yellow }
main:has(#form:valid) > #subject3 { color: yellow }
main:not(:has(#form:invalid)) > #subject4 { color: yellow }
</style>
<main id=main>
<form id=form>
<input type=checkbox id=checkbox></input>
<select id=select><optgroup id=optgroup><option>a</option><option id=option>b</option></optgroup></select>
<input id=text_input type=text required></input>
</form>
<div id=subject></div>
<div id=subject2></div>
<div id=subject3></div>
<div id=subject4></div>
</main>
<script>
const grey = 'rgb(128, 128, 128)';
const red = 'rgb(255, 0, 0)';
const green = 'rgb(0, 128, 0)';
const blue = 'rgb(0, 0, 255)';
const yellow = 'rgb(255, 255, 0)';
const purple = 'rgb(128, 0, 128)';
const pink = 'rgb(255, 192, 203)';
function testColor(test_name, subject_element, color) {
test(function() {
assert_equals(getComputedStyle(subject_element).color, color);
}, test_name);
}
function testPseudoClassChange(element, property, subject_element, expectedColor)
{
testColor(`Before set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
element[property] = true;
testColor(`Set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, expectedColor);
element[property] = false;
testColor(`Unset ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
}
function testSelectedChange(option, subject_element, expectedColor)
{
const oldOption = select.selectedOptions[0];
option.selected = true;
testColor(`Set select on ${option.id}`, subject_element, expectedColor);
oldOption.selected = true;
testColor(`Reset select`, subject, grey);
}
function testValueChange(input, subject_element, expectedColor)
{
testColor(`Before setting value of ${input.id}, testing ${subject_element.id}`, subject_element, grey);
input.value = "value";
testColor(`Set value of ${input.id}, testing ${subject_element.id}`, subject_element, expectedColor);
input.value = "";
testColor(`Clear value of ${input.id}, testing ${subject_element.id}`, subject_element, grey);
}
testPseudoClassChange(checkbox, "checked", subject, red);
testSelectedChange(option, subject, red);
testPseudoClassChange(checkbox, "disabled", subject, green);
testPseudoClassChange(checkbox, "disabled", subject3, green);
testPseudoClassChange(option, "disabled", subject, green);
testPseudoClassChange(option, "disabled", subject3, green);
testPseudoClassChange(optgroup, "disabled", subject, blue);
testPseudoClassChange(optgroup, "disabled", subject2, green);
testPseudoClassChange(optgroup, "disabled", subject3, blue);
testPseudoClassChange(optgroup, "disabled", subject4, green);
testValueChange(text_input, subject, yellow);
testValueChange(text_input, subject2, yellow);
testValueChange(text_input, subject3, yellow);
testValueChange(text_input, subject4, yellow);
</script>