docs(test runner): API reference for builtin fixtures (#7805)

This commit is contained in:
Dmitry Gozman 2021-07-22 14:47:12 -07:00 committed by GitHub
parent a20e20cdae
commit fd9c72015f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 370 additions and 22 deletions

View File

@ -0,0 +1,243 @@
# class: Fixtures
* langs: js
Playwright Test is based on the concept of the [test fixtures](./test-fixtures.md). 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 js-flavor=js
const { test, expect } = require('@playwright/test');
test('basic test', async ({ page }) => {
// ...
});
```
```js js-flavor=ts
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 [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. Many fixtures are designed as "options" that you can set in your [`property: TestConfig.use`] section.
```js js-flavor=js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
use: {
headless: false,
viewport: { width: 1280, height: 720 },
ignoreHTTPSErrors: true,
video: 'on-first-retry',
},
};
module.exports = config;
```
```js js-flavor=ts
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
use: {
headless: false,
viewport: { width: 1280, height: 720 },
ignoreHTTPSErrors: true,
video: 'on-first-retry',
},
};
export default config;
```
Alternatively, with [`method: Test.use`] you can override some options for a file.
```js js-flavor=js
// example.spec.js
const { test, expect } = require('@playwright/test');
// Run tests in this file with portrait-like viewport.
test.use({ viewport: { width: 600, height: 900 } });
test('my portrait test', async ({ page }) => {
// ...
});
```
```js js-flavor=ts
// 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 }) => {
// ...
});
```
## property: Fixtures.acceptDownloads = %%-context-option-acceptdownloads-%%
## property: Fixtures.baseURL = %%-context-option-baseURL-%%
## property: Fixtures.browserName
- type: <[BrowserName]<"chromium"|"firefox"|"webkit">>
Name of the browser that runs tests. Defaults to `'chromium'`. Most of the time you should set `browserName` in your [TestConfig]:
```js js-flavor=js
// playwright.config.js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
use: {
browserName: 'firefox',
},
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
use: {
browserName: 'firefox',
},
};
export default config;
```
## property: Fixtures.bypassCSP = %%-context-option-bypasscsp-%%
## property: Fixtures.channel = %%-browser-option-channel-%%
## property: Fixtures.colorScheme = %%-context-option-colorscheme-%%
## property: Fixtures.context
- type: <[BrowserContext]>
Isolated [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 [Browser] for maximum efficiency.
Learn how to [configure context](./test-configuration.md) through other fixtures and options.
The [`property: Fixtures.page`] belongs to this context.
## property: Fixtures.contextOptions
- type: <[Object]>
Options used to create the context, as passed to [`method: Browser.newContext`]. Specific options like [`property: Fixtures.viewport`] take priority over this.
## property: Fixtures.deviceScaleFactor = %%-context-option-devicescalefactor-%%
## property: Fixtures.extraHTTPHeaders = %%-context-option-extrahttpheaders-%%
## property: Fixtures.geolocation = %%-context-option-geolocation-%%
## property: Fixtures.hasTouch = %%-context-option-hastouch-%%
## property: Fixtures.headless = %%-browser-option-headless-%%
## property: Fixtures.httpCredentials = %%-context-option-httpcredentials-%%
## property: Fixtures.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%%
## property: Fixtures.isMobile = %%-context-option-ismobile-%%
## property: Fixtures.javaScriptEnabled = %%-context-option-javascriptenabled-%%
## property: Fixtures.launchOptions
- type: <[Object]>
Options used to launch the browser, as passed to [`method: BrowserType.launch`]. Specific options [`property: Fixtures.headless`] and [`property: Fixtures.channel`] take priority over this.
## property: Fixtures.locale = %%-context-option-locale-%%
## property: Fixtures.offline = %%-context-option-offline-%%
## property: Fixtures.page
- type: <[Page]>
Isolated [Page] instance, created for each test. Pages are isolated between tests due to [`property: Fixtures.context`] isolation.
This is the most common fixture used in a test.
```js js-flavor=js
const { test, expect } = require('@playwright/test');
test('basic test', async ({ page }) => {
await page.goto('/signin');
await page.fill('#username', 'User');
await page.fill('#password', 'pwd');
await page.click('text=Sign in');
// ...
});
```
```js js-flavor=ts
import { test, expect } from '@playwright/test';
test('basic test', async ({ page }) => {
await page.goto('/signin');
await page.fill('#username', 'User');
await page.fill('#password', 'pwd');
await page.click('text=Sign in');
// ...
});
```
## property: Fixtures.permissions = %%-context-option-permissions-%%
## property: Fixtures.proxy = %%-browser-option-proxy-%%
## property: Fixtures.screenshot
- type: <[Screenshot]<"off"|"on"|"only-on-failure">>
Whether to automatically capture a screenshot after each test. Defaults to `'off'`.
1. `'off'`: Do not capture screenshots.
1. `'on'`: Capture screenshot after each test.
1. `'only-on-failure'`: Capture screenshot after each test failure.
Learn more about [automatic screenshots](./test-configuration.md#automatic-screenshots).
## property: Fixtures.storageState = %%-js-python-context-option-storage-state-%%
## property: Fixtures.timezoneId = %%-context-option-timezoneid-%%
## property: Fixtures.trace
- type: <[Screenshot]<"off"|"on"|"retain-on-failure"|"on-first-retry">>
Whether to record a trace for each test. Defaults to `'off'`.
1. `'off'`: Do not record a trace.
1. `'on'`: Record a trace for each test.
1. `'retain-on-failure'`: Record a trace for each test, but remove it from successful test runs.
1. `'on-first-retry'`: Record a trace only when retrying a test for the first time.
Learn more about [recording trace](./test-configuration.md#record-test-trace).
## property: Fixtures.userAgent = %%-context-option-useragent-%%
## property: Fixtures.video
- type: <[Object]|[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">>
- `mode` <[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">> Video recording mode.
- `size` <[Object]> Size of the recorded video.
- `width` <[int]>
- `height` <[int]>
Whether to record video for each test. Defaults to `'off'`.
1. `'off'`: Do not record video.
1. `'on'`: Record video for each test.
1. `'retain-on-failure'`: Record video for each test, but remove all videos from successful test runs.
1. `'on-first-retry'`: Record video only when retrying a test for the first time.
Learn more about [recording video](./test-configuration.md#record-video).
## property: Fixtures.viewport = %%-context-option-viewport-%%

View File

@ -53,7 +53,7 @@ test('basic test', async ({ page }) => {
Test title.
### param: Test.(call).testFunction
- `testFunction` <[function]\([Object], [TestInfo]\)>
- `testFunction` <[function]\([Fixtures], [TestInfo]\)>
Test function that takes one or two arguments: an object with fixtures and optional [TestInfo].
@ -64,7 +64,7 @@ Test function that takes one or two arguments: an object with fixtures and optio
Declares an `afterAll` hook that is executed once after all tests. When called in the scope of a test file, runs after all tests in the file. When called inside a [`method: Test.describe`] group, runs after all tests in the group.
### param: Test.afterAll.hookFunction
- `hookFunction` <[function]\([Object], [WorkerInfo]\)>
- `hookFunction` <[function]\([Fixtures], [WorkerInfo]\)>
Hook function that takes one or two arguments: an object with fixtures and optional [WorkerInfo].
@ -75,7 +75,7 @@ Hook function that takes one or two arguments: an object with fixtures and optio
Declares an `afterEach` hook that is executed after each test. When called in the scope of a test file, runs before each test in the file. When called inside a [`method: Test.describe`] group, runs before each test in the group.
### param: Test.afterEach.hookFunction
- `hookFunction` <[function]\([Object], [TestInfo]\)>
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>
Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].
@ -121,7 +121,7 @@ test('my test', async ({ page }) => {
You can use [`method: Test.afterAll`] to teardown any resources set up in `beforeAll`.
### param: Test.beforeAll.hookFunction
- `hookFunction` <[function]\([Object], [WorkerInfo]\)>
- `hookFunction` <[function]\([Fixtures], [WorkerInfo]\)>
Hook function that takes one or two arguments: an object with fixtures and optional [WorkerInfo].
@ -162,7 +162,7 @@ test('my test', async ({ page }) => {
You can use [`method: Test.afterEach`] to teardown any resources set up in `beforeEach`.
### param: Test.beforeEach.hookFunction
- `hookFunction` <[function]\([Object], [TestInfo]\)>
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>
Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].
@ -327,9 +327,9 @@ test('fail in WebKit 2', async ({ page }) => {
```
### param: Test.fail.condition
- `condition` <[void]|[boolean]|[function]\([Object]\):[boolean]>
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures Object and returns a boolean. Test or tests are marked as "should fail" when the condition is `true`.
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are marked as "should fail" when the condition is `true`.
### param: Test.fail.description
- `description` <[void]|[string]>
@ -432,9 +432,9 @@ test.beforeEach(async ({ page }) => {
```
### param: Test.fixme.condition
- `condition` <[void]|[boolean]|[function]\([Object]\):[boolean]>
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures Object and returns a boolean. Test or tests are marked as "fixme" when the condition is `true`.
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are marked as "fixme" when the condition is `true`.
### param: Test.fixme.description
- `description` <[void]|[string]>
@ -465,7 +465,7 @@ test.only('focus this test', async ({ page }) => {
Test title.
### param: Test.only.testFunction
- `testFunction` <[function]\([Object], [TestInfo]\)>
- `testFunction` <[function]\([Fixtures], [TestInfo]\)>
Test function that takes one or two arguments: an object with fixtures and optional [TestInfo].
@ -617,9 +617,9 @@ test.beforeEach(async ({ page }) => {
```
### param: Test.skip.condition
- `condition` <[void]|[boolean]|[function]\([Object]\):[boolean]>
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures Object and returns a boolean. Test or tests are skipped when the condition is `true`.
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are skipped when the condition is `true`.
### param: Test.skip.description
- `description` <[void]|[string]>
@ -702,9 +702,9 @@ test('fail in WebKit 2', async ({ page }) => {
```
### param: Test.slow.condition
- `condition` <[void]|[boolean]|[function]\([Object]\):[boolean]>
- `condition` <[void]|[boolean]|[function]\([Fixtures]\):[boolean]>
Optional condition - either a boolean value, or a function that takes a fixtures Object and returns a boolean. Test or tests are marked as "slow" when the condition is `true`.
Optional condition - either a boolean value, or a function that takes a fixtures object and returns a boolean. Test or tests are marked as "slow" when the condition is `true`.
### param: Test.slow.description
- `description` <[void]|[string]>
@ -738,9 +738,43 @@ test('test with locale', async ({ page }) => {
});
```
It is possible not only to provide a fixture value, but also to override a fixture by providing a fixture function.
```js js-flavor=js
const { test, expect } = require('@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
});
```
```js js-flavor=ts
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: Test.use.fixtures
- `fixtures` <[Object]>
- `fixtures` <[Fixtures]>
An object with fixture values.
An object with fixture definitions.

View File

@ -266,6 +266,36 @@ Whether to update expected snapshots with the actual results produced by the tes
Learn more about [snapshots](./test-snapshots.md).
## property: TestConfig.use
- type: <[Fixtures]>
Additional fixtures for this project. Most useful for specifying options, for example [`property: Fixtures.browserName`]. Learn more about [Fixtures] and [configuration](./test-configuration.md).
```js js-flavor=js
// playwright.config.js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
use: {
browserName: 'chromium',
},
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
use: {
browserName: 'chromium',
},
};
export default config;
```
## property: TestConfig.workers
- type: <[int]>

View File

@ -154,7 +154,7 @@ Optional condition - the test is marked as "fixme" when the condition is `true`.
Optional description that will be reflected in a test report.
## property: TestInfo.fn
- type: <[function]\([Object], [TestInfo]\)>
- type: <[function]\([TestArgs], [TestInfo]\)>
Test function as passed to `test(title, testFunction)`.

View File

@ -273,3 +273,43 @@ 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 [`method: Test.setTimeout`].
## property: TestProject.use
- type: <[Fixtures]>
Additional fixtures for this project. Most useful for specifying options, for example [`property: Fixtures.browserName`]. Learn more about [Fixtures] and [configuration](./test-configuration.md).
```js js-flavor=js
// playwright.config.js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
projects: [
{
name: 'Chromium',
use: {
browserName: 'chromium',
},
},
],
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
projects: [
{
name: 'Chromium',
use: {
browserName: 'chromium',
},
},
],
};
export default config;
```

View File

@ -26,10 +26,10 @@ const Documentation = require('./documentation');
class ApiParser {
/**
* @param {string} apiDir
* @param {string=} paramsPath
*/
constructor(apiDir) {
constructor(apiDir, paramsPath) {
let bodyParts = [];
let paramsPath;
for (const name of fs.readdirSync(apiDir)) {
if (!name.endsWith('.md'))
continue;
@ -314,9 +314,10 @@ function guessRequired(comment) {
/**
* @param {string} apiDir
* @param {string=} paramsPath
*/
function parseApi(apiDir) {
return new ApiParser(apiDir).documentation;
function parseApi(apiDir, paramsPath) {
return new ApiParser(apiDir, paramsPath).documentation;
}
/**

View File

@ -39,7 +39,7 @@ run().catch(e => {
async function run() {
const apiDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
apiDocumentation.filterForLanguage('js');
const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'));
const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
testDocumentation.filterForLanguage('js');
const documentation = apiDocumentation.mergeWith(testDocumentation);
documentation.mergeWith(testDocumentation);