Files
sousa-gecko/testing/web-platform/tests/css/selectors/toplayer-transition-001.html
T
Mason Freed 0cad86c633 Bug 2028820 [wpt PR 58932] - Fix user action pseudo-classes when elements enter/exit top layer, a=testonly
Automatic update from web-platform-tests
Fix user action pseudo-classes when elements enter/exit top layer

This behavior was recently changed, in [1]. When an element enters or
exits the top layer, its ancestor chain for user action pseudo-classes
(:hover, :focus-within, and :active) needs to be re-evaluated. This is
because the tree traversal used to propagate these states stops at the
top layer. Thus, ancestors might need their state cleared when the
element enters the top layer, or applied when it exits.

Additionally, a requestAnimationFrame is added to the related WPT test
(toplayer-transition-001.html) since hidePopover style invalidations
require a frame to fully resolve before the pseudo-classes update
correctly.

[1] https://crrev.com/c/7683005

Fixed: 496700727
Change-Id: I8370db87780ce6f3f6034d87487994ec197ddebc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7709256
Commit-Queue: Mason Freed <masonf@chromium.org>
Reviewed-by: David Baron <dbaron@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1608927}

--

wpt-commits: 2ba865f94c2666ba9b8209e36ec60181fcec42bf
wpt-pr: 58932
2026-04-17 08:36:16 +00:00

68 lines
3.3 KiB
HTML

<!DOCTYPE html>
<meta charset="utf-8">
<title>Selectors: top layer transitions should adjust pseudo-classes on ancestors</title>
<link rel="help" href="https://drafts.csswg.org/selectors/#the-hover-pseudo">
<link rel="help" href="https://drafts.csswg.org/selectors/#the-focus-within-pseudo">
<link rel="help" href="https://drafts.csswg.org/css-position-4/#top-layer">
<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>
[popover] { display: block; }
</style>
<div id="container">
<div id="popover" popover="manual">
<input id="input">
<div id="hoverTarget">hover here</div>
</div>
</div>
<script>
promise_test(async t => {
t.add_cleanup(() => { if (popover.matches(':popover-open')) popover.hidePopover(); });
input.focus();
assert_true(input.matches(':focus'), 'input should be focused');
assert_true(container.matches(':focus-within'), 'container should match :focus-within before showPopover');
popover.showPopover();
assert_true(input.matches(':focus'), 'input should still be focused after showPopover');
assert_true(popover.matches(':focus-within'), 'popover should match :focus-within after showPopover');
assert_false(container.matches(':focus-within'), 'container should not match :focus-within after showPopover');
assert_false(document.body.matches(':focus-within'), 'body should not match :focus-within after showPopover');
popover.hidePopover();
await new Promise(requestAnimationFrame);
assert_true(input.matches(':focus'), 'input should still be focused after hidePopover');
assert_true(container.matches(':focus-within'), 'container should match :focus-within after hidePopover');
assert_true(document.body.matches(':focus-within'), 'body should match :focus-within after hidePopover');
}, ':focus-within should be adjusted on ancestors when popover enters/exits top layer.');
promise_test(async t => {
t.add_cleanup(() => { if (popover.matches(':popover-open')) popover.hidePopover(); });
await new test_driver.Actions()
.pointerMove(1, 1, {origin: hoverTarget})
.send();
await new Promise(requestAnimationFrame);
assert_true(hoverTarget.matches(':hover'), 'hoverTarget should match :hover');
assert_true(container.matches(':hover'), 'container should match :hover before showPopover');
popover.showPopover();
assert_true(hoverTarget.matches(':hover'), 'hoverTarget should still match :hover after showPopover');
assert_true(popover.matches(':hover'), 'popover should match :hover after showPopover');
assert_false(container.matches(':hover'), 'container should not match :hover after showPopover');
assert_false(document.body.matches(':hover'), 'body should not match :hover after showPopover');
popover.hidePopover();
await new Promise(requestAnimationFrame);
assert_true(hoverTarget.matches(':hover'), 'hoverTarget should still match :hover after hidePopover');
assert_true(container.matches(':hover'), 'container should match :hover after hidePopover');
assert_true(document.body.matches(':hover'), 'body should match :hover after hidePopover');
}, ':hover should be adjusted on ancestors when popover enters/exits top layer.');
</script>