Skip to content

Commit 2670e5c

Browse files
authored
fix(page): collect DOM elements retained by locator hit-target interceptor (#41575)
1 parent b635709 commit 2670e5c

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

packages/injected/src/injectedScript.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,7 @@ export class InjectedScript {
11151115
}[action];
11161116
let result: 'done' | { hitTargetDescription: string } | undefined;
11171117

1118-
const listener = (event: PointerEvent | MouseEvent | TouchEvent) => {
1118+
let listener: ((event: PointerEvent | MouseEvent | TouchEvent) => void) | undefined = (event: PointerEvent | MouseEvent | TouchEvent) => {
11191119
// Ignore events that we do not expect to intercept.
11201120
if (!events.has(event.type))
11211121
return;
@@ -1144,6 +1144,7 @@ export class InjectedScript {
11441144
const stop = () => {
11451145
if (this._hitTargetInterceptor === listener)
11461146
this._hitTargetInterceptor = undefined;
1147+
listener = undefined;
11471148
// If we did not get any events, consider things working. Possible causes:
11481149
// - JavaScript is disabled (webkit-only).
11491150
// - Some <iframe> overlays the element from another frame.

tests/page/page-request-gc.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,16 @@ test('should work', async ({ page }) => {
3232
await page.requestGC();
3333
expect(await page.evaluate(() => globalThis.weakRef.deref())).toBe(undefined);
3434
});
35+
36+
test('should collect element retained by locator hit-target interceptor after detach', async ({ page, browserName }) => {
37+
test.fixme(browserName === 'firefox', 'Firefox hit-target interceptor does not release its element reference on detach');
38+
test.fixme(browserName === 'chromium', 'Chromium retains a native reference to the last hit-tested element; fix pending upstream discussion, see #41575');
39+
await page.setContent('<button id="btn">click me</button>');
40+
await page.locator('#btn').click();
41+
await page.evaluate(() => {
42+
globalThis.weakRef = new WeakRef(document.getElementById('btn')!);
43+
document.getElementById('btn')!.remove();
44+
});
45+
await page.requestGC();
46+
expect(await page.evaluate(() => globalThis.weakRef.deref())).toBe(undefined);
47+
});

0 commit comments

Comments
 (0)