Files
sousa-gecko/testing/web-platform/tests/event-timing/target-selector.tentative.html
T
Michal Mocny cd02eae79d Bug 2022513 [wpt PR 58408] - [event-timing]: Replace RawTarget() with target(), and use EventPath., a=testonly
Automatic update from web-platform-tests
[event-timing]: Replace RawTarget() with target(), and use EventPath.

Previously, Event Timing used event.RawTarget() to capture the
EventTarget as early as possible. While this reduced the chances of a
null target, it was overly aggressive and could report internal targets
not exposed to the web.

This change aligns the Event Timing API with what is reported to
developers by using event.target() at the end of event processing. This
ensures only web-exposed targets are reported.

A consequence of this change is that event.target() may be null more
often (e.g., for events where dispatch is skipped). To mitigate this and
provide a more robust identifier, this CL refines an existing
experimental addition to EventTiming: targetSelector. Support has
already been added to the specification and tentative WPT exist.

This CL also changes to generate this value from the event's propagation
path (EventPath), rather than from the target(), which may be
unavailable as EventPath is often available even when event.target() is
null.

Bug: 447111342, 452637511, 40887145
Change-Id: I4ec185b72ed86afe4250cd8c93c0973e6a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7617568
Reviewed-by: Scott Haseley <shaseley@chromium.org>
Commit-Queue: Michal Mocny <mmocny@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1597277}

--

wpt-commits: 4773722b338c62e6e259e3ecb12903e275e483b7
wpt-pr: 58408
2026-03-16 10:11:15 +00:00

89 lines
3.5 KiB
HTML

<!DOCTYPE html>
<html>
<meta charset=utf-8 />
<meta name="timeout" content="long">
<title>Event Timing targetSelector.</title>
<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>
<script src=resources/event-timing-test-utils.js></script>
<div id='div-with-id'>Target with ID</div>
<div>Target without ID</div>
<img id='img-with-id-and-src' src='/images/blue.png'>
<img src='/images/green.png'>
<script>
function runTest(t, eventType, target) {
let entry;
const callback = (entryList) => {
const entries = entryList.getEntriesByName(eventType);
if (entries.length > 0) {
entry = entries[0];
}
};
const readyToResolve = () => !!entry;
const observerPromise = createPerformanceObserverPromise(['event'], callback, readyToResolve);
return interactAndObserve(eventType, target, observerPromise)
.then(() => {
assert_equals(entry.name, eventType);
assert_equals(entry.entryType, 'event');
assert_equals(entry.target, target);
assert_true(!!entry.targetSelector, "targetSelector should not be empty");
// The new format is a path (e.g. "BODY > DIV:nth-child(1)").
// It should be a valid querySelector that includes our target.
const matchingElements = document.querySelectorAll(entry.targetSelector);
assert_true(Array.from(matchingElements).includes(target),
`Selector "${entry.targetSelector}" should match the target element`);
});
}
promise_test(async t => {
// Element with tagName and id.
return runTest(t, 'click', document.getElementById('div-with-id'));
}, "Test with target that has an ID");
promise_test(async t => {
// Element with tagName only.
return runTest(t, 'click', document.querySelector('div:not([id])'));
}, "Test with simple target (no id)");
promise_test(async t => {
// Element with tagName, id, and src.
return runTest(t, 'click', document.getElementById('img-with-id-and-src'));
}, "Test with image target with id and src");
promise_test(async t => {
// Element with tagName and src.
return runTest(t, 'click', document.querySelector('img:not([id])'));
}, "Test with image target with src only");
promise_test(async t => {
let entry;
const callback = (entryList) => {
const entries = entryList.getEntriesByName('click');
if (entries.length > 0) {
entry = entries[0];
}
};
const readyToResolve = () => !!entry;
const observerPromise = createPerformanceObserverPromise(['event'], callback, readyToResolve);
const parent = document.body;
const target = document.createElement('button');
target.id = 'temp-target';
target.textContent = 'Click Me';
parent.appendChild(target);
await interactAndObserve('click', target, observerPromise);
// The new format is a path, but it should still end with or contain the ID.
const selector = entry.targetSelector;
assert_true(selector.includes('BUTTON#temp-target'),
`Selector "${selector}" should contain BUTTON#temp-target`);
parent.removeChild(target);
// The garbage collector might need some time to collect |target|.
await new Promise(r => t.step_timeout(r, 0));
assert_equals(entry.target, null);
assert_equals(entry.targetSelector, selector);
}, "Test with disconnected target");
</script>
</html>