Skip to content

Commit 218bcbb

Browse files
DavertMikDavertMikclaude
authored
fix(helpers): scroll element into view in moveCursorTo (#5715)
moveCursorTo moved the mouse to the element's center coordinates without scrolling first. For an element outside the viewport the cursor landed off-screen and no hover fired, with no error. Playwright now calls scrollIntoViewIfNeeded() before reading the point. Puppeteer scrolls the element to the center when it is not fully in the viewport, the same check its own ElementHandle.hover() performs, using public API only. WebDriver needs no change: WebdriverIO's moveTo already scrolls into view. Claude-Session: https://claude.ai/code/session_01VmYyNa6z4o3hxPkdpDiUmB Co-authored-by: DavertMik <davert@testomat.io> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent b9a7366 commit 218bcbb

5 files changed

Lines changed: 31 additions & 0 deletions

File tree

lib/helper/Playwright.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,7 @@ class Playwright extends Helper {
15251525
assertElementExists(el, locator)
15261526
}
15271527

1528+
await el.scrollIntoViewIfNeeded()
15281529
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
15291530
const { x, y } = await clickablePoint(el)
15301531
await this.page.mouse.move(x + offsetX, y + offsetY)

lib/helper/Puppeteer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,9 @@ class Puppeteer extends Helper {
845845
}
846846
}
847847

848+
if (!(await el.isIntersectingViewport({ threshold: 1 }))) {
849+
await el.evaluate(el => el.scrollIntoView({ block: 'center', inline: 'center' }))
850+
}
848851
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
849852
const { x, y } = await getClickablePoint(el)
850853
await this.page.mouse.move(x + offsetX, y + offsetY)

test/data/app/view/form/hover.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@
77

88
<div id="show"></div>
99

10+
<div id="offscreen_show"></div>
11+
<span id="offscreen_hover" style="display: inline-block; margin-top: 2000px" onmouseover="document.getElementById('offscreen_show').innerText = 'Hovered offscreen!'">Hover me too!</span>
12+
1013
</body>
1114
</html>

test/helper/Playwright_test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,18 @@ describe('Playwright', function () {
395395
I.amOnPage('/form/hover')
396396
.then(() => I.moveCursorTo('#hover', 'body'))
397397
.then(() => I.see('Hovered', '#show')))
398+
399+
it('should scroll element into view before hovering', async () => {
400+
await I.amOnPage('/form/hover')
401+
await I.moveCursorTo('#offscreen_hover')
402+
await I.see('Hovered offscreen', '#offscreen_show')
403+
})
404+
405+
it('should scroll element into view before hovering within a context', async () => {
406+
await I.amOnPage('/form/hover')
407+
await I.moveCursorTo('#offscreen_hover', 'body')
408+
await I.see('Hovered offscreen', '#offscreen_show')
409+
})
398410
})
399411

400412
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => {

test/helper/Puppeteer_test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,18 @@ describe('Puppeteer', function () {
245245
I.amOnPage('/form/hover')
246246
.then(() => I.moveCursorTo('#hover', 'body'))
247247
.then(() => I.see('Hovered', '#show')))
248+
249+
it('should scroll element into view before hovering', async () => {
250+
await I.amOnPage('/form/hover')
251+
await I.moveCursorTo('#offscreen_hover')
252+
await I.see('Hovered offscreen', '#offscreen_show')
253+
})
254+
255+
it('should scroll element into view before hovering within a context', async () => {
256+
await I.amOnPage('/form/hover')
257+
await I.moveCursorTo('#offscreen_hover', 'body')
258+
await I.see('Hovered offscreen', '#offscreen_show')
259+
})
248260
})
249261

250262
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => {

0 commit comments

Comments
 (0)