From a194c82659c7a23d67370951170d318b6171bae2 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Fri, 20 Oct 2023 18:17:30 +0100 Subject: [PATCH] feat: split test from index --- .npmignore | 1 + examples/todomvc-crx/src/todos.ts | 5 +- index.d.ts | 6 +- package.json | 12 +- src/index.ts | 3 - src/test.ts | 18 + src/types/test.d.ts | 7151 +++++++++++++++++++++++++++++ src/types/types.d.ts | 7 +- test.d.ts | 18 + utils/generate_test_types.js | 33 + vite.config.ts | 7 +- 11 files changed, 7241 insertions(+), 20 deletions(-) create mode 100644 src/test.ts create mode 100644 src/types/test.d.ts create mode 100644 test.d.ts create mode 100644 utils/generate_test_types.js diff --git a/.npmignore b/.npmignore index 7f10a1e2a..e3ec78dcd 100644 --- a/.npmignore +++ b/.npmignore @@ -6,6 +6,7 @@ !lib/**/*.mjs # Include generated types and entrypoint. !index.d.ts +!test.d.ts !src/types/types.d.ts !playwright/packages/playwright-core/types/types.d.ts !playwright/packages/playwright/types/test.d.ts diff --git a/examples/todomvc-crx/src/todos.ts b/examples/todomvc-crx/src/todos.ts index 3cb5d20c6..4d26b8a7e 100644 --- a/examples/todomvc-crx/src/todos.ts +++ b/examples/todomvc-crx/src/todos.ts @@ -1,4 +1,4 @@ -import { Page } from "playwright-crx"; +import { Page, expect } from "playwright-crx/test"; export async function createTodos(page: Page) { @@ -25,4 +25,7 @@ export async function createTodos(page: Page) { await newTodo.fill(item); await newTodo.press('Enter'); } + + // assertions work too + await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); } diff --git a/index.d.ts b/index.d.ts index 1ebd96761..85aae4691 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,10 +15,6 @@ */ import type { Crx } from './src/types/types'; -export type { Crx, CrxApplication, CrxRecorder } from './src/types/types'; -export type { Page, Frame, BrowserContext, Worker, JSHandle, ElementHandle, Locator, BrowserType, CDPSession, Accessibility, ElectronApplication, Android, AndroidDevice, AndroidInput, AndroidSocket, AndroidWebView, APIRequest, APIRequestContext, APIResponse, Browser, BrowserServer, ConsoleMessage, Coverage, Dialog, Download, Electron, FileChooser, FrameLocator, Keyboard, Logger, Mouse, Request, Response, Route, Selectors, Touchscreen, Tracing, Video, WebError, WebSocket, BrowserContextOptions, ViewportSize, HTTPCredentials, Geolocation, LaunchOptions, ConnectOverCDPOptions, ConnectOptions, LocatorScreenshotOptions, Cookie, PageScreenshotOptions, ChromiumBrowserContext, ChromiumBrowser, FirefoxBrowser, WebKitBrowser, ChromiumCoverage } from './playwright/packages/playwright-core/types/types'; -export type { expect, test } from './playwright/packages/playwright/types/test'; +export * from './src/types/types'; export const crx: Crx; - -export function _setUnderTest(): void; diff --git a/package.json b/package.json index 7b8f8908f..e2cefa50e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "examples:build:recorder": "npm run build --prefix ./examples/recorder-crx", "examples:build": "npm run examples:build:todomvc && npm run examples:build:recorder", "examples:clean": "rimraf ./examples/recorder-crx/dist && rimraf ./examples/todomvc-crx/dist", - "build:crx": "npm run pw:generate-injected && vite build", + "build:crx": "npm run pw:generate-injected && node ./utils/generate_test_types.js && vite build", "build": "npm run pw:ci:bundles && npm run build:crx && npm run examples:build", "clean": "npm run pw:clean && npm run examples:clean && rimraf ./lib" }, @@ -33,8 +33,14 @@ ".": { "types": "./index.d.ts", "import": "./lib/index.mjs", - "require": "./lib/index.umd.js", - "default": "./lib/index.umd.js" + "require": "./lib/index.js", + "default": "./lib/index.js" + }, + "./test": { + "types": "./test.d.ts", + "import": "./lib/test.mjs", + "require": "./lib/test.js", + "default": "./lib/test.js" }, "./package.json": "./package.json" }, diff --git a/src/index.ts b/src/index.ts index f8972754c..f5ac79f5c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,12 +19,10 @@ import './shims/global'; import './protocol/validator'; import { DispatcherConnection, RootDispatcher } from 'playwright-core/lib/server'; -import { setUnderTest } from 'playwright-core/lib/utils'; import { CrxConnection } from './client/crxConnection'; import type { CrxPlaywright as CrxPlaywrightAPI } from './client/crxPlaywright'; import { CrxPlaywright } from './server/crxPlaywright'; import { CrxPlaywrightDispatcher } from './server/dispatchers/crxPlaywrightDispatcher'; -export { expect, test } from '@playwright/test/lib/index'; const playwright = new CrxPlaywright(); @@ -48,6 +46,5 @@ clientConnection.onmessage = message => setImmediate(() => dispatcherConnection. clientConnection.toImpl = (x: any) => x ? dispatcherConnection._dispatchers.get(x._guid)!._object : dispatcherConnection._dispatchers.get(''); (playwrightAPI as any)._toImpl = clientConnection.toImpl; -export const _setUnderTest = setUnderTest; export const { _crx: crx } = playwrightAPI; export default playwrightAPI; diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 000000000..29c2fe3a4 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from '.'; +export { expect, test } from '@playwright/test/lib/index'; diff --git a/src/types/test.d.ts b/src/types/test.d.ts new file mode 100644 index 000000000..8e05ef2ca --- /dev/null +++ b/src/types/test.d.ts @@ -0,0 +1,7151 @@ +// This file is generated by /utils/generate_types/index.js +/** + * Copyright (c) Microsoft Corporation. + * Modifications copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse, PageScreenshotOptions } from './types'; +export * from './types'; + +export type ReporterDescription = + ['blob'] | ['blob', { outputDir?: string }] | + ['dot'] | + ['line'] | + ['list'] | ['list', { printSteps?: boolean }] | + ['github'] | + ['junit'] | ['junit', { outputFile?: string, stripANSIControlSequences?: boolean }] | + ['json'] | ['json', { outputFile?: string }] | + ['html'] | ['html', { outputFolder?: string, open?: 'always' | 'never' | 'on-failure', host?: string, port?: number, attachmentsBaseURL?: string }] | + ['null'] | + [string] | [string, any]; + +type UseOptions = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] }; + +/** + * Playwright Test supports running multiple test projects at the same time. This is useful for running tests in + * multiple configurations. For example, consider running tests against multiple browsers. + * + * `TestProject` encapsulates configuration specific to a single project. Projects are configured in + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects) specified in the + * [configuration file](https://playwright.dev/docs/test-configuration). Note that all properties of {@link TestProject} are available in + * the top-level {@link TestConfig}, in which case they are shared between all projects. + * + * Here is an example configuration that runs every test in Chromium, Firefox and WebKit, both Desktop and Mobile + * versions. + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * // Options shared for all projects. + * timeout: 30000, + * use: { + * ignoreHTTPSErrors: true, + * }, + * + * // Options specific to each project. + * projects: [ + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * }, + * { + * name: 'Mobile Chrome', + * use: devices['Pixel 5'], + * }, + * { + * name: 'Mobile Safari', + * use: devices['iPhone 12'], + * }, + * ], + * }); + * ``` + * + */ +export interface Project extends TestProject { + /** + * Options for all tests in this project, for example + * [testOptions.browserName](https://playwright.dev/docs/api/class-testoptions#test-options-browser-name). Learn more + * about [configuration](https://playwright.dev/docs/test-configuration) and see [available options]{@link TestOptions}. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'Chromium', + * use: { + * browserName: 'chromium', + * }, + * }, + * ], + * }); + * ``` + * + * Use [testConfig.use](https://playwright.dev/docs/api/class-testconfig#test-config-use) to change this option for + * all projects. + */ + use?: UseOptions; +} + +/** + * Playwright Test supports running multiple test projects at the same time. This is useful for running tests in + * multiple configurations. For example, consider running tests against multiple browsers. + * + * `TestProject` encapsulates configuration specific to a single project. Projects are configured in + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects) specified in the + * [configuration file](https://playwright.dev/docs/test-configuration). Note that all properties of {@link TestProject} are available in + * the top-level {@link TestConfig}, in which case they are shared between all projects. + * + * Here is an example configuration that runs every test in Chromium, Firefox and WebKit, both Desktop and Mobile + * versions. + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * // Options shared for all projects. + * timeout: 30000, + * use: { + * ignoreHTTPSErrors: true, + * }, + * + * // Options specific to each project. + * projects: [ + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * }, + * { + * name: 'Mobile Chrome', + * use: devices['Pixel 5'], + * }, + * { + * name: 'Mobile Safari', + * use: devices['iPhone 12'], + * }, + * ], + * }); + * ``` + * + */ +export interface FullProject { + /** + * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only + * run tests with "cart" in the title. Also available globally and in the [command line](https://playwright.dev/docs/test-cli) with the `-g` + * option. The regular expression will be tested against the string that consists of the test file name, + * `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * + * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + */ + grep: RegExp | RegExp[]; + /** + * Filter to only run tests with a title **not** matching one of the patterns. This is the opposite of + * [testProject.grep](https://playwright.dev/docs/api/class-testproject#test-project-grep). Also available globally + * and in the [command line](https://playwright.dev/docs/test-cli) with the `--grep-invert` option. + * + * `grepInvert` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + */ + grepInvert: RegExp | RegExp[] | null; + /** + * Metadata that will be put directly to the test report serialized as JSON. + */ + metadata: Metadata; + /** + * Project name is visible in the report and during test execution. + */ + name: string; + /** + * List of projects that need to run before any test in this project runs. Dependencies can be useful for configuring + * the global setup actions in a way that every action is in a form of a test. Passing `--no-deps` argument ignores + * the dependencies and behaves as if they were not specified. + * + * Using dependencies allows global setup to produce traces and other artifacts, see the setup steps in the test + * report, etc. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'setup', + * testMatch: /global.setup\.ts/, + * }, + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * dependencies: ['setup'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * dependencies: ['setup'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * dependencies: ['setup'], + * }, + * ], + * }); + * ``` + * + */ + dependencies: string[]; + /** + * The base directory, relative to the config file, for snapshot files created with `toMatchSnapshot`. Defaults to + * [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir). + * + * The directory for each test can be accessed by + * [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) and + * [testInfo.snapshotPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-path). + * + * This path will serve as the base directory for each test file snapshot directory. Setting `snapshotDir` to + * `'snapshots'`, the [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) + * would resolve to `snapshots/a.spec.js-snapshots`. + */ + snapshotDir: string; + /** + * The output directory for files created during test execution. Defaults to `/test-results`. + * + * This directory is cleaned at the start. When running a test, a unique subdirectory inside the + * [testProject.outputDir](https://playwright.dev/docs/api/class-testproject#test-project-output-dir) is created, + * guaranteeing that test running in parallel do not conflict. This directory can be accessed by + * [testInfo.outputDir](https://playwright.dev/docs/api/class-testinfo#test-info-output-dir) and + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path). + * + * Here is an example that uses + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path) to + * create a temporary file. + * + * ```js + * import { test, expect } from '@playwright/test'; + * import fs from 'fs'; + * + * test('example test', async ({}, testInfo) => { + * const file = testInfo.outputPath('temporary-file.txt'); + * await fs.promises.writeFile(file, 'Put some data to the file', 'utf8'); + * }); + * ``` + * + * Use [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir) to change this + * option for all projects. + */ + outputDir: string; + /** + * The number of times to repeat each test, useful for debugging flaky tests. + * + * Use [testConfig.repeatEach](https://playwright.dev/docs/api/class-testconfig#test-config-repeat-each) to change + * this option for all projects. + */ + repeatEach: number; + /** + * The maximum number of retry attempts given to failed tests. Learn more about + * [test retries](https://playwright.dev/docs/test-retries#retries). + * + * Use [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) to + * change the number of retries for a specific file or a group of tests. + * + * Use [testConfig.retries](https://playwright.dev/docs/api/class-testconfig#test-config-retries) to change this + * option for all projects. + */ + retries: number; + /** + * Name of a project that needs to run after this and all dependent projects have finished. Teardown is useful to + * cleanup any resources acquired by this project. + * + * Passing `--no-deps` argument ignores + * [testProject.teardown](https://playwright.dev/docs/api/class-testproject#test-project-teardown) and behaves as if + * it was not specified. + * + * **Usage** + * + * A common pattern is a "setup" dependency that has a corresponding "teardown": + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'setup', + * testMatch: /global.setup\.ts/, + * teardown: 'teardown', + * }, + * { + * name: 'teardown', + * testMatch: /global.teardown\.ts/, + * }, + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * dependencies: ['setup'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * dependencies: ['setup'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * dependencies: ['setup'], + * }, + * ], + * }); + * ``` + * + */ + teardown?: string; + /** + * Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file. + * + * Each project can use a different directory. Here is an example that runs smoke tests in three browsers and all + * other tests in stable Chrome browser. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'Smoke Chromium', + * testDir: './smoke-tests', + * use: { + * browserName: 'chromium', + * } + * }, + * { + * name: 'Smoke WebKit', + * testDir: './smoke-tests', + * use: { + * browserName: 'webkit', + * } + * }, + * { + * name: 'Smoke Firefox', + * testDir: './smoke-tests', + * use: { + * browserName: 'firefox', + * } + * }, + * { + * name: 'Chrome Stable', + * testDir: './', + * use: { + * browserName: 'chromium', + * channel: 'chrome', + * } + * }, + * ], + * }); + * ``` + * + * Use [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir) to change this + * option for all projects. + */ + testDir: string; + /** + * Files matching one of these patterns are not executed as test files. Matching is performed against the absolute + * file path. Strings are treated as glob patterns. + * + * For example, `'**\/test-assets/**'` will ignore any files in the `test-assets` directory. + * + * Use [testConfig.testIgnore](https://playwright.dev/docs/api/class-testconfig#test-config-test-ignore) to change + * this option for all projects. + */ + testIgnore: string | RegExp | (string | RegExp)[]; + /** + * Only the files matching one of these patterns are executed as test files. Matching is performed against the + * absolute file path. Strings are treated as glob patterns. + * + * By default, Playwright looks for files matching the following glob pattern: `**\/*.@(spec|test).?(c|m)[jt]s?(x)`. + * This means JavaScript or TypeScript files with `".test"` or `".spec"` suffix, for example + * `login-screen.wrong-credentials.spec.ts`. + * + * Use [testConfig.testMatch](https://playwright.dev/docs/api/class-testconfig#test-config-test-match) to change this + * option for all projects. + */ + testMatch: string | RegExp | (string | RegExp)[]; + /** + * Timeout for each test in milliseconds. Defaults to 30 seconds. + * + * This is a base timeout for all tests. Each test can configure its own timeout with + * [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout). Each file or a group of + * tests can configure the timeout with + * [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure). + * + * Use [testConfig.timeout](https://playwright.dev/docs/api/class-testconfig#test-config-timeout) to change this + * option for all projects. + */ + timeout: number; + /** + * Options for all tests in this project, for example + * [testOptions.browserName](https://playwright.dev/docs/api/class-testoptions#test-options-browser-name). Learn more + * about [configuration](https://playwright.dev/docs/test-configuration) and see [available options]{@link TestOptions}. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'Chromium', + * use: { + * browserName: 'chromium', + * }, + * }, + * ], + * }); + * ``` + * + * Use [testConfig.use](https://playwright.dev/docs/api/class-testconfig#test-config-use) to change this option for + * all projects. + */ + use: UseOptions; +} + +type LiteralUnion = T | (U & { zz_IGNORE_ME?: never }); + +/** + * Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` + * or `testDir`. These options are described in the {@link TestConfig} object in the + * [configuration file](https://playwright.dev/docs/test-configuration). + * + * Playwright Test supports running multiple test projects at the same time. Project-specific options should be put to + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects), but top-level {@link + * TestConfig} can also define base options shared between all projects. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * timeout: 30000, + * globalTimeout: 600000, + * reporter: 'list', + * testDir: './tests', + * }); + * ``` + * + */ +interface TestConfig { + /** + * The list of reporters to use. Each reporter can be: + * - A builtin reporter name like `'list'` or `'json'`. + * - A module name like `'my-awesome-reporter'`. + * - A relative path to the reporter like `'./reporters/my-awesome-reporter.js'`. + * + * You can pass options to the reporter in a tuple like `['json', { outputFile: './report.json' }]`. + * + * Learn more in the [reporters guide](https://playwright.dev/docs/test-reporters). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * reporter: 'line', + * }); + * ``` + * + */ + reporter?: LiteralUnion<'list'|'dot'|'line'|'github'|'json'|'junit'|'null'|'html', string> | ReporterDescription[]; + /** + * Launch a development web server (or multiple) during the tests. + * + * **Details** + * + * If the port is specified, Playwright Test will wait for it to be available on `127.0.0.1` or `::1`, before running + * the tests. If the url is specified, Playwright Test will wait for the URL to return a 2xx, 3xx, 400, 401, 402, or + * 403 status code before running the tests. + * + * For continuous integration, you may want to use the `reuseExistingServer: !process.env.CI` option which does not + * use an existing server on the CI. To see the stdout, you can set the `DEBUG=pw:webserver` environment variable. + * + * The `port` (but not the `url`) gets passed over to Playwright as a + * [testOptions.baseURL](https://playwright.dev/docs/api/class-testoptions#test-options-base-url). For example port + * `8080` produces `baseURL` equal `http://localhost:8080`. If `webServer` is specified as an array, you must + * explicitly configure the `baseURL` (even if it only has one entry). + * + * **NOTE** It is also recommended to specify + * [testOptions.baseURL](https://playwright.dev/docs/api/class-testoptions#test-options-base-url) in the config, so + * that tests could use relative urls. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * webServer: { + * command: 'npm run start', + * url: 'http://127.0.0.1:3000', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * }, + * use: { + * baseURL: 'http://localhost:3000/', + * }, + * }); + * ``` + * + * Now you can use a relative path when navigating the page: + * + * ```js + * // test.spec.ts + * import { test } from '@playwright/test'; + * + * test('test', async ({ page }) => { + * // This will result in http://localhost:3000/foo + * await page.goto('/foo'); + * }); + * ``` + * + * Multiple web servers (or background processes) can be launched: + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * webServer: [ + * { + * command: 'npm run start', + * url: 'http://127.0.0.1:3000', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * }, + * { + * command: 'npm run backend', + * url: 'http://127.0.0.1:3333', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * } + * ], + * use: { + * baseURL: 'http://127.0.0.1:3000', + * }, + * }); + * ``` + * + */ + webServer?: TestConfigWebServer | TestConfigWebServer[]; + /** + * Playwright transpiler configuration. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * build: { + * external: ['**\/*bundle.js'], + * }, + * }); + * ``` + * + */ + build?: { + /** + * Paths to exclude from the transpilation expressed as a list of glob patterns. Typically heavy JS bundles that your + * test uses are listed here. + */ + external?: Array; + }; + + /** + * Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * expect: { + * timeout: 10000, + * toMatchSnapshot: { + * maxDiffPixels: 10, + * }, + * }, + * }); + * ``` + * + */ + expect?: { + /** + * Default timeout for async expect matchers in milliseconds, defaults to 5000ms. + */ + timeout?: number; + + /** + * Configuration for the + * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * method. + */ + toHaveScreenshot?: { + /** + * an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and + * `1` (lax). `"pixelmatch"` comparator computes color difference in + * [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. + */ + threshold?: number; + + /** + * an acceptable amount of pixels that could be different, unset by default. + */ + maxDiffPixels?: number; + + /** + * an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by + * default. + */ + maxDiffPixelRatio?: number; + + /** + * See `animations` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). + * Defaults to `"disabled"`. + */ + animations?: "allow"|"disabled"; + + /** + * See `caret` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults + * to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * See `scale` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults + * to `"css"`. + */ + scale?: "css"|"device"; + }; + + /** + * Configuration for the + * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) + * method. + */ + toMatchSnapshot?: { + /** + * an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and + * `1` (lax). `"pixelmatch"` comparator computes color difference in + * [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. + */ + threshold?: number; + + /** + * an acceptable amount of pixels that could be different, unset by default. + */ + maxDiffPixels?: number; + + /** + * an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by + * default. + */ + maxDiffPixelRatio?: number; + }; + }; + + /** + * Whether to exit with an error if any tests or groups are marked as + * [test.only(title, testFunction)](https://playwright.dev/docs/api/class-test#test-only) or + * [test.describe.only(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-only). Useful on CI. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * forbidOnly: !!process.env.CI, + * }); + * ``` + * + */ + forbidOnly?: boolean; + + /** + * Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the + * same time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same + * worker process. + * + * You can configure entire test run to concurrently execute all tests in all files using this option. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * fullyParallel: true, + * }); + * ``` + * + */ + fullyParallel?: boolean; + + /** + * Path to the global setup file. This file will be required and run before all the tests. It must export a single + * function that takes a [`TestConfig`] argument. + * + * Learn more about [global setup and teardown](https://playwright.dev/docs/test-global-setup-teardown). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalSetup: './global-setup', + * }); + * ``` + * + */ + globalSetup?: string; + + /** + * Path to the global teardown file. This file will be required and run after all the tests. It must export a single + * function. See also + * [testConfig.globalSetup](https://playwright.dev/docs/api/class-testconfig#test-config-global-setup). + * + * Learn more about [global setup and teardown](https://playwright.dev/docs/test-global-setup-teardown). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalTeardown: './global-teardown', + * }); + * ``` + * + */ + globalTeardown?: string; + + /** + * Maximum time in milliseconds the whole test suite can run. Zero timeout (default) disables this behavior. Useful on + * CI to prevent broken setup from running too long and wasting resources. Learn more about + * [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalTimeout: process.env.CI ? 60 * 60 * 1000 : undefined, + * }); + * ``` + * + */ + globalTimeout?: number; + + /** + * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only + * run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option. The + * regular expression will be tested against the string that consists of the test file name, `test.describe` name (if + * any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * + * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * grep: /smoke/, + * }); + * ``` + * + */ + grep?: RegExp|Array; + + /** + * Filter to only run tests with a title **not** matching one of the patterns. This is the opposite of + * [testConfig.grep](https://playwright.dev/docs/api/class-testconfig#test-config-grep). Also available in the + * [command line](https://playwright.dev/docs/test-cli) with the `--grep-invert` option. + * + * `grepInvert` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * grepInvert: /manual/, + * }); + * ``` + * + */ + grepInvert?: RegExp|Array; + + /** + * Whether to skip snapshot expectations, such as `expect(value).toMatchSnapshot()` and `await + * expect(page).toHaveScreenshot()`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * ignoreSnapshots: !process.env.CI, + * }); + * ``` + * + */ + ignoreSnapshots?: boolean; + + /** + * The maximum number of test failures for the whole test suite run. After reaching this number, testing will stop and + * exit with an error. Setting to zero (default) disables this behavior. + * + * Also available in the [command line](https://playwright.dev/docs/test-cli) with the `--max-failures` and `-x` options. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * maxFailures: process.env.CI ? 1 : 0, + * }); + * ``` + * + */ + maxFailures?: number; + + /** + * Metadata that will be put directly to the test report serialized as JSON. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * metadata: 'acceptance tests', + * }); + * ``` + * + */ + metadata?: Metadata; + + /** + * Config name is visible in the report and during test execution, unless overridden by + * [testProject.name](https://playwright.dev/docs/api/class-testproject#test-project-name). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * name: 'acceptance tests', + * }); + * ``` + * + */ + name?: string; + + /** + * The output directory for files created during test execution. Defaults to `/test-results`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * outputDir: './test-results', + * }); + * ``` + * + * **Details** + * + * This directory is cleaned at the start. When running a test, a unique subdirectory inside the + * [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir) is created, + * guaranteeing that test running in parallel do not conflict. This directory can be accessed by + * [testInfo.outputDir](https://playwright.dev/docs/api/class-testinfo#test-info-output-dir) and + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path). + * + * Here is an example that uses + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path) to + * create a temporary file. + * + * ```js + * import { test, expect } from '@playwright/test'; + * import fs from 'fs'; + * + * test('example test', async ({}, testInfo) => { + * const file = testInfo.outputPath('temporary-file.txt'); + * await fs.promises.writeFile(file, 'Put some data to the file', 'utf8'); + * }); + * ``` + * + */ + outputDir?: string; + + /** + * Whether to preserve test output in the + * [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir). Defaults to + * `'always'`. + * - `'always'` - preserve output for all tests; + * - `'never'` - do not preserve output for any tests; + * - `'failures-only'` - only preserve output for failed tests. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * preserveOutput: 'always', + * }); + * ``` + * + */ + preserveOutput?: "always"|"never"|"failures-only"; + + /** + * Playwright Test supports running multiple test projects at the same time. See {@link TestProject} for more + * information. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { name: 'chromium', use: devices['Desktop Chrome'] } + * ] + * }); + * ``` + * + */ + projects?: Array; + + /** + * Whether to suppress stdio and stderr output from the tests. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * quiet: !!process.env.CI, + * }); + * ``` + * + */ + quiet?: boolean; + + /** + * The number of times to repeat each test, useful for debugging flaky tests. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * repeatEach: 3, + * }); + * ``` + * + */ + repeatEach?: number; + + /** + * Whether to report slow test files. Pass `null` to disable this feature. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * reportSlowTests: null, + * }); + * ``` + * + * **Details** + * + * Test files that took more than `threshold` milliseconds are considered slow, and the slowest ones are reported, no + * more than `max` number of them. Passing zero as `max` reports all test files that exceed the threshold. + */ + reportSlowTests?: null|{ + /** + * The maximum number of slow test files to report. Defaults to `5`. + */ + max: number; + + /** + * Test duration in milliseconds that is considered slow. Defaults to 15 seconds. + */ + threshold: number; + }; + + /** + * The maximum number of retry attempts given to failed tests. By default failing tests are not retried. Learn more + * about [test retries](https://playwright.dev/docs/test-retries#retries). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * retries: 2, + * }); + * ``` + * + */ + retries?: number; + + /** + * Shard tests and execute only the selected shard. Specify in the one-based form like `{ total: 5, current: 2 }`. + * + * Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * shard: { total: 10, current: 3 }, + * }); + * ``` + * + */ + shard?: null|{ + /** + * The total number of shards. + */ + total: number; + + /** + * The index of the shard to execute, one-based. + */ + current: number; + }; + + /** + * **NOTE** Use + * [testConfig.snapshotPathTemplate](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-path-template) + * to configure snapshot paths. + * + * The base directory, relative to the config file, for snapshot files created with `toMatchSnapshot`. Defaults to + * [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * snapshotDir: './snapshots', + * }); + * ``` + * + * **Details** + * + * The directory for each test can be accessed by + * [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) and + * [testInfo.snapshotPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-path). + * + * This path will serve as the base directory for each test file snapshot directory. Setting `snapshotDir` to + * `'snapshots'`, the [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) + * would resolve to `snapshots/a.spec.js-snapshots`. + */ + snapshotDir?: string; + + /** + * This option configures a template controlling location of snapshots generated by + * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * and + * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * testDir: './tests', + * snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + * }); + * ``` + * + * **Details** + * + * The value might include some "tokens" that will be replaced with actual values during test execution. + * + * Consider the following file structure: + * + * ```txt + * playwright.config.ts + * tests/ + * └── page/ + * └── page-click.spec.ts + * ``` + * + * And the following `page-click.spec.ts` that uses `toHaveScreenshot()` call: + * + * ```js + * // page-click.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.describe('suite', () => { + * test('test should work', async ({ page }) => { + * await expect(page).toHaveScreenshot(['foo', 'bar', 'baz.png']); + * }); + * }); + * ``` + * + * The list of supported tokens: + * - `{testDir}` - Project's + * [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir). + * - Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with + * config) + * - `{snapshotDir}` - Project's + * [testConfig.snapshotDir](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-dir). + * - Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`) + * - `{platform}` - The value of `process.platform`. + * - `{projectName}` - Project's file-system-sanitized name, if any. + * - Value: `''` (empty string). + * - `{testFileDir}` - Directories in relative path from `testDir` to **test file**. + * - Value: `page` + * - `{testFileName}` - Test file name with extension. + * - Value: `page-click.spec.ts` + * - `{testFilePath}` - Relative path from `testDir` to **test file** + * - Value: `page/page-click.spec.ts` + * - `{testName}` - File-system-sanitized test title, including parent describes but excluding file name. + * - Value: `suite-test-should-work` + * - `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the + * `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated + * snapshot name. + * - Value: `foo/bar/baz` + * - `{ext}` - snapshot extension (with dots) + * - Value: `.png` + * + * Each token can be preceded with a single character that will be used **only if** this token has non-empty value. + * + * Consider the following config: + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * snapshotPathTemplate: '__screenshots__{/projectName}/{testFilePath}/{arg}{ext}', + * testMatch: 'example.spec.ts', + * projects: [ + * { use: { browserName: 'firefox' } }, + * { name: 'chromium', use: { browserName: 'chromium' } }, + * ], + * }); + * ``` + * + * In this config: + * 1. First project **does not** have a name, so its snapshots will be stored in + * `/__screenshots__/example.spec.ts/...`. + * 1. Second project **does** have a name, so its snapshots will be stored in + * `/__screenshots__/chromium/example.spec.ts/..`. + * 1. Since `snapshotPathTemplate` resolves to relative path, it will be resolved relative to `configDir`. + * 1. Forward slashes `"/"` can be used as path separators on any platform. + */ + snapshotPathTemplate?: string; + + /** + * Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * testDir: './tests/playwright', + * }); + * ``` + * + */ + testDir?: string; + + /** + * Files matching one of these patterns are not executed as test files. Matching is performed against the absolute + * file path. Strings are treated as glob patterns. + * + * For example, `'**\/test-assets/**'` will ignore any files in the `test-assets` directory. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * testIgnore: '**\/test-assets/**', + * }); + * ``` + * + */ + testIgnore?: string|RegExp|Array; + + /** + * Only the files matching one of these patterns are executed as test files. Matching is performed against the + * absolute file path. Strings are treated as glob patterns. + * + * By default, Playwright looks for files matching the following glob pattern: `**\/*.@(spec|test).?(c|m)[jt]s?(x)`. + * This means JavaScript or TypeScript files with `".test"` or `".spec"` suffix, for example + * `login-screen.wrong-credentials.spec.ts`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * testMatch: /.*\.e2e\.js/, + * }); + * ``` + * + */ + testMatch?: string|RegExp|Array; + + /** + * Timeout for each test in milliseconds. Defaults to 30 seconds. + * + * This is a base timeout for all tests. In addition, each test can configure its own timeout with + * [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout). Learn more about + * [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * timeout: 5 * 60 * 1000, + * }); + * ``` + * + */ + timeout?: number; + + /** + * Whether to update expected snapshots with the actual results produced by the test run. Defaults to `'missing'`. + * - `'all'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be + * updated. + * - `'none'` - No snapshots are updated. + * - `'missing'` - Missing snapshots are created, for example when authoring a new test and running it for the first + * time. This is the default. + * + * Learn more about [snapshots](https://playwright.dev/docs/test-snapshots). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * updateSnapshots: 'missing', + * }); + * ``` + * + */ + updateSnapshots?: "all"|"none"|"missing"; + + /** + * The maximum number of concurrent worker processes to use for parallelizing tests. Can also be set as percentage of + * logical CPU cores, e.g. `'50%'.` + * + * Playwright Test uses worker processes to run tests. There is always at least one worker process, but more can be + * used to speed up test execution. + * + * Defaults to half of the number of logical CPU cores. Learn more about + * [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * workers: 3, + * }); + * ``` + * + */ + workers?: number|string; +} + +/** + * Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` + * or `testDir`. These options are described in the {@link TestConfig} object in the + * [configuration file](https://playwright.dev/docs/test-configuration). + * + * Playwright Test supports running multiple test projects at the same time. Project-specific options should be put to + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects), but top-level {@link + * TestConfig} can also define base options shared between all projects. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * timeout: 30000, + * globalTimeout: 600000, + * reporter: 'list', + * testDir: './tests', + * }); + * ``` + * + */ +export interface Config extends TestConfig { + /** + * Playwright Test supports running multiple test projects at the same time. See {@link TestProject} for more + * information. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { name: 'chromium', use: devices['Desktop Chrome'] } + * ] + * }); + * ``` + * + */ + projects?: Project[]; + /** + * Global options for all tests, for example + * [testOptions.browserName](https://playwright.dev/docs/api/class-testoptions#test-options-browser-name). Learn more + * about [configuration](https://playwright.dev/docs/test-configuration) and see [available options]{@link TestOptions}. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * browserName: 'chromium', + * }, + * }); + * ``` + * + */ + use?: UseOptions; +} + +export type Metadata = { [key: string]: any }; + +/** + * Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` + * or `testDir`. These options are described in the {@link TestConfig} object in the + * [configuration file](https://playwright.dev/docs/test-configuration). + * + * Playwright Test supports running multiple test projects at the same time. Project-specific options should be put to + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects), but top-level {@link + * TestConfig} can also define base options shared between all projects. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * timeout: 30000, + * globalTimeout: 600000, + * reporter: 'list', + * testDir: './tests', + * }); + * ``` + * + */ +export interface FullConfig { + /** + * Whether to exit with an error if any tests or groups are marked as + * [test.only(title, testFunction)](https://playwright.dev/docs/api/class-test#test-only) or + * [test.describe.only(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-only). Useful on CI. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * forbidOnly: !!process.env.CI, + * }); + * ``` + * + */ + forbidOnly: boolean; + /** + * Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the + * same time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same + * worker process. + * + * You can configure entire test run to concurrently execute all tests in all files using this option. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * fullyParallel: true, + * }); + * ``` + * + */ + fullyParallel: boolean; + /** + * Path to the global setup file. This file will be required and run before all the tests. It must export a single + * function that takes a [`TestConfig`] argument. + * + * Learn more about [global setup and teardown](https://playwright.dev/docs/test-global-setup-teardown). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalSetup: './global-setup', + * }); + * ``` + * + */ + globalSetup: string | null; + /** + * Path to the global teardown file. This file will be required and run after all the tests. It must export a single + * function. See also + * [testConfig.globalSetup](https://playwright.dev/docs/api/class-testconfig#test-config-global-setup). + * + * Learn more about [global setup and teardown](https://playwright.dev/docs/test-global-setup-teardown). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalTeardown: './global-teardown', + * }); + * ``` + * + */ + globalTeardown: string | null; + /** + * Maximum time in milliseconds the whole test suite can run. Zero timeout (default) disables this behavior. Useful on + * CI to prevent broken setup from running too long and wasting resources. Learn more about + * [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * globalTimeout: process.env.CI ? 60 * 60 * 1000 : undefined, + * }); + * ``` + * + */ + globalTimeout: number; + /** + * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only + * run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option. The + * regular expression will be tested against the string that consists of the test file name, `test.describe` name (if + * any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * + * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * grep: /smoke/, + * }); + * ``` + * + */ + grep: RegExp | RegExp[]; + /** + * Filter to only run tests with a title **not** matching one of the patterns. This is the opposite of + * [testConfig.grep](https://playwright.dev/docs/api/class-testconfig#test-config-grep). Also available in the + * [command line](https://playwright.dev/docs/test-cli) with the `--grep-invert` option. + * + * `grepInvert` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * grepInvert: /manual/, + * }); + * ``` + * + */ + grepInvert: RegExp | RegExp[] | null; + /** + * The maximum number of test failures for the whole test suite run. After reaching this number, testing will stop and + * exit with an error. Setting to zero (default) disables this behavior. + * + * Also available in the [command line](https://playwright.dev/docs/test-cli) with the `--max-failures` and `-x` options. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * maxFailures: process.env.CI ? 1 : 0, + * }); + * ``` + * + */ + maxFailures: number; + /** + * Metadata that will be put directly to the test report serialized as JSON. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * metadata: 'acceptance tests', + * }); + * ``` + * + */ + metadata: Metadata; + version: string; + /** + * Whether to preserve test output in the + * [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir). Defaults to + * `'always'`. + * - `'always'` - preserve output for all tests; + * - `'never'` - do not preserve output for any tests; + * - `'failures-only'` - only preserve output for failed tests. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * preserveOutput: 'always', + * }); + * ``` + * + */ + preserveOutput: 'always' | 'never' | 'failures-only'; + /** + * Playwright Test supports running multiple test projects at the same time. See {@link TestProject} for more + * information. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { name: 'chromium', use: devices['Desktop Chrome'] } + * ] + * }); + * ``` + * + */ + projects: FullProject[]; + /** + * The list of reporters to use. Each reporter can be: + * - A builtin reporter name like `'list'` or `'json'`. + * - A module name like `'my-awesome-reporter'`. + * - A relative path to the reporter like `'./reporters/my-awesome-reporter.js'`. + * + * You can pass options to the reporter in a tuple like `['json', { outputFile: './report.json' }]`. + * + * Learn more in the [reporters guide](https://playwright.dev/docs/test-reporters). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * reporter: 'line', + * }); + * ``` + * + */ + reporter: ReporterDescription[]; + /** + * Whether to report slow test files. Pass `null` to disable this feature. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * reportSlowTests: null, + * }); + * ``` + * + * **Details** + * + * Test files that took more than `threshold` milliseconds are considered slow, and the slowest ones are reported, no + * more than `max` number of them. Passing zero as `max` reports all test files that exceed the threshold. + */ + reportSlowTests: { max: number, threshold: number } | null; + rootDir: string; + /** + * Whether to suppress stdio and stderr output from the tests. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * quiet: !!process.env.CI, + * }); + * ``` + * + */ + quiet: boolean; + /** + * Shard tests and execute only the selected shard. Specify in the one-based form like `{ total: 5, current: 2 }`. + * + * Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * shard: { total: 10, current: 3 }, + * }); + * ``` + * + */ + shard: { total: number, current: number } | null; + /** + * Whether to update expected snapshots with the actual results produced by the test run. Defaults to `'missing'`. + * - `'all'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be + * updated. + * - `'none'` - No snapshots are updated. + * - `'missing'` - Missing snapshots are created, for example when authoring a new test and running it for the first + * time. This is the default. + * + * Learn more about [snapshots](https://playwright.dev/docs/test-snapshots). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * updateSnapshots: 'missing', + * }); + * ``` + * + */ + updateSnapshots: 'all' | 'none' | 'missing'; + /** + * The maximum number of concurrent worker processes to use for parallelizing tests. Can also be set as percentage of + * logical CPU cores, e.g. `'50%'.` + * + * Playwright Test uses worker processes to run tests. There is always at least one worker process, but more can be + * used to speed up test execution. + * + * Defaults to half of the number of logical CPU cores. Learn more about + * [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * workers: 3, + * }); + * ``` + * + */ + workers: number; + /** + * Launch a development web server (or multiple) during the tests. + * + * **Details** + * + * If the port is specified, Playwright Test will wait for it to be available on `127.0.0.1` or `::1`, before running + * the tests. If the url is specified, Playwright Test will wait for the URL to return a 2xx, 3xx, 400, 401, 402, or + * 403 status code before running the tests. + * + * For continuous integration, you may want to use the `reuseExistingServer: !process.env.CI` option which does not + * use an existing server on the CI. To see the stdout, you can set the `DEBUG=pw:webserver` environment variable. + * + * The `port` (but not the `url`) gets passed over to Playwright as a + * [testOptions.baseURL](https://playwright.dev/docs/api/class-testoptions#test-options-base-url). For example port + * `8080` produces `baseURL` equal `http://localhost:8080`. If `webServer` is specified as an array, you must + * explicitly configure the `baseURL` (even if it only has one entry). + * + * **NOTE** It is also recommended to specify + * [testOptions.baseURL](https://playwright.dev/docs/api/class-testoptions#test-options-base-url) in the config, so + * that tests could use relative urls. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * webServer: { + * command: 'npm run start', + * url: 'http://127.0.0.1:3000', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * }, + * use: { + * baseURL: 'http://localhost:3000/', + * }, + * }); + * ``` + * + * Now you can use a relative path when navigating the page: + * + * ```js + * // test.spec.ts + * import { test } from '@playwright/test'; + * + * test('test', async ({ page }) => { + * // This will result in http://localhost:3000/foo + * await page.goto('/foo'); + * }); + * ``` + * + * Multiple web servers (or background processes) can be launched: + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * webServer: [ + * { + * command: 'npm run start', + * url: 'http://127.0.0.1:3000', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * }, + * { + * command: 'npm run backend', + * url: 'http://127.0.0.1:3333', + * timeout: 120 * 1000, + * reuseExistingServer: !process.env.CI, + * } + * ], + * use: { + * baseURL: 'http://127.0.0.1:3000', + * }, + * }); + * ``` + * + */ + webServer: TestConfigWebServer | null; + configFile?: string; +} + +export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted'; + +/** + * `WorkerInfo` contains information about the worker that is running tests and is available to worker-scoped + * fixtures. `WorkerInfo` is a subset of {@link TestInfo} that is available in many other places. + */ +export interface WorkerInfo { + /** + * Processed configuration from the [configuration file](https://playwright.dev/docs/test-configuration). + */ + config: FullConfig; + /** + * Processed project configuration from the [configuration file](https://playwright.dev/docs/test-configuration). + */ + project: FullProject; + /** + * The index of the worker between `0` and `workers - 1`. It is guaranteed that workers running at the same time have + * a different `parallelIndex`. When a worker is restarted, for example after a failure, the new worker process has + * the same `parallelIndex`. + * + * Also available as `process.env.TEST_PARALLEL_INDEX`. Learn more about + * [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + */ + parallelIndex: number; + + /** + * The unique index of the worker process that is running the test. When a worker is restarted, for example after a + * failure, the new worker process gets a new unique `workerIndex`. + * + * Also available as `process.env.TEST_WORKER_INDEX`. Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) + * with Playwright Test. + */ + workerIndex: number; +} + +/** + * `TestInfo` contains information about currently running test. It is available to test functions, + * [test.beforeEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-each-1), + * [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each-1), + * [test.beforeAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-all-1) and + * [test.afterAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-all-1) hooks, and test-scoped + * fixtures. `TestInfo` provides utilities to control test execution: attach files, update test timeout, determine + * which test is currently running and whether it was retried, etc. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }, testInfo) => { + * expect(testInfo.title).toBe('basic test'); + * await page.screenshot(testInfo.outputPath('screenshot.png')); + * }); + * ``` + * + */ +export interface TestInfo { + /** + * Processed configuration from the [configuration file](https://playwright.dev/docs/test-configuration). + */ + config: FullConfig; + /** + * Processed project configuration from the [configuration file](https://playwright.dev/docs/test-configuration). + */ + project: FullProject; + /** + * Attach a value or a file from disk to the current test. Some reporters show test attachments. Either `path` or + * `body` must be specified, but not both. + * + * For example, you can attach a screenshot to the test: + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }, testInfo) => { + * await page.goto('https://playwright.dev'); + * const screenshot = await page.screenshot(); + * await testInfo.attach('screenshot', { body: screenshot, contentType: 'image/png' }); + * }); + * ``` + * + * Or you can attach files returned by your APIs: + * + * ```js + * import { test, expect } from '@playwright/test'; + * import { download } from './my-custom-helpers'; + * + * test('basic test', async ({}, testInfo) => { + * const tmpPath = await download('a'); + * await testInfo.attach('downloaded', { path: tmpPath }); + * }); + * ``` + * + * **NOTE** [testInfo.attach(name[, options])](https://playwright.dev/docs/api/class-testinfo#test-info-attach) + * automatically takes care of copying attached files to a location that is accessible to reporters. You can safely + * remove the attachment after awaiting the attach call. + * @param name Attachment name. The name will also be sanitized and used as the prefix of file name when saving to disk. + * @param options + */ + attach(name: string, options?: { + /** + * Attachment body. Mutually exclusive with `path`. + */ + body?: string|Buffer; + + /** + * Content type of this attachment to properly present in the report, for example `'application/json'` or + * `'image/png'`. If omitted, content type is inferred based on the `path`, or defaults to `text/plain` for [string] + * attachments and `application/octet-stream` for [Buffer] attachments. + */ + contentType?: string; + + /** + * Path on the filesystem to the attached file. Mutually exclusive with `body`. + */ + path?: string; + }): Promise; + + /** + * Marks the currently running test as "should fail". Playwright Test runs this test and ensures that it is actually + * failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is + * fixed. This is similar to [test.fail()](https://playwright.dev/docs/api/class-test#test-fail-1). + */ + fail(): void; + + /** + * Conditionally mark the currently running test as "should fail" with an optional description. This is similar to + * [test.fail(condition[, description])](https://playwright.dev/docs/api/class-test#test-fail-2). + * @param condition Test is marked as "should fail" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fail(condition: boolean, description?: string): void; + + /** + * Mark a test as "fixme", with the intention to fix it. Test is immediately aborted. This is similar to + * [test.fixme()](https://playwright.dev/docs/api/class-test#test-fixme-2). + */ + fixme(): void; + + /** + * Conditionally mark the currently running test as "fixme" with an optional description. This is similar to + * [test.fixme(condition[, description])](https://playwright.dev/docs/api/class-test#test-fixme-3). + * @param condition Test is marked as "fixme" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fixme(condition: boolean, description?: string): void; + + /** + * Returns a path inside the [testInfo.outputDir](https://playwright.dev/docs/api/class-testinfo#test-info-output-dir) + * where the test can safely put a temporary file. Guarantees that tests running in parallel will not interfere with + * each other. + * + * ```js + * import { test, expect } from '@playwright/test'; + * import fs from 'fs'; + * + * test('example test', async ({}, testInfo) => { + * const file = testInfo.outputPath('dir', 'temporary-file.txt'); + * await fs.promises.writeFile(file, 'Put some data to the dir/temporary-file.txt', 'utf8'); + * }); + * ``` + * + * > Note that `pathSegments` accepts path segments to the test output directory such as + * `testInfo.outputPath('relative', 'path', 'to', 'output')`. + * > However, this path must stay within the + * [testInfo.outputDir](https://playwright.dev/docs/api/class-testinfo#test-info-output-dir) directory for each test + * (i.e. `test-results/a-test-title`), otherwise it will throw. + * @param pathSegments Path segments to append at the end of the resulting path. + */ + outputPath(...pathSegments: Array): string; + + /** + * Changes the timeout for the currently running test. Zero means no timeout. Learn more about + * [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * Timeout is usually specified in the [configuration file](https://playwright.dev/docs/test-configuration), but it could be useful to + * change the timeout in certain scenarios: + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach(async ({ page }, testInfo) => { + * // Extend timeout for all tests running this hook by 30 seconds. + * testInfo.setTimeout(testInfo.timeout + 30000); + * }); + * ``` + * + * @param timeout Timeout in milliseconds. + */ + setTimeout(timeout: number): void; + + /** + * Unconditionally skip the currently running test. Test is immediately aborted. This is similar to + * [test.skip()](https://playwright.dev/docs/api/class-test#test-skip-2). + */ + skip(): void; + + /** + * Conditionally skips the currently running test with an optional description. This is similar to + * [test.skip(condition[, description])](https://playwright.dev/docs/api/class-test#test-skip-3). + * @param condition A skip condition. Test is skipped when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + skip(condition: boolean, description?: string): void; + + /** + * Marks the currently running test as "slow", giving it triple the default timeout. This is similar to + * [test.slow()](https://playwright.dev/docs/api/class-test#test-slow-1). + */ + slow(): void; + + /** + * Conditionally mark the currently running test as "slow" with an optional description, giving it triple the default + * timeout. This is similar to + * [test.slow(condition[, description])](https://playwright.dev/docs/api/class-test#test-slow-2). + * @param condition Test is marked as "slow" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + slow(condition: boolean, description?: string): void; + + /** + * Returns a path to a snapshot file with the given `pathSegments`. Learn more about + * [snapshots](https://playwright.dev/docs/test-snapshots). + * + * > Note that `pathSegments` accepts path segments to the snapshot file such as `testInfo.snapshotPath('relative', + * 'path', 'to', 'snapshot.png')`. + * > However, this path must stay within the snapshots directory for each test file (i.e. `a.spec.js-snapshots`), + * otherwise it will throw. + * @param pathSegments The name of the snapshot or the path segments to define the snapshot file path. Snapshots with the same name in the + * same test file are expected to be the same. + */ + snapshotPath(...pathSegments: Array): string; + + /** + * The list of annotations applicable to the current test. Includes annotations from the test, annotations from all + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) groups the test + * belongs to and file-level annotations for the test file. + * + * Learn more about [test annotations](https://playwright.dev/docs/test-annotations). + */ + annotations: Array<{ + /** + * Annotation type, for example `'skip'` or `'fail'`. + */ + type: string; + + /** + * Optional description. + */ + description?: string; + }>; + + /** + * The list of files or buffers attached to the current test. Some reporters show test attachments. + * + * To add an attachment, use + * [testInfo.attach(name[, options])](https://playwright.dev/docs/api/class-testinfo#test-info-attach) instead of + * directly pushing onto this array. + */ + attachments: Array<{ + /** + * Attachment name. + */ + name: string; + + /** + * Content type of this attachment to properly present in the report, for example `'application/json'` or + * `'image/png'`. + */ + contentType: string; + + /** + * Optional path on the filesystem to the attached file. + */ + path?: string; + + /** + * Optional attachment body used instead of a file. + */ + body?: Buffer; + }>; + + /** + * Column number where the currently running test is declared. + */ + column: number; + + /** + * The number of milliseconds the test took to finish. Always zero before the test finishes, either successfully or + * not. Can be used in [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each-1) + * hook. + */ + duration: number; + + /** + * First error thrown during test execution, if any. This is equal to the first element in + * [testInfo.errors](https://playwright.dev/docs/api/class-testinfo#test-info-errors). + */ + error?: TestInfoError; + + /** + * Errors thrown during test execution, if any. + */ + errors: Array; + + /** + * Expected status for the currently running test. This is usually `'passed'`, except for a few cases: + * - `'skipped'` for skipped tests, e.g. with [test.skip()](https://playwright.dev/docs/api/class-test#test-skip-2); + * - `'failed'` for tests marked as failed with + * [test.fail()](https://playwright.dev/docs/api/class-test#test-fail-1). + * + * Expected status is usually compared with the actual + * [testInfo.status](https://playwright.dev/docs/api/class-testinfo#test-info-status): + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.afterEach(async ({}, testInfo) => { + * if (testInfo.status !== testInfo.expectedStatus) + * console.log(`${testInfo.title} did not run as expected!`); + * }); + * ``` + * + */ + expectedStatus: "passed"|"failed"|"timedOut"|"skipped"|"interrupted"; + + /** + * Absolute path to a file where the currently running test is declared. + */ + file: string; + + /** + * Test function as passed to `test(title, testFunction)`. + */ + fn: Function; + + /** + * Line number where the currently running test is declared. + */ + line: number; + + /** + * Absolute path to the output directory for this specific test run. Each test run gets its own directory so they + * cannot conflict. + */ + outputDir: string; + + /** + * The index of the worker between `0` and `workers - 1`. It is guaranteed that workers running at the same time have + * a different `parallelIndex`. When a worker is restarted, for example after a failure, the new worker process has + * the same `parallelIndex`. + * + * Also available as `process.env.TEST_PARALLEL_INDEX`. Learn more about + * [parallelism and sharding](https://playwright.dev/docs/test-parallel) with Playwright Test. + */ + parallelIndex: number; + + /** + * Specifies a unique repeat index when running in "repeat each" mode. This mode is enabled by passing `--repeat-each` + * to the [command line](https://playwright.dev/docs/test-cli). + */ + repeatEachIndex: number; + + /** + * Specifies the retry number when the test is retried after a failure. The first test run has + * [testInfo.retry](https://playwright.dev/docs/api/class-testinfo#test-info-retry) equal to zero, the first retry has + * it equal to one, and so on. Learn more about [retries](https://playwright.dev/docs/test-retries#retries). + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach(async ({}, testInfo) => { + * // You can access testInfo.retry in any hook or fixture. + * if (testInfo.retry > 0) + * console.log(`Retrying!`); + * }); + * + * test('my test', async ({ page }, testInfo) => { + * // Here we clear some server-side state when retrying. + * if (testInfo.retry) + * await cleanSomeCachesOnTheServer(); + * // ... + * }); + * ``` + * + */ + retry: number; + + /** + * Absolute path to the snapshot output directory for this specific test. Each test suite gets its own directory so + * they cannot conflict. + * + * This property does not account for the + * [testProject.snapshotPathTemplate](https://playwright.dev/docs/api/class-testproject#test-project-snapshot-path-template) + * configuration. + */ + snapshotDir: string; + + /** + * **NOTE** Use of [testInfo.snapshotSuffix](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-suffix) + * is discouraged. Please use + * [testConfig.snapshotPathTemplate](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-path-template) + * to configure snapshot paths. + * + * Suffix used to differentiate snapshots between multiple test configurations. For example, if snapshots depend on + * the platform, you can set `testInfo.snapshotSuffix` equal to `process.platform`. In this case + * `expect(value).toMatchSnapshot(snapshotName)` will use different snapshots depending on the platform. Learn more + * about [snapshots](https://playwright.dev/docs/test-snapshots). + */ + snapshotSuffix: string; + + /** + * Actual status for the currently running test. Available after the test has finished in + * [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each-1) hook and fixtures. + * + * Status is usually compared with the + * [testInfo.expectedStatus](https://playwright.dev/docs/api/class-testinfo#test-info-expected-status): + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.afterEach(async ({}, testInfo) => { + * if (testInfo.status !== testInfo.expectedStatus) + * console.log(`${testInfo.title} did not run as expected!`); + * }); + * ``` + * + */ + status?: "passed"|"failed"|"timedOut"|"skipped"|"interrupted"; + + /** + * Output written to `process.stderr` or `console.error` during the test execution. + */ + stderr: Array; + + /** + * Output written to `process.stdout` or `console.log` during the test execution. + */ + stdout: Array; + + /** + * Test id matching the test case id in the reporter API. + */ + testId: string; + + /** + * Timeout in milliseconds for the currently running test. Zero means no timeout. Learn more about + * [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * Timeout is usually specified in the [configuration file](https://playwright.dev/docs/test-configuration) + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach(async ({ page }, testInfo) => { + * // Extend timeout for all tests running this hook by 30 seconds. + * testInfo.setTimeout(testInfo.timeout + 30000); + * }); + * ``` + * + */ + timeout: number; + + /** + * The title of the currently running test as passed to `test(title, testFunction)`. + */ + title: string; + + /** + * The full title path starting with the project. + */ + titlePath: Array; + + /** + * The unique index of the worker process that is running the test. When a worker is restarted, for example after a + * failure, the new worker process gets a new unique `workerIndex`. + * + * Also available as `process.env.TEST_WORKER_INDEX`. Learn more about [parallelism and sharding](https://playwright.dev/docs/test-parallel) + * with Playwright Test. + */ + workerIndex: number; +} + +interface SuiteFunction { + /** + * Declares a group of tests. + * + * **Usage** + * + * ```js + * test.describe('two tests', () => { + * test('one', async ({ page }) => { + * // ... + * }); + * + * test('two', async ({ page }) => { + * // ... + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1). Any tests added in + * this callback will belong to the group. + */ + (title: string, callback: () => void): void; + /** + * Declares an anonymous group of tests. This is convenient to give a group of tests a common option with + * [test.use(options)](https://playwright.dev/docs/api/class-test#test-use). + * + * **Usage** + * + * ```js + * test.describe(() => { + * test.use({ colorScheme: 'dark' }); + * + * test('one', async ({ page }) => { + * // ... + * }); + * + * test('two', async ({ page }) => { + * // ... + * }); + * }); + * ``` + * + * @param callback A callback that is run immediately when calling + * [test.describe(callback)](https://playwright.dev/docs/api/class-test#test-describe-2). Any tests added in this + * callback will belong to the group. + */ + (callback: () => void): void; +} + +interface TestFunction { + (title: string, testFunction: (args: TestArgs, testInfo: TestInfo) => Promise | void): void; +} + +/** + * Playwright Test provides a `test` function to declare tests and `expect` function to write assertions. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }) => { + * await page.goto('https://playwright.dev/'); + * const name = await page.innerText('.navbar__title'); + * expect(name).toBe('Playwright'); + * }); + * ``` + * + */ +export interface TestType extends TestFunction { + /** + * Declares a focused test. If there are some focused tests or suites, all of them will be run but nothing else. + * + * **Usage** + * + * ```js + * test.only('focus this test', async ({ page }) => { + * // Run only focused tests in the entire project. + * }); + * ``` + * + * @param title Test title. + * @param testFunction Test function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + only: TestFunction; + /** + * Declares a group of tests. + * + * **Usage** + * + * ```js + * test.describe('two tests', () => { + * test('one', async ({ page }) => { + * // ... + * }); + * + * test('two', async ({ page }) => { + * // ... + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1). Any tests added in + * this callback will belong to the group. + */ + describe: SuiteFunction & { + /** + * Declares a focused group of tests. If there are some focused tests or suites, all of them will be run but nothing + * else. + * + * **Usage** + * + * ```js + * test.describe.only('focused group', () => { + * test('in the focused group', async ({ page }) => { + * // This test will run + * }); + * }); + * test('not in the focused group', async ({ page }) => { + * // This test will not run + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.only(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-only). Any tests + * added in this callback will belong to the group. + */ + only: SuiteFunction; + /** + * Declares a skipped test group, similarly to + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1). Tests in the skipped + * group are never run. + * + * **Usage** + * + * ```js + * test.describe.skip('skipped group', () => { + * test('example', async ({ page }) => { + * // This test will not run + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.skip(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-skip). Any tests + * added in this callback will belong to the group, and will not be run. + */ + skip: SuiteFunction; + /** + * Declares a test group similarly to + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1). Tests in this group + * are marked as "fixme" and will not be executed. + * + * **Usage** + * + * ```js + * test.describe.fixme('broken tests', () => { + * test('example', async ({ page }) => { + * // This test will not run + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.fixme(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-fixme). Any tests + * added in this callback will belong to the group, and will not be run. + */ + fixme: SuiteFunction; + /** + * **NOTE** See [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) for + * the preferred way of configuring the execution mode. + * + * Declares a group of tests that should always be run serially. If one of the tests fails, all subsequent tests are + * skipped. All tests in a group are retried together. + * + * **NOTE** Using serial is not recommended. It is usually better to make your tests isolated, so they can be run + * independently. + * + * **Usage** + * + * ```js + * test.describe.serial('group', () => { + * test('runs first', async ({ page }) => {}); + * test('runs second', async ({ page }) => {}); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.serial(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-serial). Any tests + * added in this callback will belong to the group. + */ + serial: SuiteFunction & { + /** + * **NOTE** See [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) for + * the preferred way of configuring the execution mode. + * + * Declares a focused group of tests that should always be run serially. If one of the tests fails, all subsequent + * tests are skipped. All tests in a group are retried together. If there are some focused tests or suites, all of + * them will be run but nothing else. + * + * **NOTE** Using serial is not recommended. It is usually better to make your tests isolated, so they can be run + * independently. + * + * **Usage** + * + * ```js + * test.describe.serial.only('group', () => { + * test('runs first', async ({ page }) => { + * }); + * test('runs second', async ({ page }) => { + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.serial.only(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-serial-only). + * Any tests added in this callback will belong to the group. + */ + only: SuiteFunction; + }; + /** + * **NOTE** See [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) for + * the preferred way of configuring the execution mode. + * + * Declares a group of tests that could be run in parallel. By default, tests in a single test file run one after + * another, but using + * [test.describe.parallel(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-parallel) allows + * them to run in parallel. + * + * **Usage** + * + * ```js + * test.describe.parallel('group', () => { + * test('runs in parallel 1', async ({ page }) => {}); + * test('runs in parallel 2', async ({ page }) => {}); + * }); + * ``` + * + * Note that parallel tests are executed in separate processes and cannot share any state or global variables. Each of + * the parallel tests executes all relevant hooks. + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.parallel(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-parallel). Any + * tests added in this callback will belong to the group. + */ + parallel: SuiteFunction & { + /** + * **NOTE** See [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) for + * the preferred way of configuring the execution mode. + * + * Declares a focused group of tests that could be run in parallel. This is similar to + * [test.describe.parallel(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-parallel), but + * focuses the group. If there are some focused tests or suites, all of them will be run but nothing else. + * + * **Usage** + * + * ```js + * test.describe.parallel.only('group', () => { + * test('runs in parallel 1', async ({ page }) => {}); + * test('runs in parallel 2', async ({ page }) => {}); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling + * [test.describe.parallel.only(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-parallel-only). + * Any tests added in this callback will belong to the group. + */ + only: SuiteFunction; + }; + /** + * Configures the enclosing scope. Can be executed either on the top level or inside a describe. Configuration applies + * to the entire scope, regardless of whether it run before or after the test declaration. + * + * Learn more about the execution modes [here](https://playwright.dev/docs/test-parallel). + * + * **Usage** + * - Running tests in parallel. + * + * ```js + * // Run all the tests in the file concurrently using parallel workers. + * test.describe.configure({ mode: 'parallel' }); + * test('runs in parallel 1', async ({ page }) => {}); + * test('runs in parallel 2', async ({ page }) => {}); + * ``` + * + * - Running tests serially, retrying from the start. + * + * **NOTE** Running serially is not recommended. It is usually better to make your tests isolated, so they can be + * run independently. + * + * ```js + * // Annotate tests as inter-dependent. + * test.describe.configure({ mode: 'serial' }); + * test('runs first', async ({ page }) => {}); + * test('runs second', async ({ page }) => {}); + * ``` + * + * - Configuring retries and timeout for each test. + * + * ```js + * // Each test in the file will be retried twice and have a timeout of 20 seconds. + * test.describe.configure({ retries: 2, timeout: 20_000 }); + * test('runs first', async ({ page }) => {}); + * test('runs second', async ({ page }) => {}); + * ``` + * + * - Run multiple describes in parallel, but tests inside each describe in order. + * + * ```js + * test.describe.configure({ mode: 'parallel' }); + * + * test.describe('A, runs in parallel with B', () => { + * test.describe.configure({ mode: 'default' }); + * test('in order A1', async ({ page }) => {}); + * test('in order A2', async ({ page }) => {}); + * }); + * + * test.describe('B, runs in parallel with A', () => { + * test.describe.configure({ mode: 'default' }); + * test('in order B1', async ({ page }) => {}); + * test('in order B2', async ({ page }) => {}); + * }); + * ``` + * + * @param options + */ + configure: (options: { mode?: 'default' | 'parallel' | 'serial', retries?: number, timeout?: number }) => void; + }; + /** + * Declares a skipped test, similarly to + * [test.(call)(title, testFunction)](https://playwright.dev/docs/api/class-test#test-call). Skipped test is never + * run. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.skip('broken test', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param title Test title. + * @param testFunction Test function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + skip(title: string, testFunction: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | void): void; + /** + * Unconditionally skip a test. Test is immediately aborted when you call + * [test.skip()](https://playwright.dev/docs/api/class-test#test-skip-2). + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('skipped test', async ({ page }) => { + * test.skip(); + * // ... + * }); + * ``` + * + * Unconditionally skip all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group: + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.skip(); + * + * test('skipped test 1', async ({ page }) => { + * // ... + * }); + * test('skipped test 2', async ({ page }) => { + * // ... + * }); + * ``` + * + */ + skip(): void; + /** + * Conditionally skip a test with an optional description. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('skip in WebKit', async ({ page, browserName }) => { + * test.skip(browserName === 'webkit', 'This feature is not implemented for Mac'); + * // ... + * }); + * ``` + * + * Skip from [test.beforeEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-each-1) hook: + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach(async ({ page }) => { + * test.skip(process.env.APP_VERSION === 'v1', 'There are no settings in v1'); + * await page.goto('/settings'); + * }); + * ``` + * + * @param condition A skip condition. Test is skipped when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + skip(condition: boolean, description?: string): void; + /** + * Conditionally skips all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.skip(({ browserName }) => browserName === 'webkit'); + * + * test('skip in WebKit 1', async ({ page }) => { + * // ... + * }); + * test('skip in WebKit 2', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param callback A function that returns whether to skip, based on test fixtures. Test or tests are skipped when the return value is + * `true`. + * @param description Optional description that will be reflected in a test report. + */ + skip(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void; + /** + * Declares a test to be fixed, similarly to + * [test.(call)(title, testFunction)](https://playwright.dev/docs/api/class-test#test-call). This test will not be + * run. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.fixme('test to be fixed', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param title Test title. + * @param testFunction Test function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + fixme(title: string, testFunction: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | void): void; + /** + * Mark a test as "fixme", with the intention to fix it. Test is immediately aborted when you call + * [test.fixme()](https://playwright.dev/docs/api/class-test#test-fixme-2). + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('test to be fixed', async ({ page }) => { + * test.fixme(); + * // ... + * }); + * ``` + * + * Mark all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group as "fixme". + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.fixme(); + * + * test('test to be fixed 1', async ({ page }) => { + * // ... + * }); + * test('test to be fixed 2', async ({ page }) => { + * // ... + * }); + * ``` + * + */ + fixme(): void; + /** + * Conditionally mark a test as "fixme" with an optional description. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('broken in WebKit', async ({ page, browserName }) => { + * test.fixme(browserName === 'webkit', 'This feature is not implemented on Mac yet'); + * // ... + * }); + * ``` + * + * @param condition Test is marked as "fixme" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fixme(condition: boolean, description?: string): void; + /** + * Conditionally mark all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group as "fixme". + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.fixme(({ browserName }) => browserName === 'webkit'); + * + * test('broken in WebKit 1', async ({ page }) => { + * // ... + * }); + * test('broken in WebKit 2', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param callback A function that returns whether to mark as "fixme", based on test fixtures. Test or tests are marked as "fixme" + * when the return value is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fixme(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void; + /** + * Unconditionally marks a test as "should fail". Playwright Test runs this test and ensures that it is actually + * failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is + * fixed. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('not yet ready', async ({ page }) => { + * test.fail(); + * // ... + * }); + * ``` + * + */ + fail(): void; + /** + * Conditionally mark a test as "should fail" with an optional description. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('fail in WebKit', async ({ page, browserName }) => { + * test.fail(browserName === 'webkit', 'This feature is not implemented for Mac yet'); + * // ... + * }); + * ``` + * + * @param condition Test is marked as "should fail" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fail(condition: boolean, description?: string): void; + /** + * Conditionally mark all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group as "should + * fail". + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.fail(({ browserName }) => browserName === 'webkit'); + * + * test('fail in WebKit 1', async ({ page }) => { + * // ... + * }); + * test('fail in WebKit 2', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param callback A function that returns whether to mark as "should fail", based on test fixtures. Test or tests are marked as + * "should fail" when the return value is `true`. + * @param description Optional description that will be reflected in a test report. + */ + fail(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void; + /** + * Unconditionally marks a test as "slow". Slow test will be given triple the default timeout. + * + * **Details** + * + * [test.slow()](https://playwright.dev/docs/api/class-test#test-slow-1) cannot be used in a `beforeAll` or `afterAll` + * hook. Use [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout) instead. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('slow test', async ({ page }) => { + * test.slow(); + * // ... + * }); + * ``` + * + */ + slow(): void; + /** + * Conditionally mark a test as "slow" with an optional description. Slow test will be given triple the default + * timeout. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('slow in WebKit', async ({ page, browserName }) => { + * test.slow(browserName === 'webkit', 'This feature is slow on Mac'); + * // ... + * }); + * ``` + * + * @param condition Test is marked as "slow" when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + slow(condition: boolean, description?: string): void; + /** + * Conditionally mark all tests in a file or + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group as "slow". Slow + * tests will be given triple the default timeout. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.slow(({ browserName }) => browserName === 'webkit'); + * + * test('slow in WebKit 1', async ({ page }) => { + * // ... + * }); + * test('fail in WebKit 2', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param callback A function that returns whether to mark as "slow", based on test fixtures. Test or tests are marked as "slow" when + * the return value is `true`. + * @param description Optional description that will be reflected in a test report. + */ + slow(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void; + /** + * Changes the timeout for the test. Zero means no timeout. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts). + * + * Timeout for the currently running test is available through + * [testInfo.timeout](https://playwright.dev/docs/api/class-testinfo#test-info-timeout). + * + * **Usage** + * - Changing test timeout. + * + * ```js + * test('very slow test', async ({ page }) => { + * test.setTimeout(120000); + * // ... + * }); + * ``` + * + * - Changing timeout from a slow `beforeEach` or `afterEach` hook. Note that this affects the test timeout that is + * shared with `beforeEach`/`afterEach` hooks. + * + * ```js + * test.beforeEach(async ({ page }, testInfo) => { + * // Extend timeout for all tests running this hook by 30 seconds. + * test.setTimeout(testInfo.timeout + 30000); + * }); + * ``` + * + * - Changing timeout for a `beforeAll` or `afterAll` hook. Note this affects the hook's timeout, not the test + * timeout. + * + * ```js + * test.beforeAll(async () => { + * // Set timeout for this hook. + * test.setTimeout(60000); + * }); + * ``` + * + * - Changing timeout for all tests in a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group. + * + * ```js + * test.describe('group', () => { + * // Applies to all tests in this group. + * test.describe.configure({ timeout: 60000 }); + * + * test('test one', async () => { /* ... *\/ }); + * test('test two', async () => { /* ... *\/ }); + * test('test three', async () => { /* ... *\/ }); + * }); + * ``` + * + * @param timeout Timeout in milliseconds. + */ + setTimeout(timeout: number): void; + /** + * Declares a `beforeEach` hook that is executed before each test. + * + * **Details** + * + * When called in the scope of a test file, runs before each test in the file. When called inside a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group, runs before + * each test in the group. If multiple `beforeEach` hooks are added, they will run in the order of their + * registration. + * + * You can access all the same {@link Fixtures} as the test function itself, and also the {@link TestInfo} object that + * gives a lot of useful information. For example, you can navigate the page before starting the test. + * + * You can use [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each-1) to + * teardown any resources set up in `beforeEach`. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach(async ({ page }, testInfo) => { + * console.log(`Running ${testInfo.title}`); + * await page.goto('https://my.start.url/'); + * }); + * + * test('my test', async ({ page }) => { + * expect(page.url()).toBe('https://my.start.url/'); + * }); + * ``` + * + * @param hookFunction Hook function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + beforeEach(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares a `beforeEach` hook with a title that is executed before each test. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.beforeEach('Open start URL', async ({ page }, testInfo) => { + * console.log(`Running ${testInfo.title}`); + * await page.goto('https://my.start.url/'); + * }); + * + * test('my test', async ({ page }) => { + * expect(page.url()).toBe('https://my.start.url/'); + * }); + * ``` + * + * @param title Hook title. + * @param hookFunction Hook function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + beforeEach(title: string, inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares an `afterEach` hook that is executed after each test. + * + * **Details** + * + * When called in the scope of a test file, runs after each test in the file. When called inside a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group, runs after each + * test in the group. If multiple `afterEach` hooks are added, they will run in the order of their registration. + * + * You can access all the same {@link Fixtures} as the test function itself, and also the {@link TestInfo} object that + * gives a lot of useful information. For example, you can check whether the test succeeded or failed. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.afterEach(async ({ page }, testInfo) => { + * console.log(`Finished ${testInfo.title} with status ${testInfo.status}`); + * + * if (testInfo.status !== testInfo.expectedStatus) + * console.log(`Did not run as expected, ended up at ${page.url()}`); + * }); + * + * test('my test', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param hookFunction Hook function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + afterEach(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares an `afterEach` hook with a title that is executed after each test. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.afterEach('Status check', async ({ page }, testInfo) => { + * console.log(`Finished ${testInfo.title} with status ${testInfo.status}`); + * + * if (testInfo.status !== testInfo.expectedStatus) + * console.log(`Did not run as expected, ended up at ${page.url()}`); + * }); + * + * test('my test', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param title Hook title. + * @param hookFunction Hook function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + afterEach(title: string, inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares a `beforeAll` hook that is executed once per worker process before all tests. + * + * **Details** + * + * When called in the scope of a test file, runs before all tests in the file. When called inside a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group, runs before all + * tests in the group. If multiple `beforeAll` hooks are added, they will run in the order of their registration. + * + * Note that worker process is restarted on test failures, and `beforeAll` hook runs again in the new worker. Learn + * more about [workers and failures](https://playwright.dev/docs/test-retries). + * + * You can use [test.afterAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-all-1) to teardown + * any resources set up in `beforeAll`. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.beforeAll(async () => { + * console.log('Before tests'); + * }); + * + * test.afterAll(async () => { + * console.log('After tests'); + * }); + * + * test('my test', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param hookFunction Hook function that takes one or two arguments: an object with worker fixtures and optional {@link TestInfo}. + */ + beforeAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares a `beforeAll` hook with a title that is executed once per worker process before all tests. + * + * **Usage** + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.beforeAll('Setup', async () => { + * console.log('Before tests'); + * }); + * + * test('my test', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param title Hook title. + * @param hookFunction Hook function that takes one or two arguments: an object with worker fixtures and optional {@link TestInfo}. + */ + beforeAll(title: string, inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares an `afterAll` hook that is executed once per worker after all tests. + * + * **Details** + * + * When called in the scope of a test file, runs after all tests in the file. When called inside a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group, runs after all + * tests in the group. If multiple `afterAll` hooks are added, they will run in the order of their registration. + * + * Note that worker process is restarted on test failures, and `afterAll` hook runs again in the new worker. Learn + * more about [workers and failures](https://playwright.dev/docs/test-retries). + * + * **Usage** + * + * ```js + * test.afterAll(async () => { + * console.log('Done with tests'); + * // ... + * }); + * ``` + * + * @param hookFunction Hook function that takes one or two arguments: an object with worker fixtures and optional {@link TestInfo}. + */ + afterAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Declares an `afterAll` hook with a title that is executed once per worker after all tests. + * + * **Usage** + * + * ```js + * test.afterAll('Teardown', async () => { + * console.log('Done with tests'); + * // ... + * }); + * ``` + * + * @param title Hook title. + * @param hookFunction Hook function that takes one or two arguments: an object with worker fixtures and optional {@link TestInfo}. + */ + afterAll(title: string, inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | any): void; + /** + * Specifies options or fixtures to use in a single test file or a + * [test.describe(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-1) group. Most useful to + * set an option, for example set `locale` to configure `context` fixture. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.use({ locale: 'en-US' }); + * + * test('test with locale', async ({ page }) => { + * // Default context and page have locale as specified + * }); + * ``` + * + * **Details** + * + * `test.use` can be called either in the global scope or inside `test.describe`. It is an error to call it within + * `beforeEach` or `beforeAll`. + * + * It is also possible to override a fixture by providing a function. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.use({ + * locale: async ({}, use) => { + * // Read locale from some configuration file. + * const locale = await fs.promises.readFile('test-locale', 'utf-8'); + * await use(locale); + * }, + * }); + * + * test('test with locale', async ({ page }) => { + * // Default context and page have locale as specified + * }); + * ``` + * + * @param options An object with local options. + */ + use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void; + /** + * Declares a test step that is shown in the report. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('test', async ({ page }) => { + * await test.step('Log in', async () => { + * // ... + * }); + * + * await test.step('Outer step', async () => { + * // ... + * // You can nest steps inside each other. + * await test.step('Inner step', async () => { + * // ... + * }); + * }); + * }); + * ``` + * + * **Details** + * + * The method returns the value returned by the step callback. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('test', async ({ page }) => { + * const user = await test.step('Log in', async () => { + * // ... + * return 'john'; + * }); + * expect(user).toBe('john'); + * }); + * ``` + * + * **Decorator** + * + * You can use TypeScript method decorators to turn a method into a step. Each call to the decorated method will show + * up as a step in the report. + * + * ```js + * function step(target: Function, context: ClassMethodDecoratorContext) { + * return function replacementMethod(...args: any) { + * const name = this.constructor.name + '.' + (context.name as string); + * return test.step(name, async () => { + * return await target.call(this, ...args); + * }); + * }; + * } + * + * class LoginPage { + * constructor(readonly page: Page) {} + * + * @step + * async login() { + * const account = { username: 'Alice', password: 's3cr3t' }; + * await this.page.getByLabel('Username or email address').fill(account.username); + * await this.page.getByLabel('Password').fill(account.password); + * await this.page.getByRole('button', { name: 'Sign in' }).click(); + * await expect(this.page.getByRole('button', { name: 'View profile and more' })).toBeVisible(); + * } + * } + * + * test('example', async ({ page }) => { + * const loginPage = new LoginPage(page); + * await loginPage.login(); + * }); + * ``` + * + * **Boxing** + * + * When something inside a step fails, you would usually see the error pointing to the exact action that failed. For + * example, consider the following login step: + * + * ```js + * async function login(page) { + * await test.step('login', async () => { + * const account = { username: 'Alice', password: 's3cr3t' }; + * await page.getByLabel('Username or email address').fill(account.username); + * await page.getByLabel('Password').fill(account.password); + * await page.getByRole('button', { name: 'Sign in' }).click(); + * await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible(); + * }); + * } + * + * test('example', async ({ page }) => { + * await page.goto('https://github.com/login'); + * await login(page); + * }); + * ``` + * + * ```txt + * Error: Timed out 5000ms waiting for expect(locator).toBeVisible() + * ... error details omitted ... + * + * 8 | await page.getByRole('button', { name: 'Sign in' }).click(); + * > 9 | await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible(); + * | ^ + * 10 | }); + * ``` + * + * As we see above, the test may fail with an error pointing inside the step. If you would like the error to highlight + * the "login" step instead of its internals, use the `box` option. An error inside a boxed step points to the step + * call site. + * + * ```js + * async function login(page) { + * await test.step('login', async () => { + * // ... + * }, { box: true }); // Note the "box" option here. + * } + * ``` + * + * ```txt + * Error: Timed out 5000ms waiting for expect(locator).toBeVisible() + * ... error details omitted ... + * + * 14 | await page.goto('https://github.com/login'); + * > 15 | await login(page); + * | ^ + * 16 | }); + * ``` + * + * You can also create a TypeScript decorator for a boxed step, similar to a regular step decorator above: + * + * ```js + * function boxedStep(target: Function, context: ClassMethodDecoratorContext) { + * return function replacementMethod(...args: any) { + * const name = this.constructor.name + '.' + (context.name as string); + * return test.step(name, async () => { + * return await target.call(this, ...args); + * }, { box: true }); // Note the "box" option here. + * }; + * } + * + * class LoginPage { + * constructor(readonly page: Page) {} + * + * @boxedStep + * async login() { + * // .... + * } + * } + * + * test('example', async ({ page }) => { + * const loginPage = new LoginPage(page); + * await loginPage.login(); // <-- Error will be reported on this line. + * }); + * ``` + * + * @param title Step name. + * @param body Step body. + * @param options + */ + step(title: string, body: () => T | Promise, options?: { box?: boolean }): Promise; + /** + * `expect` function can be used to create test assertions. Read more about [test assertions](https://playwright.dev/docs/test-assertions). + * + * **Usage** + * + * ```js + * test('example', async ({ page }) => { + * await test.expect(page).toHaveTitle('Title'); + * }); + * ``` + * + */ + expect: Expect<{}>; + /** + * Extends the `test` object by defining fixtures and/or options that can be used in the tests. + * + * **Usage** + * + * First define a fixture and/or an option. + * + * ```js + * import { test as base } from '@playwright/test'; + * import { TodoPage } from './todo-page'; + * + * export type Options = { defaultItem: string }; + * + * // Extend basic test by providing a "defaultItem" option and a "todoPage" fixture. + * export const test = base.extend({ + * // Define an option and provide a default value. + * // We can later override it in the config. + * defaultItem: ['Do stuff', { option: true }], + * + * // Define a fixture. Note that it can use built-in fixture "page" + * // and a new option "defaultItem". + * todoPage: async ({ page, defaultItem }, use) => { + * const todoPage = new TodoPage(page); + * await todoPage.goto(); + * await todoPage.addToDo(defaultItem); + * await use(todoPage); + * await todoPage.removeAll(); + * }, + * }); + * ``` + * + * Then use the fixture in the test. + * + * ```js + * // example.spec.ts + * import { test } from './my-test'; + * + * test('test 1', async ({ todoPage }) => { + * await todoPage.addToDo('my todo'); + * // ... + * }); + * ``` + * + * Configure the option in config file. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * import type { Options } from './my-test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'shopping', + * use: { defaultItem: 'Buy milk' }, + * }, + * { + * name: 'wellbeing', + * use: { defaultItem: 'Exercise!' }, + * }, + * ] + * }); + * ``` + * + * Learn more about [fixtures](https://playwright.dev/docs/test-fixtures) and [parametrizing tests](https://playwright.dev/docs/test-parameterize). + * @param fixtures An object containing fixtures and/or options. Learn more about [fixtures format](https://playwright.dev/docs/test-fixtures). + */ + extend(fixtures: Fixtures): TestType; + /** + * Returns information about the currently running test. This method can only be called during the test execution, + * otherwise it throws. + * + * **Usage** + * + * ```js + * test('example test', async ({ page }) => { + * // ... + * await test.info().attach('screenshot', { + * body: await page.screenshot(), + * contentType: 'image/png', + * }); + * }); + * ``` + * + */ + info(): TestInfo; +} + +type KeyValue = { [key: string]: any }; +export type TestFixture = (args: Args, use: (r: R) => Promise, testInfo: TestInfo) => any; +export type WorkerFixture = (args: Args, use: (r: R) => Promise, workerInfo: WorkerInfo) => any; +type TestFixtureValue = Exclude | TestFixture; +type WorkerFixtureValue = Exclude | WorkerFixture; +export type Fixtures = { + [K in keyof PW]?: WorkerFixtureValue | [WorkerFixtureValue, { scope: 'worker', timeout?: number | undefined }]; +} & { + [K in keyof PT]?: TestFixtureValue | [TestFixtureValue, { scope: 'test', timeout?: number | undefined }]; +} & { + [K in keyof W]?: [WorkerFixtureValue, { scope: 'worker', auto?: boolean, option?: boolean, timeout?: number | undefined }]; +} & { + [K in keyof T]?: TestFixtureValue | [TestFixtureValue, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined }]; +}; + +type BrowserName = 'chromium' | 'firefox' | 'webkit'; +type BrowserChannel = Exclude; +type ColorScheme = Exclude; +type ExtraHTTPHeaders = Exclude; +type Proxy = Exclude; +type StorageState = Exclude; +type ServiceWorkerPolicy = Exclude; +type ConnectOptions = { + /** + * A browser websocket endpoint to connect to. + */ + wsEndpoint: string; + + /** + * Additional HTTP headers to be sent with web socket connect request. + */ + headers?: { [key: string]: string; }; + + /** + * This option exposes network available on the connecting client to the browser being connected to. + * Consists of a list of rules separated by comma. + * + * Available rules: + * - Hostname pattern, for example: `example.com`, `*.org:99`, `x.*.y.com`, `*foo.org`. + * - IP literal, for example: `127.0.0.1`, `0.0.0.0:99`, `[::1]`, `[0:0::1]:99`. + * - `` that matches local loopback interfaces: `localhost`, `*.localhost`, `127.0.0.1`, `[::1]`. + + * Some common examples: + * - `"*"` to expose all network. + * - `""` to expose localhost network. + * - `"*.test.internal-domain,*.staging.internal-domain,"` to expose test/staging deployments and localhost. + */ + exposeNetwork?: string; + + /** + * Timeout in milliseconds for the connection to be established. Optional, defaults to no timeout. + */ + timeout?: number; +}; + +/** + * Playwright Test provides many options to configure test environment, {@link Browser}, {@link BrowserContext} and + * more. + * + * These options are usually provided in the [configuration file](https://playwright.dev/docs/test-configuration) through + * [testConfig.use](https://playwright.dev/docs/api/class-testconfig#test-config-use) and + * [testProject.use](https://playwright.dev/docs/api/class-testproject#test-project-use). + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * use: { + * headless: false, + * viewport: { width: 1280, height: 720 }, + * ignoreHTTPSErrors: true, + * video: 'on-first-retry', + * }, + * }); + * ``` + * + * Alternatively, with [test.use(options)](https://playwright.dev/docs/api/class-test#test-use) you can override some + * options for a file. + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * // Run tests in this file with portrait-like viewport. + * test.use({ viewport: { width: 600, height: 900 } }); + * + * test('my portrait test', async ({ page }) => { + * // ... + * }); + * ``` + * + */ +export interface PlaywrightWorkerOptions { + /** + * Name of the browser that runs tests. Defaults to `'chromium'`. Most of the time you should set `browserName` in + * your {@link TestConfig}: + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * browserName: 'firefox', + * }, + * }); + * ``` + * + */ + browserName: BrowserName; + defaultBrowserType: BrowserName; + /** + * Whether to run browser in headless mode. More details for + * [Chromium](https://developers.google.com/web/updates/2017/04/headless-chrome) and + * [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode). Defaults to `true` unless the + * `devtools` option is `true`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * headless: false + * }, + * }); + * ``` + * + */ + headless: boolean; + /** + * Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", + * "msedge", "msedge-beta", "msedge-dev", "msedge-canary". Read more about using + * [Google Chrome and Microsoft Edge](https://playwright.dev/docs/browsers#google-chrome--microsoft-edge). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'Microsoft Edge', + * use: { + * ...devices['Desktop Edge'], + * channel: 'msedge' + * }, + * }, + * ] + * }); + * ``` + * + */ + channel: BrowserChannel | undefined; + /** + * Options used to launch the browser, as passed to + * [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). Specific + * options [testOptions.headless](https://playwright.dev/docs/api/class-testoptions#test-options-headless) and + * [testOptions.channel](https://playwright.dev/docs/api/class-testoptions#test-options-channel) take priority over + * this. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'chromium', + * use: { + * ...devices['Desktop Chrome'], + * launchOptions: { + * args: ['--start-maximized'] + * } + * } + * } + * ] + * }); + * ``` + * + */ + launchOptions: Omit; + /** + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * connectOptions: { + * wsEndpoint: 'ws://localhost:5678', + * }, + * }, + * }); + * ``` + * + * When connect options are specified, default + * [fixtures.browser](https://playwright.dev/docs/api/class-fixtures#fixtures-browser), + * [fixtures.context](https://playwright.dev/docs/api/class-fixtures#fixtures-context) and + * [fixtures.page](https://playwright.dev/docs/api/class-fixtures#fixtures-page) use the remote browser instead of + * launching a browser locally, and any launch options like + * [testOptions.headless](https://playwright.dev/docs/api/class-testoptions#test-options-headless) or + * [testOptions.channel](https://playwright.dev/docs/api/class-testoptions#test-options-channel) are ignored. + */ + connectOptions: ConnectOptions | undefined; + /** + * Whether to automatically capture a screenshot after each test. Defaults to `'off'`. + * - `'off'`: Do not capture screenshots. + * - `'on'`: Capture screenshot after each test. + * - `'only-on-failure'`: Capture screenshot after each test failure. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * screenshot: 'only-on-failure', + * }, + * }); + * ``` + * + * Learn more about [automatic screenshots](https://playwright.dev/docs/test-use-options#recording-options). + */ + screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick; + /** + * Whether to record trace for each test. Defaults to `'off'`. + * - `'off'`: Do not record trace. + * - `'on'`: Record trace for each test. + * - `'retain-on-failure'`: Record trace for each test, but remove all traces from successful test runs. + * - `'on-first-retry'`: Record trace only when retrying a test for the first time. + * - `'on-all-retries'`: Record traces only when retrying for all retries. + * + * For more control, pass an object that specifies `mode` and trace features to enable. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * trace: 'on-first-retry' + * }, + * }); + * ``` + * + * Learn more about [recording trace](https://playwright.dev/docs/test-use-options#recording-options). + */ + trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean, attachments?: boolean }; + /** + * Whether to record video for each test. Defaults to `'off'`. + * - `'off'`: Do not record video. + * - `'on'`: Record video for each test. + * - `'retain-on-failure'`: Record video for each test, but remove all videos from successful test runs. + * - `'on-first-retry'`: Record video only when retrying a test for the first time. + * + * To control video size, pass an object with `mode` and `size` properties. If video size is not specified, it will be + * equal to [testOptions.viewport](https://playwright.dev/docs/api/class-testoptions#test-options-viewport) scaled + * down to fit into 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual + * picture of each page will be scaled down if necessary to fit the specified size. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * video: 'on-first-retry', + * }, + * }); + * ``` + * + * Learn more about [recording video](https://playwright.dev/docs/test-use-options#recording-options). + */ + video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize }; +} + +export type ScreenshotMode = 'off' | 'on' | 'only-on-failure'; +export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries'; +export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry'; + +/** + * Playwright Test provides many options to configure test environment, {@link Browser}, {@link BrowserContext} and + * more. + * + * These options are usually provided in the [configuration file](https://playwright.dev/docs/test-configuration) through + * [testConfig.use](https://playwright.dev/docs/api/class-testconfig#test-config-use) and + * [testProject.use](https://playwright.dev/docs/api/class-testproject#test-project-use). + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * export default defineConfig({ + * use: { + * headless: false, + * viewport: { width: 1280, height: 720 }, + * ignoreHTTPSErrors: true, + * video: 'on-first-retry', + * }, + * }); + * ``` + * + * Alternatively, with [test.use(options)](https://playwright.dev/docs/api/class-test#test-use) you can override some + * options for a file. + * + * ```js + * // example.spec.ts + * import { test, expect } from '@playwright/test'; + * + * // Run tests in this file with portrait-like viewport. + * test.use({ viewport: { width: 600, height: 900 } }); + * + * test('my portrait test', async ({ page }) => { + * // ... + * }); + * ``` + * + */ +export interface PlaywrightTestOptions { + /** + * Whether to automatically download all the attachments. Defaults to `true` where all the downloads are accepted. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * acceptDownloads: false, + * }, + * }); + * ``` + * + */ + acceptDownloads: boolean; + /** + * Toggles bypassing page's Content-Security-Policy. Defaults to `false`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * bypassCSP: true, + * } + * }); + * ``` + * + */ + bypassCSP: boolean; + /** + * Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. + * Passing `null` resets emulation to system defaults. Defaults to `'light'`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * colorScheme: 'dark', + * }, + * }); + * ``` + * + */ + colorScheme: ColorScheme; + /** + * Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about + * [emulating devices with device scale factor](https://playwright.dev/docs/emulation#devices). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * viewport: { width: 2560, height: 1440 }, + * deviceScaleFactor: 2, + * }, + * }); + * ``` + * + */ + deviceScaleFactor: number | undefined; + /** + * An object containing additional HTTP headers to be sent with every request. Defaults to none. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * extraHTTPHeaders: { + * 'X-My-Header': 'value', + * }, + * }, + * }); + * ``` + * + */ + extraHTTPHeaders: ExtraHTTPHeaders | undefined; + /** + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * geolocation: { longitude: 12.492507, latitude: 41.889938 }, + * }, + * }); + * ``` + * + * Learn more about [geolocation](https://playwright.dev/docs/emulation#color-scheme-and-media). + */ + geolocation: Geolocation | undefined; + /** + * Specifies if viewport supports touch events. Defaults to false. Learn more about + * [mobile emulation](https://playwright.dev/docs/emulation#devices). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * hasTouch: true + * }, + * }); + * ``` + * + */ + hasTouch: boolean; + /** + * Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). If no + * origin is specified, the username and password are sent to any servers upon unauthorized responses. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * httpCredentials: { + * username: 'user', + * password: 'pass', + * }, + * }, + * }); + * ``` + * + */ + httpCredentials: HTTPCredentials | undefined; + /** + * Whether to ignore HTTPS errors when sending network requests. Defaults to `false`. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * ignoreHTTPSErrors: true, + * }, + * }); + * ``` + * + */ + ignoreHTTPSErrors: boolean; + /** + * Whether the `meta viewport` tag is taken into account and touch events are enabled. isMobile is a part of device, + * so you don't actually need to set it manually. Defaults to `false` and is not supported in Firefox. Learn more + * about [mobile emulation](https://playwright.dev/docs/emulation#ismobile). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * isMobile: false, + * }, + * }); + * ``` + * + */ + isMobile: boolean; + /** + * Whether or not to enable JavaScript in the context. Defaults to `true`. Learn more about + * [disabling JavaScript](https://playwright.dev/docs/emulation#javascript-enabled). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * javaScriptEnabled: false, + * }, + * }); + * ``` + * + */ + javaScriptEnabled: boolean; + /** + * Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, + * `Accept-Language` request header value as well as number and date formatting rules. Defaults to the system default + * locale. Learn more about emulation in our [emulation guide](https://playwright.dev/docs/emulation#locale--timezone). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * locale: 'it-IT', + * }, + * }); + * ``` + * + */ + locale: string | undefined; + /** + * Whether to emulate network being offline. Defaults to `false`. Learn more about + * [network emulation](https://playwright.dev/docs/emulation#offline). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * offline: true + * }, + * }); + * ``` + * + */ + offline: boolean; + /** + * A list of permissions to grant to all pages in this context. See + * [browserContext.grantPermissions(permissions[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-grant-permissions) + * for more details. Defaults to none. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * permissions: ['notifications'], + * }, + * }); + * ``` + * + */ + permissions: string[] | undefined; + /** + * Network proxy settings. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * proxy: { + * server: 'http://myproxy.com:3128', + * bypass: 'localhost', + * }, + * }, + * }); + * ``` + * + */ + proxy: Proxy | undefined; + /** + * Learn more about [storage state and auth](https://playwright.dev/docs/auth). + * + * Populates context with given storage state. This option can be used to initialize context with logged-in + * information obtained via + * [browserContext.storageState([options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * storageState: 'storage-state.json', + * }, + * }); + * ``` + * + * **Details** + * + * When storage state is set up in the config, it is possible to reset storage state for a file: + * + * ```js + * // not-signed-in.spec.ts + * import { test } from '@playwright/test'; + * + * // Reset storage state for this file to avoid being authenticated + * test.use({ storageState: { cookies: [], origins: [] } }); + * + * test('not signed in test', async ({ page }) => { + * // ... + * }); + * ``` + * + */ + storageState: StorageState | undefined; + /** + * Changes the timezone of the context. See + * [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) + * for a list of supported timezone IDs. Defaults to the system timezone. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * timezoneId: 'Europe/Rome', + * }, + * }); + * ``` + * + */ + timezoneId: string | undefined; + /** + * Specific user agent to use in this context. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * userAgent: 'some custom ua', + * }, + * }); + * ``` + * + */ + userAgent: string | undefined; + /** + * Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use `null` to disable the consistent + * viewport emulation. Learn more about [viewport emulation](https://playwright.dev/docs/emulation#viewport). + * + * **NOTE** The `null` value opts out from the default presets, makes viewport depend on the host window size defined + * by the operating system. It makes the execution of the tests non-deterministic. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * viewport: { width: 100, height: 100 }, + * }, + * }); + * ``` + * + */ + viewport: ViewportSize | null; + /** + * When using [page.goto(url[, options])](https://playwright.dev/docs/api/class-page#page-goto), + * [page.route(url, handler[, options])](https://playwright.dev/docs/api/class-page#page-route), + * [page.waitForURL(url[, options])](https://playwright.dev/docs/api/class-page#page-wait-for-url), + * [page.waitForRequest(urlOrPredicate[, options])](https://playwright.dev/docs/api/class-page#page-wait-for-request), + * or + * [page.waitForResponse(urlOrPredicate[, options])](https://playwright.dev/docs/api/class-page#page-wait-for-response) + * it takes the base URL in consideration by using the + * [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. + * Unset by default. Examples: + * - baseURL: `http://localhost:3000` and navigating to `/bar.html` results in `http://localhost:3000/bar.html` + * - baseURL: `http://localhost:3000/foo/` and navigating to `./bar.html` results in + * `http://localhost:3000/foo/bar.html` + * - baseURL: `http://localhost:3000/foo` (without trailing slash) and navigating to `./bar.html` results in + * `http://localhost:3000/bar.html` + * + * **Usage** + * + * ```js + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * /* Base URL to use in actions like `await page.goto('/')`. *\/ + * baseURL: 'http://localhost:3000', + * }, + * }); + * ``` + * + */ + baseURL: string | undefined; + /** + * Options used to create the context, as passed to + * [browser.newContext([options])](https://playwright.dev/docs/api/class-browser#browser-new-context). Specific + * options like [testOptions.viewport](https://playwright.dev/docs/api/class-testoptions#test-options-viewport) take + * priority over this. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * contextOptions: { + * reducedMotion: 'reduce', + * }, + * }, + * }); + * ``` + * + */ + contextOptions: BrowserContextOptions; + /** + * 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). + * + * **Usage** + * + * ```js + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). *\/ + * actionTimeout: 0, + * }, + * }); + * ``` + * + * Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts). + */ + actionTimeout: number; + /** + * Timeout for each navigation action in milliseconds. Defaults to 0 (no timeout). + * + * This is a default navigation timeout, same as configured via + * [page.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-navigation-timeout). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * navigationTimeout: 3000, + * }, + * }); + * ``` + * + * Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts). + */ + navigationTimeout: number; + /** + * Whether to allow sites to register Service workers. Defaults to `'allow'`. + * - `'allow'`: [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) can be + * registered. + * - `'block'`: Playwright will block all registration of Service Workers. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * serviceWorkers: 'allow' + * }, + * }); + * ``` + * + */ + serviceWorkers: ServiceWorkerPolicy; + /** + * Custom attribute to be used in + * [page.getByTestId(testId)](https://playwright.dev/docs/api/class-page#page-get-by-test-id). `data-testid` is used + * by default. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * use: { + * testIdAttribute: 'pw-test-id', + * }, + * }); + * ``` + * + */ + testIdAttribute: string; +} + + +/** + * Playwright Test is based on the concept of the [test fixtures](https://playwright.dev/docs/test-fixtures). Test fixtures are used to + * establish environment for each test, giving the test everything it needs and nothing else. + * + * Playwright Test looks at each test declaration, analyses the set of fixtures the test needs and prepares those + * fixtures specifically for the test. Values prepared by the fixtures are merged into a single object that is + * available to the `test`, hooks, annotations and other fixtures as a first parameter. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }) => { + * // ... + * }); + * ``` + * + * Given the test above, Playwright Test will set up the `page` fixture before running the test, and tear it down + * after the test has finished. `page` fixture provides a {@link Page} object that is available to the test. + * + * Playwright Test comes with builtin fixtures listed below, and you can add your own fixtures as well. Playwright + * Test also [provides options]{@link TestOptions} to configure + * [fixtures.browser](https://playwright.dev/docs/api/class-fixtures#fixtures-browser), + * [fixtures.context](https://playwright.dev/docs/api/class-fixtures#fixtures-context) and + * [fixtures.page](https://playwright.dev/docs/api/class-fixtures#fixtures-page). + */ +export interface PlaywrightWorkerArgs { + playwright: typeof import('./types'); + /** + * {@link Browser} instance is shared between all tests in the [same worker](https://playwright.dev/docs/test-parallel) - this makes testing + * efficient. However, each test runs in an isolated {@link BrowserContext} and gets a fresh environment. + * + * Learn how to [configure browser](https://playwright.dev/docs/test-configuration) and see [available options]{@link TestOptions}. + * + * **Usage** + * + * ```js + * test.beforeAll(async ({ browser }) => { + * const page = await browser.newPage(); + * // ... + * }); + * ``` + * + */ + browser: Browser; +} + +/** + * Playwright Test is based on the concept of the [test fixtures](https://playwright.dev/docs/test-fixtures). Test fixtures are used to + * establish environment for each test, giving the test everything it needs and nothing else. + * + * Playwright Test looks at each test declaration, analyses the set of fixtures the test needs and prepares those + * fixtures specifically for the test. Values prepared by the fixtures are merged into a single object that is + * available to the `test`, hooks, annotations and other fixtures as a first parameter. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }) => { + * // ... + * }); + * ``` + * + * Given the test above, Playwright Test will set up the `page` fixture before running the test, and tear it down + * after the test has finished. `page` fixture provides a {@link Page} object that is available to the test. + * + * Playwright Test comes with builtin fixtures listed below, and you can add your own fixtures as well. Playwright + * Test also [provides options]{@link TestOptions} to configure + * [fixtures.browser](https://playwright.dev/docs/api/class-fixtures#fixtures-browser), + * [fixtures.context](https://playwright.dev/docs/api/class-fixtures#fixtures-context) and + * [fixtures.page](https://playwright.dev/docs/api/class-fixtures#fixtures-page). + */ +export interface PlaywrightTestArgs { + /** + * Isolated {@link BrowserContext} instance, created for each test. Since contexts are isolated between each other, + * every test gets a fresh environment, even when multiple tests run in a single {@link Browser} for maximum + * efficiency. + * + * Learn how to [configure context](https://playwright.dev/docs/test-configuration) and see [available options]{@link TestOptions}. + * + * Default [fixtures.page](https://playwright.dev/docs/api/class-fixtures#fixtures-page) belongs to this context. + * + * **Usage** + * + * ```js + * test('example test', async ({ page, context }) => { + * await context.route('*external.com/*', route => route.abort()); + * // ... + * }); + * ``` + * + */ + context: BrowserContext; + /** + * Isolated {@link Page} instance, created for each test. Pages are isolated between tests due to + * [fixtures.context](https://playwright.dev/docs/api/class-fixtures#fixtures-context) isolation. + * + * This is the most common fixture used in a test. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }) => { + * await page.goto('/signin'); + * await page.getByLabel('User Name').fill('user'); + * await page.getByLabel('Password').fill('password'); + * await page.getByText('Sign in').click(); + * // ... + * }); + * ``` + * + */ + page: Page; + /** + * Isolated {@link APIRequestContext} instance for each test. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ request }) => { + * await request.post('/signin', { + * data: { + * username: 'user', + * password: 'password' + * } + * }); + * // ... + * }); + * ``` + * + */ + request: APIRequestContext; +} + +type ExcludeProps = { + [K in Exclude]: A[K]; +}; +type CustomProperties = ExcludeProps; + +export type PlaywrightTestProject = Project, PlaywrightWorkerOptions & CustomProperties>; +export type PlaywrightTestConfig = Config, PlaywrightWorkerOptions & CustomProperties>; + +type AsymmetricMatcher = Record; + +interface AsymmetricMatchers { + /** + * `expect.any()` matches any object instance created from the `constructor` or a corresponding primitive type. Use it + * inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. + * + * **Usage** + * + * ```js + * // Match instance of a class. + * class Example {} + * expect(new Example()).toEqual(expect.any(Example)); + * + * // Match any number. + * expect({ prop: 1 }).toEqual({ prop: expect.any(Number) }); + * + * // Match any string. + * expect('abc').toEqual(expect.any(String)); + * ``` + * + * @param constructor Constructor of the expected object like `ExampleClass`, or a primitive boxed type like `Number`. + */ + any(sample: unknown): AsymmetricMatcher; + /** + * `expect.anything()` matches everything except `null` and `undefined`. Use it inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toEqual({ prop: expect.anything() }); + * expect(value).not.toEqual({ otherProp: expect.anything() }); + * ``` + * + */ + anything(): AsymmetricMatcher; + /** + * `expect.arrayContaining()` matches an array that contains all of the elements in the expected array, in any order. + * Note that received array may be a superset of the expected array and contain some extra elements. + * + * Use this method inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. + * + * **Usage** + * + * ```js + * expect([1, 2, 3]).toEqual(expect.arrayContaining([3, 1])); + * expect([1, 2, 3]).not.toEqual(expect.arrayContaining([1, 4])); + * ``` + * + * @param expected Expected array that is a subset of the received value. + */ + arrayContaining(sample: Array): AsymmetricMatcher; + /** + * Compares floating point numbers for approximate equality. Use this method inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. When just comparing two numbers, prefer + * [genericAssertions.toBeCloseTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be-close-to). + * + * **Usage** + * + * ```js + * expect({ prop: 0.1 + 0.2 }).not.toEqual({ prop: 0.3 }); + * expect({ prop: 0.1 + 0.2 }).toEqual({ prop: expect.closeTo(0.3, 5) }); + * ``` + * + * @param expected Expected value. + * @param numDigits The number of decimal digits after the decimal point that must be equal. + */ + closeTo(sample: number, precision?: number): AsymmetricMatcher; + /** + * `expect.objectContaining()` matches an object that contains and matches all of the properties in the expected + * object. Note that received object may be a superset of the expected object and contain some extra properties. + * + * Use this method inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. Object properties can be matchers to further relax the expectation. See examples. + * + * **Usage** + * + * ```js + * // Assert some of the properties. + * expect({ foo: 1, bar: 2 }).toEqual(expect.objectContaining({ foo: 1 })); + * + * // Matchers can be used on the properties as well. + * expect({ foo: 1, bar: 2 }).toEqual(expect.objectContaining({ bar: expect.any(Number) })); + * + * // Complex matching of sub-properties. + * expect({ + * list: [1, 2, 3], + * obj: { prop: 'Hello world!', another: 'some other value' }, + * extra: 'extra', + * }).toEqual(expect.objectContaining({ + * list: expect.arrayContaining([2, 3]), + * obj: expect.objectContaining({ prop: expect.stringContaining('Hello') }), + * })); + * ``` + * + * @param expected Expected object pattern that contains a subset of the properties. + */ + objectContaining(sample: Record): AsymmetricMatcher; + /** + * `expect.stringContaining()` matches a string that contains the expected substring. Use this method inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. + * + * **Usage** + * + * ```js + * expect('Hello world!').toEqual(expect.stringContaining('Hello')); + * ``` + * + * @param expected Expected substring. + */ + stringContaining(sample: string): AsymmetricMatcher; + /** + * `expect.stringMatching()` matches a received string that in turn matches the expected pattern. Use this method + * inside + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * to perform pattern matching. + * + * **Usage** + * + * ```js + * expect('123ms').toEqual(expect.stringMatching(/\d+m?s/)); + * + * // Inside another matcher. + * expect({ + * status: 'passed', + * time: '123ms', + * }).toEqual({ + * status: expect.stringMatching(/passed|failed/), + * time: expect.stringMatching(/\d+m?s/), + * }); + * ``` + * + * @param expected Pattern that expected string should match. + */ + stringMatching(sample: string | RegExp): AsymmetricMatcher; +} + +/** + * The {@link GenericAssertions} class provides assertion methods that can be used to make assertions about any values + * in the tests. A new instance of {@link GenericAssertions} is created by calling + * [expect(value)](https://playwright.dev/docs/api/class-playwrightassertions#playwright-assertions-expect-generic): + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('assert a value', async ({ page }) => { + * const value = 1; + * expect(value).toBe(2); + * }); + * ``` + * + */ +interface GenericAssertions { + /** + * Makes the assertion check for the opposite condition. For example, the following code passes: + * + * ```js + * const value = 1; + * expect(value).not.toBe(2); + * ``` + * + */ + not: GenericAssertions; + /** + * Compares value with `expected` by calling `Object.is`. This method compares objects by reference instead of their + * contents, similarly to the strict equality operator `===`. + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toBe(value); + * expect(value).not.toBe({}); + * expect(value.prop).toBe(1); + * ``` + * + * @param expected Expected value. + */ + toBe(expected: unknown): R; + /** + * Compares floating point numbers for approximate equality. Use this method instead of + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) + * when comparing floating point numbers. + * + * **Usage** + * + * ```js + * expect(0.1 + 0.2).not.toBe(0.3); + * expect(0.1 + 0.2).toBeCloseTo(0.3, 5); + * ``` + * + * @param expected Expected value. + * @param numDigits The number of decimal digits after the decimal point that must be equal. + */ + toBeCloseTo(expected: number, numDigits?: number): R; + /** + * Ensures that value is not `undefined`. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeDefined(); + * ``` + * + */ + toBeDefined(): R; + /** + * Ensures that value is false in a boolean context, one of `false`, `0`, `''`, `null`, `undefined` or `NaN`. Use this + * method when you don't care about the specific value. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeFalsy(); + * ``` + * + */ + toBeFalsy(): R; + /** + * Ensures that `value > expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeGreaterThan(1); + * ``` + * + * @param expected The value to compare to. + */ + toBeGreaterThan(expected: number | bigint): R; + /** + * Ensures that `value >= expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeGreaterThanOrEqual(42); + * ``` + * + * @param expected The value to compare to. + */ + toBeGreaterThanOrEqual(expected: number | bigint): R; + /** + * Ensures that value is an instance of a class. Uses `instanceof` operator. + * + * **Usage** + * + * ```js + * expect(page).toBeInstanceOf(Page); + * + * class Example {} + * expect(new Example()).toBeInstanceOf(Example); + * ``` + * + * @param expected The class or constructor function. + */ + toBeInstanceOf(expected: Function): R; + /** + * Ensures that `value < expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeLessThan(100); + * ``` + * + * @param expected The value to compare to. + */ + toBeLessThan(expected: number | bigint): R; + /** + * Ensures that `value <= expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeLessThanOrEqual(42); + * ``` + * + * @param expected The value to compare to. + */ + toBeLessThanOrEqual(expected: number | bigint): R; + /** + * Ensures that value is `NaN`. + * + * **Usage** + * + * ```js + * const value = NaN; + * expect(value).toBeNaN(); + * ``` + * + */ + toBeNaN(): R; + /** + * Ensures that value is `null`. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeNull(); + * ``` + * + */ + toBeNull(): R; + /** + * Ensures that value is true in a boolean context, **anything but** `false`, `0`, `''`, `null`, `undefined` or `NaN`. + * Use this method when you don't care about the specific value. + * + * **Usage** + * + * ```js + * const value = { example: 'value' }; + * expect(value).toBeTruthy(); + * ``` + * + */ + toBeTruthy(): R; + /** + * Ensures that value is `undefined`. + * + * **Usage** + * + * ```js + * const value = undefined; + * expect(value).toBeUndefined(); + * ``` + * + */ + toBeUndefined(): R; + /** + * Ensures that string value contains an expected substring. Comparison is case-sensitive. + * + * **Usage** + * + * ```js + * const value = 'Hello, World'; + * expect(value).toContain('World'); + * expect(value).toContain(','); + * ``` + * + * @param expected Expected substring. + */ + toContain(expected: string): R; + /** + * Ensures that value is an `Array` or `Set` and contains an expected item. + * + * **Usage** + * + * ```js + * const value = [1, 2, 3]; + * expect(value).toContain(2); + * expect(new Set(value)).toContain(2); + * ``` + * + * @param expected Expected value in the collection. + */ + toContain(expected: unknown): R; + /** + * Ensures that value is an `Array` or `Set` and contains an item equal to the expected. + * + * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as + * performed by + * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * + * For primitive values, this method is equivalent to + * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * + * **Usage** + * + * ```js + * const value = [ + * { example: 1 }, + * { another: 2 }, + * { more: 3 }, + * ]; + * expect(value).toContainEqual({ another: 2 }); + * expect(new Set(value)).toContainEqual({ another: 2 }); + * ``` + * + * @param expected Expected value in the collection. + */ + toContainEqual(expected: unknown): R; + /** + * Compares contents of the value with contents of `expected`, performing "deep equality" check. + * + * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as + * performed by + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * + * For primitive values, this method is equivalent to + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toEqual({ prop: 1 }); + * ``` + * + * **Non-strict equality** + * + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * performs deep equality check that compares contents of the received and expected values. To ensure two objects + * reference the same instance, use + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) + * instead. + * + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * ignores `undefined` properties and array items, and does not insist on object types being equal. For stricter + * matching, use + * [genericAssertions.toStrictEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-strict-equal). + * + * **Pattern matching** + * + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * can be also used to perform pattern matching on objects, arrays and primitive types, with the help of the following + * matchers: + * - [genericAssertions.any(constructor)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-any) + * - [genericAssertions.anything()](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-anything) + * - [genericAssertions.arrayContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-array-containing) + * - [genericAssertions.closeTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-close-to) + * - [genericAssertions.objectContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-object-containing) + * - [genericAssertions.stringContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-containing) + * - [genericAssertions.stringMatching(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-matching) + * + * Here is an example that asserts some of the values inside a complex object: + * + * ```js + * expect({ + * list: [1, 2, 3], + * obj: { prop: 'Hello world!', another: 'some other value' }, + * extra: 'extra', + * }).toEqual(expect.objectContaining({ + * list: expect.arrayContaining([2, 3]), + * obj: expect.objectContaining({ prop: expect.stringContaining('Hello') }), + * })); + * ``` + * + * @param expected Expected value. + */ + toEqual(expected: unknown): R; + /** + * Ensures that value has a `.length` property equal to `expected`. Useful for arrays and strings. + * + * **Usage** + * + * ```js + * expect('Hello, World').toHaveLength(12); + * expect([1, 2, 3]).toHaveLength(3); + * ``` + * + * @param expected Expected length. + */ + toHaveLength(expected: number): R; + /** + * Ensures that property at provided `keyPath` exists on the object and optionally checks that property is equal to + * the `expected`. Equality is checked recursively, similarly to + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal). + * + * **Usage** + * + * ```js + * const value = { + * a: { + * b: [42], + * }, + * c: true, + * }; + * expect(value).toHaveProperty('a.b'); + * expect(value).toHaveProperty('a.b', [42]); + * expect(value).toHaveProperty('a.b[0]', 42); + * expect(value).toHaveProperty('c'); + * expect(value).toHaveProperty('c', true); + * ``` + * + * @param keyPath Path to the property. Use dot notation `a.b` to check nested properties and indexed `a[2]` notation to check nested + * array items. + * @param expected Optional expected value to compare the property to. + */ + toHaveProperty(keyPath: string | Array, value?: unknown): R; + /** + * Ensures that string value matches a regular expression. + * + * **Usage** + * + * ```js + * const value = 'Is 42 enough?'; + * expect(value).toMatch(/Is \d+ enough/); + * ``` + * + * @param expected Regular expression to match against. + */ + toMatch(expected: RegExp | string): R; + /** + * Compares contents of the value with contents of `expected`, performing "deep equality" check. Allows extra + * properties to be present in the value, unlike + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal), + * so you can check just a subset of object properties. + * + * When comparing arrays, the number of items must match, and each item is checked recursively. + * + * **Usage** + * + * ```js + * const value = { + * a: 1, + * b: 2, + * c: true, + * }; + * expect(value).toMatchObject({ a: 1, c: true }); + * expect(value).toMatchObject({ b: 2, c: true }); + * + * expect([{ a: 1, b: 2 }]).toMatchObject([{ a: 1 }]); + * ``` + * + * @param expected The expected object value to match against. + */ + toMatchObject(expected: Record | Array): R; + /** + * Compares contents of the value with contents of `expected` **and** their types. + * + * Differences from + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal): + * - Keys with undefined properties are checked. For example, `{ a: undefined, b: 2 }` does not match `{ b: 2 }`. + * - Array sparseness is checked. For example, `[, 1]` does not match `[undefined, 1]`. + * - Object types are checked to be equal. For example, a class instance with fields `a` and `b` will not equal a + * literal object with fields `a` and `b`. + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toStrictEqual({ prop: 1 }); + * ``` + * + * @param expected Expected value. + */ + toStrictEqual(expected: unknown): R; + /** + * Calls the function and ensures it throws an error. + * + * Optionally compares the error with `expected`. Allowed expected values: + * - Regular expression - error message should **match** the pattern. + * - String - error message should **include** the substring. + * - Error object - error message should be **equal to** the message property of the object. + * - Error class - error object should be an **instance of** the class. + * + * **Usage** + * + * ```js + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(); + * + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(/something/); + * + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(Error); + * ``` + * + * @param expected Expected error message or error object. + */ + toThrow(error?: unknown): R; + /** + * An alias for + * [genericAssertions.toThrow([expected])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-throw). + * + * **Usage** + * + * ```js + * expect(() => { + * throw new Error('Something bad'); + * }).toThrowError(); + * ``` + * + * @param expected Expected error message or error object. + */ + toThrowError(error?: unknown): R; + +} + +type FunctionAssertions = { + /** + * Retries the callback until it passes. + */ + toPass(options?: { timeout?: number, intervals?: number[] }): Promise; +}; + +type BaseMatchers = GenericAssertions & PlaywrightTest.Matchers & SnapshotAssertions; +type AllowedGenericMatchers = PlaywrightTest.Matchers & Pick, 'toBe' | 'toBeDefined' | 'toBeFalsy' | 'toBeNull' | 'toBeTruthy' | 'toBeUndefined'>; + +type SpecificMatchers = + T extends Page ? PageAssertions & AllowedGenericMatchers : + T extends Locator ? LocatorAssertions & AllowedGenericMatchers : + T extends APIResponse ? APIResponseAssertions & AllowedGenericMatchers : + BaseMatchers & (T extends Function ? FunctionAssertions : {}); +type AllMatchers = PageAssertions & LocatorAssertions & APIResponseAssertions & FunctionAssertions & BaseMatchers; + +type IfAny = 0 extends (1 & T) ? Y : N; +type Awaited = T extends PromiseLike ? U : T; +type ToUserMatcher = F extends (first: any, ...args: infer Rest) => infer R ? (...args: Rest) => (R extends PromiseLike ? Promise : void) : never; +type ToUserMatcherObject = { + [K in keyof T as T[K] extends (arg: ArgType, ...rest: any[]) => any ? K : never]: ToUserMatcher; +}; + +type MatcherHintColor = (arg: string) => string; + +export type MatcherHintOptions = { + comment?: string; + expectedColor?: MatcherHintColor; + isDirectExpectCall?: boolean; + isNot?: boolean; + promise?: string; + receivedColor?: MatcherHintColor; + secondArgument?: string; + secondArgumentColor?: MatcherHintColor; +}; + +export interface ExpectMatcherUtils { + matcherHint(matcherName: string, received: unknown, expected: unknown, options?: MatcherHintOptions): string; + printDiffOrStringify(expected: unknown, received: unknown, expectedLabel: string, receivedLabel: string, expand: boolean): string; + printExpected(value: unknown): string; + printReceived(object: unknown): string; + printWithType(name: string, value: T, print: (value: T) => string): string; + diff(a: unknown, b: unknown): string | null; + stringify(object: unknown, maxDepth?: number, maxWidth?: number): string; +} + +type State = { + isNot: boolean; + promise: 'rejects' | 'resolves' | ''; + utils: ExpectMatcherUtils; +}; + +type MatcherReturnType = { + message: () => string; + pass: boolean; + name?: string; + expected?: unknown; + actual?: any; + log?: string[]; +}; + +type MakeMatchers = { + /** + * If you know how to test something, `.not` lets you test its opposite. + */ + not: MakeMatchers; + /** + * Use resolves to unwrap the value of a fulfilled promise so any other + * matcher can be chained. If the promise is rejected the assertion fails. + */ + resolves: MakeMatchers, Awaited, ExtendedMatchers>; + /** + * Unwraps the reason of a rejected promise so any other matcher can be chained. + * If the promise is fulfilled the assertion fails. + */ + rejects: MakeMatchers, any, ExtendedMatchers>; +} & IfAny, SpecificMatchers & ToUserMatcherObject>; + +export type Expect = { + (actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers; + soft: (actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers; + poll: (actual: () => T | Promise, messageOrOptions?: string | { message?: string, timeout?: number, intervals?: number[] }) => BaseMatchers, T> & { + /** + * If you know how to test something, `.not` lets you test its opposite. + */ + not: BaseMatchers, T>; + }; + extend MatcherReturnType | Promise>>(matchers: MoreMatchers): Expect; + configure: (configuration: { + message?: string, + timeout?: number, + soft?: boolean, + }) => Expect; + getState(): { + expand?: boolean; + isNot?: boolean; + promise?: string; + utils: any; + }; + not: Omit; +} & AsymmetricMatchers; + +// --- BEGINGLOBAL --- +declare global { + export namespace PlaywrightTest { + export interface Matchers { + } + } +} +// --- ENDGLOBAL --- + +/** + * These tests are executed in Playwright environment that launches the browser + * and provides a fresh page to each test. + */ +export const test: TestType; +export default test; + +export const _baseTest: TestType<{}, {}>; +export const expect: Expect<{}>; + +/** + * Defines Playwright config + */ +export function defineConfig(config: PlaywrightTestConfig): PlaywrightTestConfig; +export function defineConfig(config: PlaywrightTestConfig): PlaywrightTestConfig; +export function defineConfig(config: PlaywrightTestConfig): PlaywrightTestConfig; +export function defineConfig(config: PlaywrightTestConfig, ...configs: PlaywrightTestConfig[]): PlaywrightTestConfig; +export function defineConfig(config: PlaywrightTestConfig, ...configs: PlaywrightTestConfig[]): PlaywrightTestConfig; +export function defineConfig(config: PlaywrightTestConfig, ...configs: PlaywrightTestConfig[]): PlaywrightTestConfig; + +type MergedT = List extends [TestType, ...(infer Rest)] ? T & MergedT : {}; +type MergedW = List extends [TestType, ...(infer Rest)] ? W & MergedW : {}; +type MergedTestType = TestType, MergedW>; + +/** + * Merges fixtures + */ +export function mergeTests(...tests: List): MergedTestType; + +type MergedExpectMatchers = List extends [Expect, ...(infer Rest)] ? M & MergedExpectMatchers : {}; +type MergedExpect = Expect>; + +/** + * Merges expects + */ +export function mergeExpects(...expects: List): MergedExpect; + +// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459 +export {}; + + +/** + * The {@link APIResponseAssertions} class provides assertion methods that can be used to make assertions about the + * {@link APIResponse} in the tests. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('navigates to login', async ({ page }) => { + * // ... + * const response = await page.request.get('https://playwright.dev'); + * await expect(response).toBeOK(); + * }); + * ``` + * + */ +interface APIResponseAssertions { + /** + * Ensures the response status code is within `200..299` range. + * + * **Usage** + * + * ```js + * await expect(response).toBeOK(); + * ``` + * + */ + toBeOK(): Promise; + + /** + * Makes the assertion check for the opposite condition. For example, this code tests that the response status is not + * successful: + * + * ```js + * await expect(response).not.toBeOK(); + * ``` + * + */ + not: APIResponseAssertions; +} + +/** + * The {@link LocatorAssertions} class provides assertion methods that can be used to make assertions about the {@link + * Locator} state in the tests. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('status becomes submitted', async ({ page }) => { + * // ... + * await page.getByRole('button').click(); + * await expect(page.locator('.status')).toHaveText('Submitted'); + * }); + * ``` + * + */ +interface LocatorAssertions { + /** + * Ensures that {@link Locator} points to an [attached](https://playwright.dev/docs/actionability#attached) DOM node. + * + * **Usage** + * + * ```js + * await expect(page.getByText('Hidden text')).toBeAttached(); + * ``` + * + * @param options + */ + toBeAttached(options?: { + attached?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to a checked input. + * + * **Usage** + * + * ```js + * const locator = page.getByLabel('Subscribe to newsletter'); + * await expect(locator).toBeChecked(); + * ``` + * + * @param options + */ + toBeChecked(options?: { + checked?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to a disabled element. Element is disabled if it has "disabled" attribute or is + * disabled via + * ['aria-disabled'](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled). Note + * that only native control elements such as HTML `button`, `input`, `select`, `textarea`, `option`, `optgroup` can be + * disabled by setting "disabled" attribute. "disabled" attribute on other elements is ignored by the browser. + * + * **Usage** + * + * ```js + * const locator = page.locator('button.submit'); + * await expect(locator).toBeDisabled(); + * ``` + * + * @param options + */ + toBeDisabled(options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an editable element. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('textbox'); + * await expect(locator).toBeEditable(); + * ``` + * + * @param options + */ + toBeEditable(options?: { + editable?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an empty editable element or to a DOM node that has no text. + * + * **Usage** + * + * ```js + * const locator = page.locator('div.warning'); + * await expect(locator).toBeEmpty(); + * ``` + * + * @param options + */ + toBeEmpty(options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an enabled element. + * + * **Usage** + * + * ```js + * const locator = page.locator('button.submit'); + * await expect(locator).toBeEnabled(); + * ``` + * + * @param options + */ + toBeEnabled(options?: { + enabled?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to a focused DOM node. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('textbox'); + * await expect(locator).toBeFocused(); + * ``` + * + * @param options + */ + toBeFocused(options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures that {@link Locator} either does not resolve to any DOM node, or resolves to a + * [non-visible](https://playwright.dev/docs/actionability#visible) one. + * + * **Usage** + * + * ```js + * const locator = page.locator('.my-element'); + * await expect(locator).toBeHidden(); + * ``` + * + * @param options + */ + toBeHidden(options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element that intersects viewport, according to the + * [intersection observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). + * + * **Usage** + * + * ```js + * const locator = page.getByRole('button'); + * // Make sure at least some part of element intersects viewport. + * await expect(locator).toBeInViewport(); + * // Make sure element is fully outside of viewport. + * await expect(locator).not.toBeInViewport(); + * // Make sure that at least half of the element intersects viewport. + * await expect(locator).toBeInViewport({ ratio: 0.5 }); + * ``` + * + * @param options + */ + toBeInViewport(options?: { + /** + * The minimal ratio of the element to intersect viewport. If equals to `0`, then element should intersect viewport at + * any positive ratio. Defaults to `0`. + */ + ratio?: number; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures that {@link Locator} points to an [attached](https://playwright.dev/docs/actionability#attached) and + * [visible](https://playwright.dev/docs/actionability#visible) DOM node. + * + * To check that at least one element from the list is visible, use + * [locator.first()](https://playwright.dev/docs/api/class-locator#locator-first). + * + * **Usage** + * + * ```js + * // A specific element is visible. + * await expect(page.getByText('Welcome')).toBeVisible(); + * + * // At least one item in the list is visible. + * await expect(page.getByTestId('todo-item').first()).toBeVisible(); + * + * // At least one of the two elements is visible, possibly both. + * await expect( + * page.getByRole('button', { name: 'Sign in' }) + * .or(page.getByRole('button', { name: 'Sign up' })) + * .first() + * ).toBeVisible(); + * ``` + * + * @param options + */ + toBeVisible(options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + + visible?: boolean; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element that contains the given text. You can use regular expressions for + * the value as well. + * + * **Usage** + * + * ```js + * const locator = page.locator('.title'); + * await expect(locator).toContainText('substring'); + * await expect(locator).toContainText(/\d messages/); + * ``` + * + * If you pass an array as an expected value, the expectations are: + * 1. Locator resolves to a list of elements. + * 1. Elements from a **subset** of this list contain text from the expected array, respectively. + * 1. The matching subset of elements has the same order as the expected array. + * 1. Each text value from the expected array is matched by some element from the list. + * + * For example, consider the following list: + * + * ```html + *
    + *
  • Item Text 1
  • + *
  • Item Text 2
  • + *
  • Item Text 3
  • + *
