Skip to content

Commit 14a217d

Browse files
authored
fix(browser): make userEvent more stable when running in parallel (#5974)
1 parent 49e973c commit 14a217d

File tree

14 files changed

+50
-31
lines changed

14 files changed

+50
-31
lines changed

docs/guide/browser.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,15 +953,16 @@ Custom functions will override built-in ones if they have the same name.
953953
Vitest exposes several `playwright` specific properties on the command context.
954954

955955
- `page` references the full page that contains the test iframe. This is the orchestrator HTML and you most likely shouldn't touch it to not break things.
956-
- `frame` is the tester [iframe instance](https://playwright.dev/docs/api/class-frame). It has a simillar API to the page, but it doesn't support certain methods.
956+
- `frame` is an async method that will resolve tester [`Frame`](https://playwright.dev/docs/api/class-frame). It has a simillar API to the `page`, but it doesn't support certain methods. If you need to query an element, you should prefer using `context.iframe` instead because it is more stable and faster.
957+
- `iframe` is a [`FrameLocator`](https://playwright.dev/docs/api/class-framelocator) that should be used to query other elements on the page.
957958
- `context` refers to the unique [BrowserContext](https://playwright.dev/docs/api/class-browsercontext).
958959

959960
```ts
960961
import { defineCommand } from '@vitest/browser'
961962

962963
export const myCommand = defineCommand(async (ctx, arg1, arg2) => {
963964
if (ctx.provider.name === 'playwright') {
964-
const element = await ctx.frame.findByRole('alert')
965+
const element = await ctx.iframe.findByRole('alert')
965966
const screenshot = await element.screenshot()
966967
// do something with the screenshot
967968
return difference

packages/browser/providers/playwright.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {
22
BrowserContext,
33
BrowserContextOptions,
44
Frame,
5+
FrameLocator,
56
LaunchOptions,
67
Page,
78
CDPSession
@@ -20,7 +21,8 @@ declare module 'vitest/node' {
2021

2122
export interface BrowserCommandContext {
2223
page: Page
23-
frame: Frame
24+
frame(): Promise<Frame>
25+
iframe: FrameLocator
2426
context: BrowserContext
2527
}
2628
}

packages/browser/src/node/cdp.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ export class BrowserServerCDPHandler {
1515
return this.session.send(method, params)
1616
}
1717

18-
detach() {
19-
return this.session.detach()
20-
}
21-
2218
on(event: string, id: string, once = false) {
2319
if (!this.listenerIds[event]) {
2420
this.listenerIds[event] = []

packages/browser/src/node/commands/clear.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ export const clear: UserEventCommand<UserEvent['clear']> = async (
88
xpath,
99
) => {
1010
if (context.provider instanceof PlaywrightBrowserProvider) {
11-
const { frame } = context
12-
const element = frame.locator(`xpath=${xpath}`)
11+
const { iframe } = context
12+
const element = iframe.locator(`xpath=${xpath}`)
1313
await element.clear({
1414
timeout: 1000,
1515
})

packages/browser/src/node/commands/click.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const click: UserEventCommand<UserEvent['click']> = async (
1010
) => {
1111
const provider = context.provider
1212
if (provider instanceof PlaywrightBrowserProvider) {
13-
const tester = context.frame
13+
const tester = context.iframe
1414
await tester.locator(`xpath=${xpath}`).click({
1515
timeout: 1000,
1616
...options,
@@ -33,7 +33,7 @@ export const dblClick: UserEventCommand<UserEvent['dblClick']> = async (
3333
) => {
3434
const provider = context.provider
3535
if (provider instanceof PlaywrightBrowserProvider) {
36-
const tester = context.frame
36+
const tester = context.iframe
3737
await tester.locator(`xpath=${xpath}`).dblclick(options)
3838
}
3939
else if (provider instanceof WebdriverBrowserProvider) {

packages/browser/src/node/commands/dragAndDrop.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export const dragAndDrop: UserEventCommand<UserEvent['dragAndDrop']> = async (
1010
options,
1111
) => {
1212
if (context.provider instanceof PlaywrightBrowserProvider) {
13-
await context.frame.dragAndDrop(
13+
const frame = await context.frame()
14+
await frame.dragAndDrop(
1415
`xpath=${source}`,
1516
`xpath=${target}`,
1617
{

packages/browser/src/node/commands/fill.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export const fill: UserEventCommand<UserEvent['fill']> = async (
1010
options = {},
1111
) => {
1212
if (context.provider instanceof PlaywrightBrowserProvider) {
13-
const { frame } = context
14-
const element = frame.locator(`xpath=${xpath}`)
13+
const { iframe } = context
14+
const element = iframe.locator(`xpath=${xpath}`)
1515
await element.fill(text, { timeout: 1000, ...options })
1616
}
1717
else if (context.provider instanceof WebdriverBrowserProvider) {

packages/browser/src/node/commands/hover.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const hover: UserEventCommand<UserEvent['hover']> = async (
99
options = {},
1010
) => {
1111
if (context.provider instanceof PlaywrightBrowserProvider) {
12-
await context.frame.locator(`xpath=${xpath}`).hover({
12+
await context.iframe.locator(`xpath=${xpath}`).hover({
1313
timeout: 1000,
1414
...options,
1515
})

packages/browser/src/node/commands/keyboard.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export const keyboard: UserEventCommand<UserEvent['keyboard']> = async (
2121
}
2222

2323
if (context.provider instanceof PlaywrightBrowserProvider) {
24-
await context.frame.evaluate(focusIframe)
24+
const frame = await context.frame()
25+
await frame.evaluate(focusIframe)
2526
}
2627
else if (context.provider instanceof WebdriverBrowserProvider) {
2728
await context.browser.execute(focusIframe)
@@ -39,7 +40,8 @@ export const keyboard: UserEventCommand<UserEvent['keyboard']> = async (
3940
}
4041
}
4142
if (context.provider instanceof PlaywrightBrowserProvider) {
42-
await context.frame.evaluate(selectAll)
43+
const frame = await context.frame()
44+
await frame.evaluate(selectAll)
4345
}
4446
else if (context.provider instanceof WebdriverBrowserProvider) {
4547
await context.browser.execute(selectAll)

packages/browser/src/node/commands/screenshot.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ export const screenshot: BrowserCommand<[string, ScreenshotOptions]> = async (
2828
if (context.provider instanceof PlaywrightBrowserProvider) {
2929
if (options.element) {
3030
const { element: elementXpath, ...config } = options
31-
const iframe = context.frame
32-
const element = iframe.locator(`xpath=${elementXpath}`)
31+
const element = context.iframe.locator(`xpath=${elementXpath}`)
3332
await element.screenshot({ ...config, path: savePath })
3433
}
3534
else {
36-
await context.frame.locator('body').screenshot({ ...options, path: savePath })
35+
await context.iframe.locator('body').screenshot({
36+
...options,
37+
path: savePath,
38+
})
3739
}
3840
return path
3941
}

0 commit comments

Comments
 (0)