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

Abierto
#43,969 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
30/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
playwright, typescript

Línea de trabajo

Start by reading the mouse input handling and Firefox-specific code paths implicated in the report, along with the related issues #43631, #43847, and #27717. The reproduction script in the issue shows the failure across two pages; use it to investigate where the drag state is lost. Done means the Firefox range drag completes and fires change after mouse movement in another page, matching the reported Chromium and WebKit behavior.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

needs-triage
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 #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
Lenguaje dominante
TypeScript
Estrellas
99.1k
Forks
6.8k
Merge medio
16 h 20 min
PR fusionados (30 d)
324

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de microsoft/playwright

Todos los issues de microsoft/playwright

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.