fix(reuse): reset mouse position in Firefox (#22973)

Otherwise, Firefox sometimes keeps the current position and triggers
unexpected hover effects.

Fixes #22432.
This commit is contained in:
Dmitry Gozman 2023-05-12 13:21:49 -07:00 committed by GitHub
parent bf1aba885b
commit 9472f79d32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 0 deletions

View File

@ -356,6 +356,9 @@ export class CRPage implements PageDelegate {
await this._mainFrameSession._client.send('Page.enable').catch(e => {});
}
async resetForReuse(): Promise<void> {
}
async pdf(options: channels.PagePdfParams): Promise<Buffer> {
return this._pdf.generate(options);
}

View File

@ -575,6 +575,14 @@ export class FFPage implements PageDelegate {
async inputActionEpilogue(): Promise<void> {
}
async resetForReuse(): Promise<void> {
// Firefox sometimes keeps the last mouse position in the page,
// which affects things like hovered state.
// See https://github.com/microsoft/playwright/issues/22432.
// Move mouse to (-1, -1) to avoid anything being hovered.
await this.rawMouse.move(-1, -1, 'none', new Set(), new Set(), false);
}
async getFrameElement(frame: frames.Frame): Promise<dom.ElementHandle> {
const parent = frame.parentFrame();
if (!parent)

View File

@ -94,6 +94,8 @@ export interface PageDelegate {
inputActionEpilogue(): Promise<void>;
// Work around for asynchronously dispatched CSP errors in Firefox.
readonly cspErrorsAsynchronousForInlineScipts?: boolean;
// Work around for mouse position in Firefox.
resetForReuse(): Promise<void>;
}
type EmulatedSize = { screen: types.Size, viewport: types.Size };
@ -265,6 +267,8 @@ export class Page extends SdkObject {
this._delegate.updateEmulateMedia(),
this._delegate.updateFileChooserInterception(),
]);
await this._delegate.resetForReuse();
}
_didClose() {

View File

@ -995,6 +995,9 @@ export class WKPage implements PageDelegate {
async inputActionEpilogue(): Promise<void> {
}
async resetForReuse(): Promise<void> {
}
async getFrameElement(frame: frames.Frame): Promise<dom.ElementHandle> {
const parent = frame.parentFrame();
if (!parent)

View File

@ -202,3 +202,35 @@ test('should ignore binding from beforeunload', async ({ reusedContext }) => {
expect(called).toBe(false);
});
test('should reset mouse position', async ({ reusedContext, browserName, platform }) => {
// Note: this test only reproduces the issue locally when run with --repeat-each=20.
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/22432' });
test.fixme(browserName === 'chromium' && platform !== 'darwin', 'chromium keeps hover on linux/win');
const pageContent = `
<style>
div { height: 30px; background: blue; }
div:hover { background: red; }
html, body { margin: 0; padding: 0; }
</style>
<div id=one>one</div>
<div id=two>two</div>
`;
let context = await reusedContext();
let page = await context.newPage();
await page.setContent(pageContent);
await expect(page.locator('#one')).toHaveCSS('background-color', 'rgb(0, 0, 255)');
await expect(page.locator('#two')).toHaveCSS('background-color', 'rgb(0, 0, 255)');
await page.mouse.move(10, 45);
await expect(page.locator('#one')).toHaveCSS('background-color', 'rgb(0, 0, 255)');
await expect(page.locator('#two')).toHaveCSS('background-color', 'rgb(255, 0, 0)');
context = await reusedContext();
page = context.pages()[0];
await page.setContent(pageContent);
await expect(page.locator('#one')).toHaveCSS('background-color', 'rgb(0, 0, 255)');
await expect(page.locator('#two')).toHaveCSS('background-color', 'rgb(0, 0, 255)');
});