Playwright Test is based on the concept of the test fixtures. Test fixtures are used to establish environment for each test, giving the test everything it needs and nothing else. Test fixtures are isolated between tests, which gives Playwright Test following benefits:
- Playwright Test runs tests in parallel by default, making your test suite much faster.
- Playwright Test can efficiently retry the flaky failures, instead of re-running the whole suite.
- You can group tests based on their meaning, instead of their common setup.
Here is how typical test environment setup differs between traditional test style and the fixture-based one. We assume a `TodoPage` class that helps interacting with a "todo list" page of the web app.
You declare exact fixtures that the test needs and the runner initializes them for each test individually. Tests can use any combinations of the fixtures to tailor precise environment they need. You no longer need to wrap tests in `describe`s that set up environment, everything is declarative and typed.
There are two types of fixtures: `test` and `worker`. Test fixtures are set up for each test and worker fixtures are set up for each process that runs test files.
## Test fixtures
Test fixtures are set up for each test. Consider the following test file:
// This fixture is a constant, so we can just provide the value.
hello: 'Hello',
// This fixture has some complex logic and is defined with a function.
helloWorld: async ({ hello }, use) => {
// Set up the fixture.
const value = hello + ', world!';
// Use the fixture value in the test.
await use(value);
// Clean up the fixture. Nothing to cleanup in this example.
},
});
// Now, this "test" can be used in multiple test files, and each of them will get the fixtures.
export default test;
```
With fixtures, test organization becomes flexible - you can put tests that make sense next to each other based on what they test, not based on the environment they need.
## Worker fixtures
Playwright Test uses worker processes to run test files. You can specify the maximum number of workers using `--workers` command line option. Similarly to how test fixtures are set up for individual test runs, worker fixtures are set up for each worker process. That's where you can set up services, run servers, etc. Playwright Test will reuse the worker process for as many test files as it can, provided their worker fixtures match and hence environments are identical.
In addition to creating your own fixtures, you can also override existing fixtures to fit your needs. Consider the following example which overrides the `page` fixture by navigating to a specified URL:
```js js-flavor=js
const base = require('@playwright/test');
exports.test = base.test.extend({
page: async ({ baseURL, page }, use) => {
await page.goto(baseURL);
await use(page);
},
});
```
```js js-flavor=ts
import { test as base } from '@playwright/test';
export const test = base.extend({
page: async ({ baseURL, page }, use) => {
await page.goto(baseURL);
await use(page);
},
});
```
Notice that in this example, the `page` fixture is able to depend on other built in fixtures such as `baseURL`. This allows us to override the `baseURL` used by the `page` fixture in our tests using `test.use`.
```js js-flavor=js
test.use({ baseURL: 'https://playwright.dev' })
```
```js js-flavor=ts
test.use({ baseURL: 'https://playwright.dev' })
```
Fixtures can also be overridden where the base fixture is completely replaced with something different. For example, we could override the `storageState` fixture to provide our own data.