mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-11 12:33:45 +03:00
feat(expect): introduce explicit default async expect timeout (#8071)
This commit is contained in:
parent
755cf60496
commit
290f601dae
@ -118,7 +118,7 @@ export default config;
|
||||
## property: Fixtures.actionTimeout
|
||||
- type: <[int]>
|
||||
|
||||
Timeout for each action and expect in milliseconds. Defaults to 0 (no timeout).
|
||||
Default timeout for each Playwright action in milliseconds, defaults to 0 (no timeout).
|
||||
|
||||
This is a default timeout for all Playwright actions, same as configured via [`method: Page.setDefaultTimeout`].
|
||||
|
||||
|
@ -106,6 +106,7 @@ export default config;
|
||||
|
||||
## property: TestProject.expect
|
||||
- type: <[Object]>
|
||||
- `timeout` <[float]> Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||
- `toMatchSnapshot` <[Object]>
|
||||
- `threshold` <[float]> Image matching threshold between zero (strict) and one (lax).
|
||||
|
||||
|
@ -25,14 +25,14 @@ await expect(page.locator('.status')).toHaveText('Submitted');
|
||||
|
||||
Playwright Test will be re-testing the node with the selector `.status` until fetched Node has the `"Submitted"`
|
||||
text. It will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is
|
||||
reached. You can either pass this timeout or configure it once via the [`property: Fixtures.actionTimeout`] value
|
||||
reached. You can either pass this timeout or configure it once via the [`property: TestProject.expect`] value
|
||||
in test config.
|
||||
|
||||
By default, the timeout for assertions is not set, so it'll wait forever, until the whole test times out.
|
||||
|
||||
## expect(locator).toBeChecked
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to the checked input.
|
||||
|
||||
@ -43,7 +43,7 @@ await expect(locator).toBeChecked();
|
||||
|
||||
## expect(locator).toBeDisabled
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to a disabled element.
|
||||
|
||||
@ -54,7 +54,7 @@ await expect(locator).toBeDisabled();
|
||||
|
||||
## expect(locator).toBeEditable
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an editable element.
|
||||
|
||||
@ -65,7 +65,7 @@ await expect(locator).toBeEditable();
|
||||
|
||||
## expect(locator).toBeEmpty
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an empty editable element or to a DOM node that has no text.
|
||||
|
||||
@ -76,7 +76,7 @@ await expect(locator).toBeEmpty();
|
||||
|
||||
## expect(locator).toBeEnabled
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an enabled element.
|
||||
|
||||
@ -87,7 +87,7 @@ await expect(locator).toBeEnabled();
|
||||
|
||||
## expect(locator).toBeFocused
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to a focused DOM node.
|
||||
|
||||
@ -98,7 +98,7 @@ await expect(locator).toBeFocused();
|
||||
|
||||
## expect(locator).toBeHidden
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to a hidden DOM node, which is the opposite of [visible](./actionability.md#visible).
|
||||
|
||||
@ -109,7 +109,7 @@ await expect(locator).toBeHidden();
|
||||
|
||||
## expect(locator).toBeVisible
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to a [visible](./actionability.md#visible) DOM node.
|
||||
|
||||
@ -121,7 +121,7 @@ await expect(locator).toBeVisible();
|
||||
## expect(locator).toContainText(text, options?)
|
||||
- `text`: <[string]> Text to look for inside the element
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to wait for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to wait for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
- `useInnerText`: <[boolean]> Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text.
|
||||
|
||||
Ensures [Locator] points to a selected option.
|
||||
@ -135,7 +135,7 @@ await expect(locator).toContainText('substring');
|
||||
- `name`: <[string]> Attribute name
|
||||
- `value`: <[string]|[RegExp]> Attribute value
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an element with given attribute.
|
||||
|
||||
@ -147,7 +147,7 @@ await expect(locator).toHaveAttribute('type', 'text');
|
||||
## expect(locator).toHaveClass(expected)
|
||||
- `expected`: <[string] | [RegExp] | [Array]<[string]>>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an element with given CSS class.
|
||||
|
||||
@ -166,7 +166,7 @@ await expect(locator).toHaveClass(['component', 'component selected', 'component
|
||||
## expect(locator).toHaveCount(count)
|
||||
- `count`: <[number]>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] resolves to an exact number of DOM nodes.
|
||||
|
||||
@ -179,7 +179,7 @@ await expect(list).toHaveCount(3);
|
||||
- `name`: <[string]> CSS property name
|
||||
- `value`: <[string]|[RegExp]> CSS property value
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] resolves to an element with the given computed CSS style
|
||||
|
||||
@ -191,7 +191,7 @@ await expect(locator).toHaveCSS('display', 'flex');
|
||||
## expect(locator).toHaveId(id)
|
||||
- `id`: <[string]> Element id
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an element with the given DOM Node ID.
|
||||
|
||||
@ -204,7 +204,7 @@ await expect(locator).toHaveId('lastname');
|
||||
- `name`: <[string]> Property name
|
||||
- `value`: <[any]> Property value
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an element with given JavaScript property. Note that this property can be
|
||||
of a primitive type as well as a plain serializable JavaScript object.
|
||||
@ -217,7 +217,7 @@ await expect(locator).toHaveJSProperty('loaded', true);
|
||||
## expect(locator).toHaveText(expected, options)
|
||||
- `expected`: <[string] | [RegExp] | [Array]<[string]>>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
- `useInnerText`: <[boolean]> Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text.
|
||||
|
||||
Ensures [Locator] points to an element with the given text. You can use regular expressions for the value as well.
|
||||
@ -237,7 +237,7 @@ await expect(locator).toHaveText(['Text 1', 'Text 2', 'Text 3']);
|
||||
## expect(page).toHaveTitle(title)
|
||||
- `title`: <[string] | [RegExp]>>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures page has a given title.
|
||||
|
||||
@ -248,7 +248,7 @@ await expect(page).toHaveTitle(/.*checkout/);
|
||||
## expect(page).toHaveURL(url)
|
||||
- `url`: <[string] | [RegExp]>>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures page is navigated to a given URL.
|
||||
|
||||
@ -259,7 +259,7 @@ await expect(page).toHaveURL(/.*checkout/);
|
||||
## expect(locator).toHaveValue(value)
|
||||
- `value`: <[string] | [RegExp]>>
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
|
||||
|
||||
Ensures [Locator] points to an element with the given input value. You can use regular expressions for the value as well.
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import expectLibrary from 'expect';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
@ -191,7 +190,6 @@ export const test = _baseTest.extend<PlaywrightTestArgs & PlaywrightTestOptions,
|
||||
};
|
||||
context.setDefaultTimeout(actionTimeout || 0);
|
||||
context.setDefaultNavigationTimeout(navigationTimeout || actionTimeout || 0);
|
||||
expectLibrary.setState({ playwrightActionTimeout: actionTimeout } as any);
|
||||
context.on('page', page => allPages.push(page));
|
||||
|
||||
if (captureTrace) {
|
||||
|
@ -44,7 +44,7 @@ export async function toBeTruthy<T>(
|
||||
let pass = false;
|
||||
|
||||
// TODO: interrupt on timeout for nice message.
|
||||
await pollUntilDeadline(this, async remainingTime => {
|
||||
await pollUntilDeadline(testInfo, async remainingTime => {
|
||||
received = await query(remainingTime);
|
||||
pass = !!received;
|
||||
return pass === !matcherOptions.isNot;
|
||||
|
@ -60,7 +60,7 @@ export async function toEqual<T>(
|
||||
let pass = false;
|
||||
|
||||
// TODO: interrupt on timeout for nice message.
|
||||
await pollUntilDeadline(this, async remainingTime => {
|
||||
await pollUntilDeadline(testInfo, async remainingTime => {
|
||||
received = await query(remainingTime);
|
||||
pass = equals(received, expected, [iterableEquality]);
|
||||
return pass === !matcherOptions.isNot;
|
||||
|
@ -70,7 +70,7 @@ export async function toMatchText(
|
||||
let pass = false;
|
||||
|
||||
// TODO: interrupt on timeout for nice message.
|
||||
await pollUntilDeadline(this, async remainingTime => {
|
||||
await pollUntilDeadline(testInfo, async remainingTime => {
|
||||
received = await query(remainingTime);
|
||||
if (options.matchSubstring)
|
||||
pass = received.includes(expected as string);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Expect } from './types';
|
||||
import type { TestInfoImpl } from './types';
|
||||
import util from 'util';
|
||||
import path from 'path';
|
||||
import type { TestError, Location } from './types';
|
||||
@ -71,9 +71,11 @@ export async function raceAgainstDeadline<T>(promise: Promise<T>, deadline: numb
|
||||
return (new DeadlineRunner(promise, deadline)).result;
|
||||
}
|
||||
|
||||
export async function pollUntilDeadline(state: ReturnType<Expect['getState']>, func: (remainingTime: number) => Promise<boolean>, pollTime: number | undefined, deadlinePromise: Promise<void>): Promise<void> {
|
||||
const playwrightActionTimeout = (state as any).playwrightActionTimeout;
|
||||
pollTime = pollTime === 0 ? 0 : pollTime || playwrightActionTimeout;
|
||||
export async function pollUntilDeadline(testInfo: TestInfoImpl, func: (remainingTime: number) => Promise<boolean>, pollTime: number | undefined, deadlinePromise: Promise<void>): Promise<void> {
|
||||
let defaultExpectTimeout = testInfo.project.expect?.timeout;
|
||||
if (typeof defaultExpectTimeout === 'undefined')
|
||||
defaultExpectTimeout = 5000;
|
||||
pollTime = pollTime === 0 ? 0 : pollTime || defaultExpectTimeout;
|
||||
const deadline = pollTime ? monotonicTime() + pollTime : 0;
|
||||
|
||||
let aborted = false;
|
||||
|
@ -161,7 +161,7 @@ test('should support toHaveURL', async ({ runInlineTest }) => {
|
||||
|
||||
test('should support respect actionTimeout', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `module.exports = { use: { actionTimeout: 1000 } }`,
|
||||
'playwright.config.js': `module.exports = { expect: { timeout: 1000 } }`,
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
|
4
types/test.d.ts
vendored
4
types/test.d.ts
vendored
@ -37,6 +37,8 @@ export type UpdateSnapshots = 'all' | 'none' | 'missing';
|
||||
type FixtureDefine<TestArgs extends KeyValue = {}, WorkerArgs extends KeyValue = {}> = { test: TestType<TestArgs, WorkerArgs>, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> };
|
||||
|
||||
type ExpectSettings = {
|
||||
// Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||
timeout?: number;
|
||||
toMatchSnapshot?: {
|
||||
// Pixel match threshold.
|
||||
threshold?: number
|
||||
@ -2520,7 +2522,7 @@ export interface PlaywrightTestOptions {
|
||||
*/
|
||||
contextOptions: BrowserContextOptions;
|
||||
/**
|
||||
* Timeout for each action and expect in milliseconds. Defaults to 0 (no timeout).
|
||||
* Default timeout for each Playwright action in milliseconds, defaults to 0 (no timeout).
|
||||
*
|
||||
* This is a default timeout for all Playwright actions, same as configured via
|
||||
* [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout).
|
||||
|
2
utils/generate_types/overrides-test.d.ts
vendored
2
utils/generate_types/overrides-test.d.ts
vendored
@ -36,6 +36,8 @@ export type UpdateSnapshots = 'all' | 'none' | 'missing';
|
||||
type FixtureDefine<TestArgs extends KeyValue = {}, WorkerArgs extends KeyValue = {}> = { test: TestType<TestArgs, WorkerArgs>, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> };
|
||||
|
||||
type ExpectSettings = {
|
||||
// Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||
timeout?: number;
|
||||
toMatchSnapshot?: {
|
||||
// Pixel match threshold.
|
||||
threshold?: number
|
||||
|
Loading…
Reference in New Issue
Block a user