Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<meta charset="utf-8" />
<title>CSS Selectors Invalidation: user-action pseudo classes in :has() argument</title>
<link rel="author" title="Byungwoo Lee" href="blee@igalia.com">
<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>
.ancestor:has(.descendant1:hover) { color: blue }
.ancestor:has(.descendant1:hover) .other-descendant { color: navy }
.ancestor:has(.descendant1:hover:active) { color: skyblue }
.ancestor:has(.descendant1:hover:active) .other-descendant { color: lightblue }
.ancestor:has(:focus) { color: green }
.ancestor:has(:focus) .other-descendant { color: darkgreen }
.ancestor:has(.descendant2:focus-visible) { color: yellowgreen }
.ancestor:has(.descendant2:focus-visible) .other-descendant { color: greenyellow }
.ancestor:has(.descendant3:focus-within) { color: lightgreen }
.ancestor:has(.descendant3:focus-within) .other-descendant { color: violet }
</style>
<div id=subject1 class=ancestor>
<div>
<div id=unhoverme>No :hover</div>
<div id=hoverme class=descendant1>Hover and click me</div>
<div id=focusme1 tabindex=1>Focus me</div>
<div id=focusme2 class=descendant2 tabindex=2>Focus me</div>
<div class=descendant3>
<div><div id=focusme3 tabindex=3>Focus me</div></div>
</div>
</div>
<div><div id=subject3 class=other-descendant>subject</div></div>
</div>
<div id=subject2 class=ancestor>
<div id=focusme4 tabindex=4>Focus me</div>
<div><div id=subject4 class=other-descendant>subject</div></div>
</div>
<script>
const tab_key = '\ue004';
promise_test(async () => {
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)", "subject1 initially black");
assert_equals(getComputedStyle(subject2).color, "rgb(0, 0, 0)", "subject3 initially black");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 255)",
"subject1 should be blue");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 128)",
"subject3 should be navy");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: unhoverme})
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)",
"subject1 should be back to black");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 0)",
"subject3 should be back to black");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.pointerDown()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(135, 206, 235)",
"subject1 should be skyblue");
assert_equals(getComputedStyle(subject3).color, "rgb(173, 216, 230)",
"subject3 should be lightblue");
// Clean up `pointerDown` from above. We want to test invalidation from
// `:hover:active` to `:hover`, but there's no guarantee that pointer
// state will stay the same between actions.
await new test_driver
.Actions()
.pointerUp()
.pointerMove(0, 0, {origin: unhoverme})
.send();
// Perform the entire activation chain again, then perform `pointerUp`.
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: hoverme})
.pointerDown()
.pointerUp()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 255)",
"subject1 should be blue");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 128)",
"subject3 should be navy");
await new test_driver
.Actions()
.pointerMove(0, 0, {origin: focusme1})
.pointerDown()
.pointerUp()
.send();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 128, 0)",
"subject1 should be green");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 100, 0)",
"subject3 should be darkgreen");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject1).color, "rgb(154, 205, 50)",
"subject1 should be yellowgreen");
assert_equals(getComputedStyle(subject3).color, "rgb(173, 255, 47)",
"subject3 should be greenyellow");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject1).color, "rgb(144, 238, 144)",
"subject1 should be lightgreen");
assert_equals(getComputedStyle(subject3).color, "rgb(238, 130, 238)",
"subject3 should be violet");
focusme3.remove();
assert_equals(getComputedStyle(subject1).color, "rgb(0, 0, 0)",
"subject1 should be black");
assert_equals(getComputedStyle(subject3).color, "rgb(0, 0, 0)",
"subject3 should be black");
await test_driver.send_keys(document.body, tab_key);
assert_equals(getComputedStyle(subject2).color, "rgb(0, 128, 0)",
"subject2 should be green");
assert_equals(getComputedStyle(subject4).color, "rgb(0, 100, 0)",
"subject4 should be darkgreen");
focusme4.remove();
assert_equals(getComputedStyle(subject2).color, "rgb(0, 0, 0)",
"subject2 should be black");
assert_equals(getComputedStyle(subject4).color, "rgb(0, 0, 0)",
"subject4 should be black");
});
</script>