+ * ``` + * + * Let's see how we can use the assertion: + * + * ```js + * // ✓ Contains the right items in the right order + * await expect(page.locator('ul > li')).toContainText(['Text 1', 'Text 3']); + * + * // ✖ Wrong order + * await expect(page.locator('ul > li')).toContainText(['Text 3', 'Text 2']); + * + * // ✖ No item contains this text + * await expect(page.locator('ul > li')).toContainText(['Some 33']); + * + * // ✖ Locator points to the outer list element, not to the list items + * await expect(page.locator('ul')).toContainText(['Text 3']); + * ``` + * + * @param expected Expected substring or RegExp or a list of those. + * @param options + */ + toContainText(expected: string|RegExp|Array, options?: { + /** + * Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular + * expression flag if specified. + */ + ignoreCase?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + + /** + * Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text. + */ + useInnerText?: boolean; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with given attribute. + * + * **Usage** + * + * ```js + * const locator = page.locator('input'); + * await expect(locator).toHaveAttribute('type', 'text'); + * ``` + * + * @param name Attribute name. + * @param value Expected attribute value. + * @param options + */ + toHaveAttribute(name: string, value: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with given attribute. The method will assert attribute presence. + * + * ```js + * const locator = page.locator('input'); + * // Assert attribute existence. + * await expect(locator).toHaveAttribute('disabled'); + * await expect(locator).not.toHaveAttribute('open'); + * ``` + * + * @param name Attribute name. + * @param options + */ + toHaveAttribute(name: string, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with given CSS classes. This needs to be a full match or using a + * relaxed regular expression. + * + * **Usage** + * + * ```html + *
+ * ``` + * + * ```js + * const locator = page.locator('#component'); + * await expect(locator).toHaveClass(/selected/); + * await expect(locator).toHaveClass('selected row'); + * ``` + * + * Note that if array is passed as an expected value, entire lists of elements can be asserted: + * + * ```js + * const locator = page.locator('list > .component'); + * await expect(locator).toHaveClass(['component', 'component selected', 'component']); + * ``` + * + * @param expected Expected class or RegExp or a list of those. + * @param options + */ + toHaveClass(expected: string|RegExp|Array, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} resolves to an exact number of DOM nodes. + * + * **Usage** + * + * ```js + * const list = page.locator('list > .component'); + * await expect(list).toHaveCount(3); + * ``` + * + * @param count Expected count. + * @param options + */ + toHaveCount(count: number, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} resolves to an element with the given computed CSS style. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('button'); + * await expect(locator).toHaveCSS('display', 'flex'); + * ``` + * + * @param name CSS property name. + * @param value CSS property value. + * @param options + */ + toHaveCSS(name: string, value: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with the given DOM Node ID. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('textbox'); + * await expect(locator).toHaveId('lastname'); + * ``` + * + * @param id Element id. + * @param options + */ + toHaveId(id: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link 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. + * + * **Usage** + * + * ```js + * const locator = page.locator('.component'); + * await expect(locator).toHaveJSProperty('loaded', true); + * ``` + * + * @param name Property name. + * @param value Property value. + * @param options + */ + toHaveJSProperty(name: string, value: any, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * This function will wait until two consecutive locator screenshots yield the same result, and then compare the last + * screenshot with the expectation. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('button'); + * await expect(locator).toHaveScreenshot('image.png'); + * ``` + * + * Note that screenshot assertions only work with Playwright test runner. + * @param name Snapshot name. + * @param options + */ + toHaveScreenshot(name: string|Array, options?: { + /** + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + * treatment depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. + * + * Defaults to `"disabled"` that disables animations. + */ + animations?: "disabled"|"allow"; + + /** + * When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + * changed. Defaults to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + * box `#FF00FF` (customized by `maskColor`) that completely covers its bounding box. + */ + mask?: Array; + + /** + * Specify the color of the overlay box for masked elements, in + * [CSS color format](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). Default color is pink `#FF00FF`. + */ + maskColor?: string; + + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + * Defaults to `false`. + */ + omitBackground?: boolean; + + /** + * When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + * will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + * screenshots of high-dpi devices will be twice as large or even larger. + * + * Defaults to `"css"`. + */ + scale?: "css"|"device"; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * This function will wait until two consecutive locator screenshots yield the same result, and then compare the last + * screenshot with the expectation. + * + * **Usage** + * + * ```js + * const locator = page.getByRole('button'); + * await expect(locator).toHaveScreenshot(); + * ``` + * + * Note that screenshot assertions only work with Playwright test runner. + * @param options + */ + toHaveScreenshot(options?: { + /** + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + * treatment depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. + * + * Defaults to `"disabled"` that disables animations. + */ + animations?: "disabled"|"allow"; + + /** + * When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + * changed. Defaults to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + * box `#FF00FF` (customized by `maskColor`) that completely covers its bounding box. + */ + mask?: Array; + + /** + * Specify the color of the overlay box for masked elements, in + * [CSS color format](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). Default color is pink `#FF00FF`. + */ + maskColor?: string; + + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + * Defaults to `false`. + */ + omitBackground?: boolean; + + /** + * When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + * will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + * screenshots of high-dpi devices will be twice as large or even larger. + * + * Defaults to `"css"`. + */ + scale?: "css"|"device"; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with the given text. You can use regular expressions for the value + * as well. + * + * **Usage** + * + * ```js + * const locator = page.locator('.title'); + * await expect(locator).toHaveText(/Welcome, Test User/); + * await expect(locator).toHaveText(/Welcome, .*\/); + * ``` + * + * If you pass an array as an expected value, the expectations are: + * 1. Locator resolves to a list of elements. + * 1. The number of elements equals the number of expected values in the array. + * 1. Elements from the list have text matching expected array values, one by one, in order. + * + * For example, consider the following list: + * + * ```html + *
    + *
  • Text 1
  • + *
  • Text 2
  • + *
  • Text 3
  • + *
+ * ``` + * + * Let's see how we can use the assertion: + * + * ```js + * // ✓ Has the right items in the right order + * await expect(page.locator('ul > li')).toHaveText(['Text 1', 'Text 2', 'Text 3']); + * + * // ✖ Wrong order + * await expect(page.locator('ul > li')).toHaveText(['Text 3', 'Text 2', 'Text 1']); + * + * // ✖ Last item does not match + * await expect(page.locator('ul > li')).toHaveText(['Text 1', 'Text 2', 'Text']); + * + * // ✖ Locator points to the outer list element, not to the list items + * await expect(page.locator('ul')).toHaveText(['Text 1', 'Text 2', 'Text 3']); + * ``` + * + * @param expected Expected string or RegExp or a list of those. + * @param options + */ + toHaveText(expected: string|RegExp|Array, options?: { + /** + * Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular + * expression flag if specified. + */ + ignoreCase?: boolean; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + + /** + * Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text. + */ + useInnerText?: boolean; + }): Promise; + + /** + * Ensures the {@link Locator} points to an element with the given input value. You can use regular expressions for + * the value as well. + * + * **Usage** + * + * ```js + * const locator = page.locator('input[type=number]'); + * await expect(locator).toHaveValue(/[0-9]/); + * ``` + * + * @param value Expected value. + * @param options + */ + toHaveValue(value: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the {@link Locator} points to multi-select/combobox (i.e. a `select` with the `multiple` attribute) and the + * specified values are selected. + * + * **Usage** + * + * For example, given the following element: + * + * ```html + * + * ``` + * + * ```js + * const locator = page.locator('id=favorite-colors'); + * await locator.selectOption(['R', 'G']); + * await expect(locator).toHaveValues([/R/, /G/]); + * ``` + * + * @param values Expected options currently selected. + * @param options + */ + toHaveValues(values: Array, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Makes the assertion check for the opposite condition. For example, this code tests that the Locator doesn't contain + * text `"error"`: + * + * ```js + * await expect(locator).not.toContainText('error'); + * ``` + * + */ + not: LocatorAssertions; +} + +/** + * The {@link PageAssertions} class provides assertion methods that can be used to make assertions about the {@link + * Page} state in the tests. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('navigates to login', async ({ page }) => { + * // ... + * await page.getByText('Sign in').click(); + * await expect(page).toHaveURL(/.*\/login/); + * }); + * ``` + * + */ +interface PageAssertions { + /** + * This function will wait until two consecutive page screenshots yield the same result, and then compare the last + * screenshot with the expectation. + * + * **Usage** + * + * ```js + * await expect(page).toHaveScreenshot('image.png'); + * ``` + * + * Note that screenshot assertions only work with Playwright test runner. + * @param name Snapshot name. + * @param options + */ + toHaveScreenshot(name: string|Array, options?: { + /** + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + * treatment depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. + * + * Defaults to `"disabled"` that disables animations. + */ + animations?: "disabled"|"allow"; + + /** + * When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + * changed. Defaults to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * An object which specifies clipping of the resulting image. + */ + clip?: { + /** + * x-coordinate of top-left corner of clip area + */ + x: number; + + /** + * y-coordinate of top-left corner of clip area + */ + y: number; + + /** + * width of clipping area + */ + width: number; + + /** + * height of clipping area + */ + height: number; + }; + + /** + * When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to + * `false`. + */ + fullPage?: boolean; + + /** + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + * box `#FF00FF` (customized by `maskColor`) that completely covers its bounding box. + */ + mask?: Array; + + /** + * Specify the color of the overlay box for masked elements, in + * [CSS color format](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). Default color is pink `#FF00FF`. + */ + maskColor?: string; + + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + * Defaults to `false`. + */ + omitBackground?: boolean; + + /** + * When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + * will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + * screenshots of high-dpi devices will be twice as large or even larger. + * + * Defaults to `"css"`. + */ + scale?: "css"|"device"; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * This function will wait until two consecutive page screenshots yield the same result, and then compare the last + * screenshot with the expectation. + * + * **Usage** + * + * ```js + * await expect(page).toHaveScreenshot(); + * ``` + * + * Note that screenshot assertions only work with Playwright test runner. + * @param options + */ + toHaveScreenshot(options?: { + /** + * When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different + * treatment depending on their duration: + * - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + * - infinite animations are canceled to initial state, and then played over after the screenshot. + * + * Defaults to `"disabled"` that disables animations. + */ + animations?: "disabled"|"allow"; + + /** + * When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be + * changed. Defaults to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * An object which specifies clipping of the resulting image. + */ + clip?: { + /** + * x-coordinate of top-left corner of clip area + */ + x: number; + + /** + * y-coordinate of top-left corner of clip area + */ + y: number; + + /** + * width of clipping area + */ + width: number; + + /** + * height of clipping area + */ + height: number; + }; + + /** + * When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to + * `false`. + */ + fullPage?: boolean; + + /** + * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink + * box `#FF00FF` (customized by `maskColor`) that completely covers its bounding box. + */ + mask?: Array; + + /** + * Specify the color of the overlay box for masked elements, in + * [CSS color format](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). Default color is pink `#FF00FF`. + */ + maskColor?: string; + + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. + * Defaults to `false`. + */ + omitBackground?: boolean; + + /** + * When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this + * will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so + * screenshots of high-dpi devices will be twice as large or even larger. + * + * Defaults to `"css"`. + */ + scale?: "css"|"device"; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the page has the given title. + * + * **Usage** + * + * ```js + * await expect(page).toHaveTitle(/.*checkout/); + * ``` + * + * @param titleOrRegExp Expected title or RegExp. + * @param options + */ + toHaveTitle(titleOrRegExp: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Ensures the page is navigated to the given URL. + * + * **Usage** + * + * ```js + * await expect(page).toHaveURL(/.*checkout/); + * ``` + * + * @param urlOrRegExp Expected URL string or RegExp. + * @param options + */ + toHaveURL(urlOrRegExp: string|RegExp, options?: { + /** + * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. + */ + timeout?: number; + }): Promise; + + /** + * Makes the assertion check for the opposite condition. For example, this code tests that the page URL doesn't + * contain `"error"`: + * + * ```js + * await expect(page).not.toHaveURL('error'); + * ``` + * + */ + not: PageAssertions; +} + +/** + * Playwright provides methods for comparing page and element screenshots with expected values stored in files. + * + * ```js + * expect(screenshot).toMatchSnapshot('landing-page.png'); + * ``` + * + */ +interface SnapshotAssertions { + /** + * **NOTE** To compare screenshots, use + * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * instead. + * + * Ensures that passed value, either a [string] or a [Buffer], matches the expected snapshot stored in the test + * snapshots directory. + * + * **Usage** + * + * ```js + * // Basic usage. + * expect(await page.screenshot()).toMatchSnapshot('landing-page.png'); + * + * // Pass options to customize the snapshot comparison and have a generated name. + * expect(await page.screenshot()).toMatchSnapshot('landing-page.png', { + * maxDiffPixels: 27, // allow no more than 27 different pixels. + * }); + * + * // Configure image matching threshold. + * expect(await page.screenshot()).toMatchSnapshot('landing-page.png', { threshold: 0.3 }); + * + * // Bring some structure to your snapshot files by passing file path segments. + * expect(await page.screenshot()).toMatchSnapshot(['landing', 'step2.png']); + * expect(await page.screenshot()).toMatchSnapshot(['landing', 'step3.png']); + * ``` + * + * Learn more about [visual comparisons](https://playwright.dev/docs/test-snapshots). + * + * Note that matching snapshots only work with Playwright test runner. + * @param name Snapshot name. + * @param options + */ + toMatchSnapshot(name: string|Array, options?: { + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + }): void; + + /** + * **NOTE** To compare screenshots, use + * [pageAssertions.toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-2) + * instead. + * + * Ensures that passed value, either a [string] or a [Buffer], matches the expected snapshot stored in the test + * snapshots directory. + * + * **Usage** + * + * ```js + * // Basic usage and the file name is derived from the test name. + * expect(await page.screenshot()).toMatchSnapshot(); + * + * // Pass options to customize the snapshot comparison and have a generated name. + * expect(await page.screenshot()).toMatchSnapshot({ + * maxDiffPixels: 27, // allow no more than 27 different pixels. + * }); + * + * // Configure image matching threshold and snapshot name. + * expect(await page.screenshot()).toMatchSnapshot({ + * name: 'landing-page.png', + * threshold: 0.3, + * }); + * ``` + * + * Learn more about [visual comparisons](https://playwright.dev/docs/test-snapshots). + * + * Note that matching snapshots only work with Playwright test runner. + * @param options + */ + toMatchSnapshot(options?: { + /** + * An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is + * configurable with `TestConfig.expect`. Unset by default. + */ + maxDiffPixelRatio?: number; + + /** + * An acceptable amount of pixels that could be different. Default is configurable with `TestConfig.expect`. Unset by + * default. + */ + maxDiffPixels?: number; + + /** + * Snapshot name. If not passed, the test name and ordinals are used when called multiple times. + */ + name?: string|Array; + + /** + * An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the + * same pixel in compared images, between zero (strict) and one (lax), default is configurable with + * `TestConfig.expect`. Defaults to `0.2`. + */ + threshold?: number; + }): void; +} + +/** + * Information about an error thrown during test execution. + */ +export interface TestInfoError { + /** + * Error message. Set when [Error] (or its subclass) has been thrown. + */ + message?: string; + + /** + * Error stack. Set when [Error] (or its subclass) has been thrown. + */ + stack?: string; + + /** + * The value that was thrown. Set when anything except the [Error] (or its subclass) has been thrown. + */ + value?: string; +} + +/** + * Playwright Test supports running multiple test projects at the same time. This is useful for running tests in + * multiple configurations. For example, consider running tests against multiple browsers. + * + * `TestProject` encapsulates configuration specific to a single project. Projects are configured in + * [testConfig.projects](https://playwright.dev/docs/api/class-testconfig#test-config-projects) specified in the + * [configuration file](https://playwright.dev/docs/test-configuration). Note that all properties of {@link TestProject} are available in + * the top-level {@link TestConfig}, in which case they are shared between all projects. + * + * Here is an example configuration that runs every test in Chromium, Firefox and WebKit, both Desktop and Mobile + * versions. + * + * ```js + * // playwright.config.ts + * import { defineConfig, devices } from '@playwright/test'; + * + * export default defineConfig({ + * // Options shared for all projects. + * timeout: 30000, + * use: { + * ignoreHTTPSErrors: true, + * }, + * + * // Options specific to each project. + * projects: [ + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * }, + * { + * name: 'Mobile Chrome', + * use: devices['Pixel 5'], + * }, + * { + * name: 'Mobile Safari', + * use: devices['iPhone 12'], + * }, + * ], + * }); + * ``` + * + */ +interface TestProject { + /** + * List of projects that need to run before any test in this project runs. Dependencies can be useful for configuring + * the global setup actions in a way that every action is in a form of a test. Passing `--no-deps` argument ignores + * the dependencies and behaves as if they were not specified. + * + * Using dependencies allows global setup to produce traces and other artifacts, see the setup steps in the test + * report, etc. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'setup', + * testMatch: /global.setup\.ts/, + * }, + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * dependencies: ['setup'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * dependencies: ['setup'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * dependencies: ['setup'], + * }, + * ], + * }); + * ``` + * + */ + dependencies?: Array; + + /** + * Configuration for the `expect` assertion library. + * + * Use [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect) to change this option + * for all projects. + */ + expect?: { + /** + * Default timeout for async expect matchers in milliseconds, defaults to 5000ms. + */ + timeout?: number; + + /** + * Configuration for the + * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * method. + */ + toHaveScreenshot?: { + /** + * an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and + * `1` (lax). `"pixelmatch"` comparator computes color difference in + * [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. + */ + threshold?: number; + + /** + * an acceptable amount of pixels that could be different, unset by default. + */ + maxDiffPixels?: number; + + /** + * an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by + * default. + */ + maxDiffPixelRatio?: number; + + /** + * See `animations` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). + * Defaults to `"disabled"`. + */ + animations?: "allow"|"disabled"; + + /** + * See `caret` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults + * to `"hide"`. + */ + caret?: "hide"|"initial"; + + /** + * See `scale` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults + * to `"css"`. + */ + scale?: "css"|"device"; + }; + + /** + * Configuration for the + * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) + * method. + */ + toMatchSnapshot?: { + /** + * an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and + * `1` (lax). `"pixelmatch"` comparator computes color difference in + * [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. + */ + threshold?: number; + + /** + * an acceptable amount of pixels that could be different, unset by default. + */ + maxDiffPixels?: number; + + /** + * an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by + * default. + */ + maxDiffPixelRatio?: number; + }; + }; + + /** + * Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the + * same time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same + * worker process. + * + * You can configure entire test project to concurrently run all tests in all files using this option. + */ + fullyParallel?: boolean; + + /** + * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only + * run tests with "cart" in the title. Also available globally and in the [command line](https://playwright.dev/docs/test-cli) with the `-g` + * option. The regular expression will be tested against the string that consists of the test file name, + * `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * + * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + */ + grep?: RegExp|Array; + + /** + * Filter to only run tests with a title **not** matching one of the patterns. This is the opposite of + * [testProject.grep](https://playwright.dev/docs/api/class-testproject#test-project-grep). Also available globally + * and in the [command line](https://playwright.dev/docs/test-cli) with the `--grep-invert` option. + * + * `grepInvert` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). + */ + grepInvert?: RegExp|Array; + + /** + * Metadata that will be put directly to the test report serialized as JSON. + */ + metadata?: Metadata; + + /** + * Project name is visible in the report and during test execution. + */ + name?: string; + + /** + * The output directory for files created during test execution. Defaults to `/test-results`. + * + * This directory is cleaned at the start. When running a test, a unique subdirectory inside the + * [testProject.outputDir](https://playwright.dev/docs/api/class-testproject#test-project-output-dir) is created, + * guaranteeing that test running in parallel do not conflict. This directory can be accessed by + * [testInfo.outputDir](https://playwright.dev/docs/api/class-testinfo#test-info-output-dir) and + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path). + * + * Here is an example that uses + * [testInfo.outputPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-output-path) to + * create a temporary file. + * + * ```js + * import { test, expect } from '@playwright/test'; + * import fs from 'fs'; + * + * test('example test', async ({}, testInfo) => { + * const file = testInfo.outputPath('temporary-file.txt'); + * await fs.promises.writeFile(file, 'Put some data to the file', 'utf8'); + * }); + * ``` + * + * Use [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir) to change this + * option for all projects. + */ + outputDir?: string; + + /** + * The number of times to repeat each test, useful for debugging flaky tests. + * + * Use [testConfig.repeatEach](https://playwright.dev/docs/api/class-testconfig#test-config-repeat-each) to change + * this option for all projects. + */ + repeatEach?: number; + + /** + * The maximum number of retry attempts given to failed tests. Learn more about + * [test retries](https://playwright.dev/docs/test-retries#retries). + * + * Use [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure) to + * change the number of retries for a specific file or a group of tests. + * + * Use [testConfig.retries](https://playwright.dev/docs/api/class-testconfig#test-config-retries) to change this + * option for all projects. + */ + retries?: number; + + /** + * The base directory, relative to the config file, for snapshot files created with `toMatchSnapshot`. Defaults to + * [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir). + * + * The directory for each test can be accessed by + * [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) and + * [testInfo.snapshotPath(...pathSegments)](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-path). + * + * This path will serve as the base directory for each test file snapshot directory. Setting `snapshotDir` to + * `'snapshots'`, the [testInfo.snapshotDir](https://playwright.dev/docs/api/class-testinfo#test-info-snapshot-dir) + * would resolve to `snapshots/a.spec.js-snapshots`. + */ + snapshotDir?: string; + + /** + * This option configures a template controlling location of snapshots generated by + * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * and + * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * testDir: './tests', + * snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + * }); + * ``` + * + * **Details** + * + * The value might include some "tokens" that will be replaced with actual values during test execution. + * + * Consider the following file structure: + * + * ```txt + * playwright.config.ts + * tests/ + * └── page/ + * └── page-click.spec.ts + * ``` + * + * And the following `page-click.spec.ts` that uses `toHaveScreenshot()` call: + * + * ```js + * // page-click.spec.ts + * import { test, expect } from '@playwright/test'; + * + * test.describe('suite', () => { + * test('test should work', async ({ page }) => { + * await expect(page).toHaveScreenshot(['foo', 'bar', 'baz.png']); + * }); + * }); + * ``` + * + * The list of supported tokens: + * - `{testDir}` - Project's + * [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir). + * - Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with + * config) + * - `{snapshotDir}` - Project's + * [testConfig.snapshotDir](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-dir). + * - Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`) + * - `{platform}` - The value of `process.platform`. + * - `{projectName}` - Project's file-system-sanitized name, if any. + * - Value: `''` (empty string). + * - `{testFileDir}` - Directories in relative path from `testDir` to **test file**. + * - Value: `page` + * - `{testFileName}` - Test file name with extension. + * - Value: `page-click.spec.ts` + * - `{testFilePath}` - Relative path from `testDir` to **test file** + * - Value: `page/page-click.spec.ts` + * - `{testName}` - File-system-sanitized test title, including parent describes but excluding file name. + * - Value: `suite-test-should-work` + * - `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the + * `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated + * snapshot name. + * - Value: `foo/bar/baz` + * - `{ext}` - snapshot extension (with dots) + * - Value: `.png` + * + * Each token can be preceded with a single character that will be used **only if** this token has non-empty value. + * + * Consider the following config: + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * snapshotPathTemplate: '__screenshots__{/projectName}/{testFilePath}/{arg}{ext}', + * testMatch: 'example.spec.ts', + * projects: [ + * { use: { browserName: 'firefox' } }, + * { name: 'chromium', use: { browserName: 'chromium' } }, + * ], + * }); + * ``` + * + * In this config: + * 1. First project **does not** have a name, so its snapshots will be stored in + * `/__screenshots__/example.spec.ts/...`. + * 1. Second project **does** have a name, so its snapshots will be stored in + * `/__screenshots__/chromium/example.spec.ts/..`. + * 1. Since `snapshotPathTemplate` resolves to relative path, it will be resolved relative to `configDir`. + * 1. Forward slashes `"/"` can be used as path separators on any platform. + */ + snapshotPathTemplate?: string; + + /** + * Name of a project that needs to run after this and all dependent projects have finished. Teardown is useful to + * cleanup any resources acquired by this project. + * + * Passing `--no-deps` argument ignores + * [testProject.teardown](https://playwright.dev/docs/api/class-testproject#test-project-teardown) and behaves as if + * it was not specified. + * + * **Usage** + * + * A common pattern is a "setup" dependency that has a corresponding "teardown": + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'setup', + * testMatch: /global.setup\.ts/, + * teardown: 'teardown', + * }, + * { + * name: 'teardown', + * testMatch: /global.teardown\.ts/, + * }, + * { + * name: 'chromium', + * use: devices['Desktop Chrome'], + * dependencies: ['setup'], + * }, + * { + * name: 'firefox', + * use: devices['Desktop Firefox'], + * dependencies: ['setup'], + * }, + * { + * name: 'webkit', + * use: devices['Desktop Safari'], + * dependencies: ['setup'], + * }, + * ], + * }); + * ``` + * + */ + teardown?: string; + + /** + * Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file. + * + * Each project can use a different directory. Here is an example that runs smoke tests in three browsers and all + * other tests in stable Chrome browser. + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * projects: [ + * { + * name: 'Smoke Chromium', + * testDir: './smoke-tests', + * use: { + * browserName: 'chromium', + * } + * }, + * { + * name: 'Smoke WebKit', + * testDir: './smoke-tests', + * use: { + * browserName: 'webkit', + * } + * }, + * { + * name: 'Smoke Firefox', + * testDir: './smoke-tests', + * use: { + * browserName: 'firefox', + * } + * }, + * { + * name: 'Chrome Stable', + * testDir: './', + * use: { + * browserName: 'chromium', + * channel: 'chrome', + * } + * }, + * ], + * }); + * ``` + * + * Use [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir) to change this + * option for all projects. + */ + testDir?: string; + + /** + * Files matching one of these patterns are not executed as test files. Matching is performed against the absolute + * file path. Strings are treated as glob patterns. + * + * For example, `'**\/test-assets/**'` will ignore any files in the `test-assets` directory. + * + * Use [testConfig.testIgnore](https://playwright.dev/docs/api/class-testconfig#test-config-test-ignore) to change + * this option for all projects. + */ + testIgnore?: string|RegExp|Array; + + /** + * Only the files matching one of these patterns are executed as test files. Matching is performed against the + * absolute file path. Strings are treated as glob patterns. + * + * By default, Playwright looks for files matching the following glob pattern: `**\/*.@(spec|test).?(c|m)[jt]s?(x)`. + * This means JavaScript or TypeScript files with `".test"` or `".spec"` suffix, for example + * `login-screen.wrong-credentials.spec.ts`. + * + * Use [testConfig.testMatch](https://playwright.dev/docs/api/class-testconfig#test-config-test-match) to change this + * option for all projects. + */ + testMatch?: string|RegExp|Array; + + /** + * Timeout for each test in milliseconds. Defaults to 30 seconds. + * + * This is a base timeout for all tests. Each test can configure its own timeout with + * [test.setTimeout(timeout)](https://playwright.dev/docs/api/class-test#test-set-timeout). Each file or a group of + * tests can configure the timeout with + * [test.describe.configure([options])](https://playwright.dev/docs/api/class-test#test-describe-configure). + * + * Use [testConfig.timeout](https://playwright.dev/docs/api/class-testconfig#test-config-timeout) to change this + * option for all projects. + */ + timeout?: number; +} + +interface TestConfigWebServer { + /** + * Shell command to start. For example `npm run start`.. + */ + command: string; + + /** + * The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port` + * or `url` should be specified. + */ + port?: number; + + /** + * The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the + * server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is + * checked. Either `port` or `url` should be specified. + */ + url?: string; + + /** + * Whether to ignore HTTPS errors when fetching the `url`. Defaults to `false`. + */ + ignoreHTTPSErrors?: boolean; + + /** + * How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. + */ + timeout?: number; + + /** + * If true, it will re-use an existing server on the `port` or `url` when available. If no server is running on that + * `port` or `url`, it will run the command to start a new server. If `false`, it will throw if an existing process is + * listening on the `port` or `url`. This should be commonly set to `!process.env.CI` to allow the local dev server + * when running tests locally. + */ + reuseExistingServer?: boolean; + + /** + * If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout + * of the command. Default to `"ignore"`. + */ + stdout?: "pipe"|"ignore"; + + /** + * Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. + */ + stderr?: "pipe"|"ignore"; + + /** + * Current working directory of the spawned process, defaults to the directory of the configuration file. + */ + cwd?: string; + + /** + * Environment variables to set for the command, `process.env` by default. + */ + env?: { [key: string]: string; }; +} + diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 11a7a5aa7..c8c59eb8f 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -14,11 +14,8 @@ * limitations under the License. */ -import type { BrowserContext } from "playwright-core/lib/client/browserContext"; -import type { Page } from "playwright-core/lib/client/page"; - -export type { BrowserContext } from "playwright-core/lib/client/browserContext"; -export type { Page } from "playwright-core/lib/client/page"; +import { Page, BrowserContext } from '../../playwright/packages/playwright-core/types/types'; +export * from '../../playwright/packages/playwright-core/types/types'; export interface Crx { /** diff --git a/test.d.ts b/test.d.ts new file mode 100644 index 000000000..afafd9e05 --- /dev/null +++ b/test.d.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './index'; +export { expect, Expect } from './src/types/test'; diff --git a/utils/generate_test_types.js b/utils/generate_test_types.js new file mode 100644 index 000000000..835330a22 --- /dev/null +++ b/utils/generate_test_types.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) Rui Figueira. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const fs = require('fs'); +const path = require('path'); + +const srcFile = path.join(__dirname, '..', 'playwright', 'packages', 'playwright', 'types', 'test.d.ts'); +const destFile = path.join(__dirname, '..', 'src', 'types', 'test.d.ts'); + +const content = fs.readFileSync(srcFile, 'utf8'); +const result = content + // playwright-crx should not rely on playwright-core + .replace(/'playwright-core'/g, `'./types'`) + .replace(/\/\/ This file is generated by (.*)$/g, `This file is generated by ${path.basename(__filename)}`) + .replace(/ \* Copyright \(c\) Microsoft Corporation./, [ + ' * Copyright (c) Microsoft Corporation.', + ' * Modifications copyright (c) Rui Figueira.', + ].join('\n')); + +fs.writeFileSync(destFile, result, 'utf8'); diff --git a/vite.config.ts b/vite.config.ts index add4655a9..7b8fdf606 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -107,9 +107,10 @@ export default defineConfig({ // skip code obfuscation minify: false, lib: { - entry: path.resolve(__dirname, 'src/index.ts'), - name: 'playwright-crx', - fileName: 'index', + entry: { + index: path.resolve(__dirname, 'src/index.ts'), + test: path.resolve(__dirname, 'src/test.ts'), + }, }, rollupOptions: { output: {