diff --git a/packages/playwright-core/src/server/bidi/bidiInput.ts b/packages/playwright-core/src/server/bidi/bidiInput.ts index 01a359dd12..c94e292dc1 100644 --- a/packages/playwright-core/src/server/bidi/bidiInput.ts +++ b/packages/playwright-core/src/server/bidi/bidiInput.ts @@ -94,8 +94,8 @@ export class RawMouseImpl implements input.RawMouse { async wheel(x: number, y: number, buttons: Set, modifiers: Set, deltaX: number, deltaY: number): Promise { // Bidi throws when x/y are not integers. - x = Math.round(x); - y = Math.round(y); + x = Math.floor(x); + y = Math.floor(y); await this._session.send('input.performActions', { context: this._session.sessionId, actions: [ diff --git a/packages/playwright-core/src/server/bidi/bidiPage.ts b/packages/playwright-core/src/server/bidi/bidiPage.ts index cf0662738b..425198d85b 100644 --- a/packages/playwright-core/src/server/bidi/bidiPage.ts +++ b/packages/playwright-core/src/server/bidi/bidiPage.ts @@ -576,6 +576,13 @@ export class BidiPage implements PageDelegate { shouldToggleStyleSheetToSyncAnimations(): boolean { return true; } + + shouldClickAtIntegerCoordinates(): boolean { + // TODO: bidi spec requires integer coordinates, but Chromium actually supports + // fractional coordinates, perhaps the spec should be updated and we wouldn't need + // this hack. + return true; + } } function addMainBinding(callback: (arg: any) => void) { diff --git a/packages/playwright-core/src/server/chromium/crPage.ts b/packages/playwright-core/src/server/chromium/crPage.ts index 9fb43b2d51..68659437a9 100644 --- a/packages/playwright-core/src/server/chromium/crPage.ts +++ b/packages/playwright-core/src/server/chromium/crPage.ts @@ -370,6 +370,10 @@ export class CRPage implements PageDelegate { shouldToggleStyleSheetToSyncAnimations(): boolean { return false; } + + shouldClickAtIntegerCoordinates(): boolean { + return false; + } } class FrameSession { diff --git a/packages/playwright-core/src/server/dom.ts b/packages/playwright-core/src/server/dom.ts index 288b8c2c8d..abcc69ffce 100644 --- a/packages/playwright-core/src/server/dom.ts +++ b/packages/playwright-core/src/server/dom.ts @@ -275,7 +275,7 @@ export class ElementHandle extends js.JSHandle { const filtered = quads.map(quad => intersectQuadWithViewport(quad)).filter(quad => computeQuadArea(quad) > 0.99); if (!filtered.length) return 'error:notinviewport'; - if (this._page._browserContext._browser.options.name === 'firefox') { + if (this._page._delegate.shouldClickAtIntegerCoordinates()) { // Firefox internally uses integer coordinates, so 8.x is converted to 8 or 9 when clicking. // // This does not work nicely for small elements. For example, 1x1 square with corners diff --git a/packages/playwright-core/src/server/firefox/ffPage.ts b/packages/playwright-core/src/server/firefox/ffPage.ts index 71199dc8d5..5d5ba0477b 100644 --- a/packages/playwright-core/src/server/firefox/ffPage.ts +++ b/packages/playwright-core/src/server/firefox/ffPage.ts @@ -574,6 +574,10 @@ export class FFPage implements PageDelegate { shouldToggleStyleSheetToSyncAnimations(): boolean { return false; } + + shouldClickAtIntegerCoordinates(): boolean { + return true; + } } function webSocketId(frameId: string, wsid: string): string { diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index b8fdae2808..7b22fdaa08 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -96,6 +96,8 @@ export interface PageDelegate { readonly cspErrorsAsynchronousForInlineScripts?: boolean; // Work around for mouse position in Firefox. resetForReuse(): Promise; + // Firefox can only click at integer coordinates. + shouldClickAtIntegerCoordinates(): boolean; // WebKit hack. shouldToggleStyleSheetToSyncAnimations(): boolean; } diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 4a78642668..3b57001987 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -1202,6 +1202,10 @@ export class WKPage implements PageDelegate { shouldToggleStyleSheetToSyncAnimations(): boolean { return true; } + + shouldClickAtIntegerCoordinates(): boolean { + return false; + } } /**