Skip to content

[Bug]: Firefox: Mouse move in one page breaks a mouse drag in another page #43969

Open

Description

Version

1.65.0, Firefox 159.0 (build 1572).

Steps to reproduce

import { chromium, firefox, webkit } from 'playwright';

const content = `
  <input type="range" style="margin: 0; width: 200px; height: 20px">
  <script>
    document.body.style.margin = '0';
    window.changed = false;
    document.querySelector('input').addEventListener('change', () => (window.changed = true));
  </script>
`;

for (const browserType of [chromium, firefox, webkit]) {
  const browser = await browserType.launch();
  const page1 = await (await browser.newContext()).newPage();
  const page2 = await (await browser.newContext()).newPage();
  await page1.setContent(content);
  await page2.setContent(content);

  // start dragging the range thumb in the first page
  await page1.mouse.move(100, 10);
  await page1.mouse.down();
  await page1.mouse.move(150, 10);

  // move the mouse in the second page, no buttons pressed
  await page2.mouse.move(50, 50);

  // finish the drag in the first page
  await page1.mouse.move(180, 10);
  await page1.mouse.up();

  const changed = await page1.evaluate(() => window.changed);
  const value = await page1.evaluate(() => document.querySelector('input').value);
  console.log(`${browserType.name()}: change fired = ${changed}, value = ${value}`);
  await browser.close();
}

Expected behavior

Same as in Chromium and WebKit, and in Firefox without the page2.mouse.move() call:

chromium: change fired = true, value = 93
firefox: change fired = true, value = 94
webkit: change fired = true, value = 94

Actual behavior

chromium: change fired = true, value = 93
firefox: change fired = false, value = 50
webkit: change fired = true, value = 94

Additional context

We faced this in vaadin-range-slider tests, see modernweb-dev/web#2374. Web Test Runner opens a new context and page for each test file. Any concurrent test file that calls sendMouse() orresetMouse() breaks drag and hover tests in other files. The only workaround is --concurrency 1.

🤖 Disclaimer: repro and text below are AI generated, I hereby confirm that I read it and it sounds reasonable.

The first page gets pointerout, pointerleave, mouseout and mouseleave when the mouse moves in the second page. After that, the range input loses mouse capture.

  • The final mouseup is dispatched to <html> instead of the input, so change never fires.
  • page2.mouse.up() or page2.mouse.click() break the drag in the same way.
  • The range input doesn't use pointer capture (hasPointerCapture() returns false during the drag).

This looks similar to #43631, but #43847 doesn't fix it. Possibly related: #27717

Possible Cause:

  • The parent process tracks a single BrowserParent::sLastMouseRemoteTarget for all tabs (dom/ipc/BrowserParent.cpp).
  • In EventStateManager::DispatchCrossProcessEvent, when a mouse event goes to a different remote than the last one, Gecko sends eMouseExitFromWidget to the old remote (dom/events/EventStateManager.cpp).
  • With one physical mouse that is correct. With independent Playwright pages, every mouse event in one page sends a mouse exit to whichever page got the last mouse event.
  • This path doesn't use the pointer id, so the per-page _mousePointerId from feat(firefox): roll to r1572 #43847 doesn't help.
  • The parent's mouse capture (PresShell::sCapturingContentInfo.mRemoteTarget) is also a single process-wide value. Any mouseup or mousedown in another page releases it.

Suggested fix: patch Gecko to keep the last mouse remote target per top-level window, or skip the cross-process mouse exit when the old and the new remote are in different top-level windows.

Environment

System:
    OS: macOS 15.8.2
    CPU: (8) arm64 Apple M1
    Memory: 197.06 MB / 16.00 GB
  Binaries:
    Node: 24.22.1 - /Users/serhii/.nvm/versions/node/v24.22.1/bin/node
    Yarn: 1.22.22 - /Users/serhii/.yarn/bin/yarn
    npm: 11.19.1 - /Users/serhii/.nvm/versions/node/v24.22.1/bin/npm
    pnpm: 7.27.1 - /Users/serhii/Library/pnpm/pnpm
  IDEs:
    VSCode: 1.145.2 - /usr/local/bin/code
    Claude Code: 2.1.319 - /Users/serhii/.local/bin/claude
  Languages:
    Bash: 5.3.3 - /opt/homebrew/bin/bash

Activity

  1. github-actions commented on Nov 6, 2026

    @github-actions
  2. microsoft-playwright-automation commented on Nov 6, 2026

    @microsoft-playwright-automation
    Contributor

    Hi, I'm the Playwright bot. I reproduced this on Linux.

    Reproduced in Firefox 159.0, build 1573, on current main. The range resets to 50 and emits no change. Chromium and WebKit pass the same headless test.

    The trigger is smaller than a mouse move: await page2.bringToFront() alone cancels the drag. Firefox releases native mouse capture when the active window changes; the range then cancels on its next movement. Build 1573 suppresses the headless cross-window exit events, but the drag still fails without any such events. This needs a Firefox browser-side fix.

    Reproduction and results

    Tested Playwright 1.66.0-next, commit 58d69dcc392af3a6994eab0323dc2e883f05f396, on Ubuntu 24.04.5 x86_64. The reported macOS platform and build 1572 were not tested.

    // Both pages are in separate contexts and contain:
    // <body style="margin:0">
    //   <input type="range" style="margin:0;width:200px;height:20px">
    // </body>
    await page1.mouse.move(100, 10);
    await page1.mouse.down();
    await page1.mouse.move(150, 10);
    await page2.mouse.move(50, 50); // bringToFront() alone also reproduces
    await page1.mouse.move(180, 10);
    await page1.mouse.up();
    Page 2 action, headless Chromium 158.0.8127.18 / 1254 Firefox 159.0 / 1573 WebKit 27.2 / 2389
    None 93, change 94, change 94, change
    bringToFront() 93, change 50, no change 94, change
    Mouse move 93, change 50, no change 94, change
    Mouse up 93, change 50, no change 94, change
    Mouse click 93, change 50, no change 94, change

    The repository test failed on all four Firefox attempts; Chromium and WebKit passed. Headed/Xvfb Firefox also fails for move, up and click; the no-interruption control passes. Headed WebKit passes those cases. Headed Chromium needs page 1 brought forward before the drag: its control, move and up reach 93; clicking page 2 ends at 77 with change. Without that initial focus, its control fails too.

    In the headless Firefox trace, the range first reaches 78, then resets to 50 on page 1's next movement. No exit events occur, and mouseup still targets the input. In headed Firefox, exit events also occur. The browser report includes the fixture-based test, the native capture-release source paths, and event traces.

    Blocked-by: https://github.com/microsoft/playwright-browsers/issues/2683

    Triaged on Linux by the Playwright bot - agent run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions