Skip to content

Commit e2c29ea

Browse files
authoredDec 1, 2024··
feat(browser): support actionTimeout as playwright provider options (#6984)
1 parent a485b32 commit e2c29ea

File tree

13 files changed

+87
-27
lines changed

13 files changed

+87
-27
lines changed
 

‎packages/browser/matchers.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ declare module 'vitest' {
1717
type PromisifyDomAssertion<T> = Promisify<Assertion<T>>
1818

1919
interface ExpectStatic {
20+
/**
21+
* `expect.element(locator)` is a shorthand for `expect.poll(() => locator.element())`.
22+
* You can set default timeout via `expect.poll.timeout` config.
23+
*/
2024
element: <T extends Element | Locator>(element: T, options?: ExpectPollOptions) => PromisifyDomAssertion<Awaited<Element | null>>
2125
}
2226
}

‎packages/browser/providers/playwright.d.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ declare module 'vitest/node' {
1616
context?: Omit<
1717
BrowserContextOptions,
1818
'ignoreHTTPSErrors' | 'serviceWorkers'
19-
>
19+
> & {
20+
/**
21+
* The maximum time in milliseconds to wait for `userEvent` action to complete.
22+
* @default 0 (no timeout)
23+
*/
24+
actionTimeout?: number
25+
}
2026
}
2127

2228
export interface BrowserCommandContext {

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ export const clear: UserEventCommand<UserEvent['clear']> = async (
1010
if (context.provider instanceof PlaywrightBrowserProvider) {
1111
const { iframe } = context
1212
const element = iframe.locator(selector)
13-
await element.clear({
14-
timeout: 1000,
15-
})
13+
await element.clear()
1614
}
1715
else if (context.provider instanceof WebdriverBrowserProvider) {
1816
const browser = context.browser

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ export const click: UserEventCommand<UserEvent['click']> = async (
1111
const provider = context.provider
1212
if (provider instanceof PlaywrightBrowserProvider) {
1313
const tester = context.iframe
14-
await tester.locator(selector).click({
15-
timeout: 1000,
16-
...options,
17-
})
14+
await tester.locator(selector).click(options)
1815
}
1916
else if (provider instanceof WebdriverBrowserProvider) {
2017
const browser = context.browser
@@ -53,7 +50,6 @@ export const tripleClick: UserEventCommand<UserEvent['tripleClick']> = async (
5350
if (provider instanceof PlaywrightBrowserProvider) {
5451
const tester = context.iframe
5552
await tester.locator(selector).click({
56-
timeout: 1000,
5753
...options,
5854
clickCount: 3,
5955
})

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ export const dragAndDrop: UserEventCommand<UserEvent['dragAndDrop']> = async (
1414
await frame.dragAndDrop(
1515
source,
1616
target,
17-
{
18-
timeout: 1000,
19-
...options_,
20-
},
17+
options_,
2118
)
2219
}
2320
else if (context.provider instanceof WebdriverBrowserProvider) {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const fill: UserEventCommand<UserEvent['fill']> = async (
1212
if (context.provider instanceof PlaywrightBrowserProvider) {
1313
const { iframe } = context
1414
const element = iframe.locator(selector)
15-
await element.fill(text, { timeout: 1000, ...options })
15+
await element.fill(text, options)
1616
}
1717
else if (context.provider instanceof WebdriverBrowserProvider) {
1818
const browser = context.browser

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ export const hover: UserEventCommand<UserEvent['hover']> = async (
99
options = {},
1010
) => {
1111
if (context.provider instanceof PlaywrightBrowserProvider) {
12-
await context.iframe.locator(selector).hover({
13-
timeout: 1000,
14-
...options,
15-
})
12+
await context.iframe.locator(selector).hover(options)
1613
}
1714
else if (context.provider instanceof WebdriverBrowserProvider) {
1815
const browser = context.browser

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

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export const screenshot: BrowserCommand<[string, ScreenshotOptions]> = async (
3030
const { element: selector, ...config } = options
3131
const element = context.iframe.locator(`${selector}`)
3232
const buffer = await element.screenshot({
33-
timeout: 1000,
3433
...config,
3534
path: savePath,
3635
})

‎packages/browser/src/node/commands/select.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ export const selectOptions: UserEventCommand<UserEvent['selectOptions']> = async
2626
return elementHandler
2727
})) as (readonly string[]) | (readonly ElementHandle[])
2828

29-
await selectElement.selectOption(values, {
30-
timeout: 1000,
31-
...options,
32-
})
29+
await selectElement.selectOption(values, options)
3330
}
3431
else if (context.provider instanceof WebdriverBrowserProvider) {
3532
const values = userValues as any as [({ index: number })]

‎packages/browser/src/node/providers/playwright.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
3131

3232
private options?: {
3333
launch?: LaunchOptions
34-
context?: BrowserContextOptions
34+
context?: BrowserContextOptions & { actionTimeout?: number }
3535
}
3636

3737
public contexts = new Map<string, BrowserContext>()
@@ -108,15 +108,19 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
108108
}
109109

110110
const browser = await this.openBrowser()
111+
const { actionTimeout, ...contextOptions } = this.options?.context ?? {}
111112
const options = {
112-
...this.options?.context,
113+
...contextOptions,
113114
ignoreHTTPSErrors: true,
114115
serviceWorkers: 'allow',
115116
} satisfies BrowserContextOptions
116117
if (this.project.config.browser.ui) {
117118
options.viewport = null
118119
}
119120
const context = await browser.newContext(options)
121+
if (actionTimeout) {
122+
context.setDefaultTimeout(actionTimeout)
123+
}
120124
this.contexts.set(contextId, context)
121125
return context
122126
}
@@ -187,7 +191,7 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
187191
async openPage(contextId: string, url: string, beforeNavigate?: () => Promise<void>) {
188192
const browserPage = await this.openBrowserPage(contextId)
189193
await beforeNavigate?.()
190-
await browserPage.goto(url)
194+
await browserPage.goto(url, { timeout: 0 })
191195
}
192196

193197
async getCDPSession(contextId: string) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { page } from '@vitest/browser/context';
2+
import { afterEach, expect, test } from 'vitest';
3+
4+
afterEach(() => {
5+
document.body.innerHTML = ''
6+
})
7+
8+
test('click default', async () => {
9+
document.body.innerHTML = '<div><span>hello</span></div>'
10+
await page.getByText('world').click()
11+
})
12+
13+
test('click override', async () => {
14+
document.body.innerHTML = '<div><span>hello</span></div>'
15+
await page.getByText('world').click({ timeout: 345 })
16+
})
17+
18+
test('element', async () => {
19+
document.body.innerHTML = '<div><span>hello</span></div>'
20+
await expect.element(page.getByText('world')).toBeVisible()
21+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { fileURLToPath } from 'node:url'
2+
import { defineConfig } from 'vitest/config'
3+
4+
const provider = process.env.PROVIDER || 'playwright'
5+
const name =
6+
process.env.BROWSER || (provider === 'playwright' ? 'chromium' : 'chrome')
7+
8+
export default defineConfig({
9+
cacheDir: fileURLToPath(new URL("./node_modules/.vite", import.meta.url)),
10+
test: {
11+
browser: {
12+
enabled: true,
13+
provider,
14+
name,
15+
providerOptions: {
16+
context: {
17+
actionTimeout: 500
18+
}
19+
}
20+
},
21+
expect: {
22+
poll: {
23+
timeout: 500
24+
}
25+
}
26+
},
27+
})

‎test/browser/specs/runner.test.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { readFile } from 'node:fs/promises'
22
import { beforeAll, describe, expect, onTestFailed, test } from 'vitest'
3-
import { browser, runBrowserTests } from './utils'
3+
import { browser, provider, runBrowserTests } from './utils'
44

55
describe('running browser tests', async () => {
66
let stderr: string
@@ -153,3 +153,17 @@ test('user-event', async () => {
153153
}
154154
`)
155155
})
156+
157+
test('timeout', async () => {
158+
const { stderr } = await runBrowserTests({
159+
root: './fixtures/timeout',
160+
})
161+
expect(stderr).toContain('Matcher did not succeed in 500ms')
162+
if (provider === 'playwright') {
163+
expect(stderr).toContain('locator.click: Timeout 500ms exceeded.')
164+
expect(stderr).toContain('locator.click: Timeout 345ms exceeded.')
165+
}
166+
if (provider === 'webdriverio') {
167+
expect(stderr).toContain('Cannot find element with locator')
168+
}
169+
})

0 commit comments

Comments
 (0)
Please sign in to comment.