Repository navigation
[Bug]: Firefox delivers other pages' mouse events to a page that captured the pointer #43631
Description
Version
1.64.1
Steps to reproduce
import { chromium, firefox, webkit } from 'playwright';
const logEvents = `
window.events = [];
for (const type of ['pointerdown', 'pointerup', 'click']) {
document.addEventListener(type, () => window.events.push(type));
}
`;
for (const browserType of [chromium, firefox, webkit]) {
const browser = await browserType.launch();
const capturing = await browser.newPage();
const clicked = await browser.newPage();
await capturing.setContent(`
<div id="handle" style="width: 200px; height: 200px; background: red"></div>
<script>
${logEvents}
handle.addEventListener('pointerdown', (event) => handle.setPointerCapture(event.pointerId));
</script>
`);
await clicked.setContent(`
<button style="width: 200px; height: 200px">click me</button>
<script>${logEvents}</script>
`);
// press the mouse on the handle of the first page, which captures the pointer
await capturing.mouse.move(100, 100);
await capturing.mouse.down();
// click the second page, in another context, 3 times
for (let i = 0; i < 3; i++) {
await clicked.mouse.click(100, 100);
}
await capturing.mouse.up();
console.log(`${browserType.name()}:`);
console.log(` first page: ${(await capturing.evaluate(() => window.events)).join(', ')}`);
console.log(` second page: ${(await clicked.evaluate(() => window.events)).join(', ')}`);
await browser.close();
}Expected behavior
Each page receives its own mouse events, as in Chromium and WebKit:
first page: pointerdown, pointerup, click
second page: pointerdown, pointerup, click, pointerdown, pointerup, click, pointerdown, pointerup, click
Actual behavior
In Firefox, the second page's first click goes to the first page, which ends its pointer capture, and the second page never receives it:
first page: pointerdown, pointerdown, pointerup, click, pointerup
second page: pointerdown, pointerup, click, pointerdown, pointerup, click
Additional context
Juggler dispatches every page's mouse events with identifier: win.windowUtils.DEFAULT_MOUSE_POINTER_ID (Page.dispatchMouseEvent in PageHandler.js). Firefox's parent process tracks pointer capture per pointer ID across all tabs (sPointerCaptureRemoteTargetTable in PointerEventHandler.cpp), and sends mouse events with a captured pointer ID to the capturing tab (EventStateManager::DispatchCrossProcessEvent). With one physical mouse that's correct, but Playwright's pages and contexts are meant to be independent.
We hit this in Vitest's browser mode, which runs test files in parallel pages of one browser, one context each. While a test drags a resize handle that captures the pointer, tests in other pages lose clicks, and the drag ends early when it receives their pointerups. We currently run those tests one at a time in a separate browser.
Using a distinct pointer ID per page, or per context, would keep their pointer captures apart.
Environment
OS: Windows 11 Pro 10.0.26300
Node.js: 26.12.1
playwright: 1.64.1
Firefox: 157.0
Activity
Run Firefox tests in parallel (#4233)
dgozman commentedon Oct 27, 2026
🛑 Blocked on upstream issue https://github.com/microsoft/playwright-browsers/issues/2632