Fixtures
By Syncfusion®, Inc. · Last updated
What fixtures are and why they beat hooks, the built-in fixtures (page, context, browser, browserName, request), the testInfo object, custom fixtures with test.extend and use(), fixtures that depend on others, overriding built-ins, test and worker scope, automatic fixtures, timeouts, option fixtures, and sharing fixtures with mergeTests and types.
Fixtures
- You have used
{ page }in every test.pageis a fixture. - A fixture is something a test needs, prepared by Playwright before the test and cleaned up after it.
- You can write your own fixtures, such as "a logged-in page" or "a cart with one item".
- In this lesson, you will see how fixtures work and build several of your own.
Simple lesson: a fixture is ready-made setup that a test asks for by name.
A Real-World Example
- Many of Priya's tests need a logged-in user.
- Instead of copying the login steps into every test, she writes a
loggedInPagefixture once. - Every test that asks for
loggedInPagegets a page that is already logged in.
- Open
tests/fixtures.tsin the explorer to see the fixture. The test file importstestfrom it, not from@playwright/test.
What You Will Learn
- What fixtures are, and why they are better than hooks.
- The built-in fixtures.
- The
testInfoobject. - How to write custom fixtures with setup and teardown.
- Test scope, worker scope, automatic fixtures and timeouts.
- Option fixtures you can set from config or
test.use(). - How to share fixtures between files.
Fixture Fundamentals
What Are Fixtures?
- A test asks for fixtures by name in its first argument:
async ({ page, browserName }) => { ... }. - Playwright creates only the fixtures the test asks for, in the right order, and cleans them up afterwards.
Animation: a fixture runs its setup, then use hands the value to the test, the test runs, and after the test the fixture runs its teardown
fixture: loggedInPage
setup: log in await use(page) teardown: log out
test body uses loggedInPage
page
Code before use() is setup. Code after use() is teardown. use() waits while the test runs.
Setup, hand over with use(), wait for the test, then tear down.
Fixtures vs Hooks
Hooks (beforeEach) | Fixtures | |
|---|---|---|
| Where | In each test file | In one shared file |
| Runs for | Every test in the group | Only tests that ask for it |
| Setup and teardown | Two separate hooks | One function, around use() |
| Reuse | Copy and paste | Import and ask by name |
Why Fixtures Are Preferred
- Setup and teardown live together, so you never forget the clean-up.
- A test lists what it needs right in its arguments. Reading the test tells you its setup.
- Playwright builds fixtures only when needed, so unused setup costs nothing.
Simple lesson: fixtures keep setup and teardown together, and run only for tests that need them.
Built-in Fixtures
| Fixture | Gives you | Scope |
|---|---|---|
page | A new page (tab) for this test | test |
context | The browser context that page lives in | test |
browser | The shared browser | worker |
browserName | 'chromium', 'firefox' or 'webkit' | worker |
request | An API client for HTTP requests | test |
contextis used in depth in Browser Contexts, Pages, and Emulation.requestis used in API Testing.
Simple lesson: page, context, browser, browserName and request come built in.
The testInfo Object
test.info()
testInfodescribes the running test. Get it as the second argument of a test, or withtest.info().
Test Title, Project and Retry Count
testInfo.title,testInfo.project.nameandtestInfo.retrytell you which test, which project and which try this is.
testInfo.outputPath()
testInfo.outputPath('cart.json')gives a file path inside this test's own folder intest-results/.testInfo.attach()adds a file or text to the report.
- Open the Steps tab. The attachment is listed under the test.
Simple lesson: testInfo tells a test about itself, and lets it attach files to the report.
Custom Fixtures
test.extend()
base.extend({ ... })makes a newtestwith extra fixtures. Each key is a fixture name.- Export the new
testand import it in your test files instead of the original.
Setup and Teardown with use()
- A fixture is an
asyncfunction with three arguments: the fixtures it needs,use, andtestInfo. - Everything before
await use(value)is setup. Everything after it is teardown.
Fixtures That Depend on Other Fixtures
- A fixture asks for other fixtures in its first argument, like a test does.
- Playwright builds them in the right order: dependencies first.
Overriding Built-in Fixtures
- You can redefine
page. Ask for the originalpageand wrap it. - Below, every test's
pagestarts on the products page, and acartfixture depends on it.
Simple lesson: test.extend() adds fixtures. Setup goes before use(), teardown after it.
Fixture Scope and Behavior
Test-Scoped and Worker-Scoped Fixtures
- Test scope (the default): a fresh value for every test.
- Worker scope: one value shared by all tests in the same worker process. Use it for slow setup, such as creating a test account.
- Write the scope in an options object:
[async ({}, use) => { ... }, { scope: 'worker' }].
Animation: one worker runs three tests. A worker-scoped account is created once at the start and shared by all three tests. A test-scoped page is created fresh for each test and thrown away after it
Worker 1
account (scope: 'worker'): created once, shared by every test
A worker fixture lives as long as the worker. A test fixture is made and thrown away for every test.
Automatic Fixtures
{ auto: true }makes a fixture run for every test, even if no test asks for it.- Good for things that must always happen, such as logging or checking for console errors.
Fixture Timeouts
- A slow fixture can have its own
timeout:{ timeout: 60_000 }.
- The Terminal shows "create the account once" a single time, for two tests.
A worker-scoped fixture is shared. If one test changes it, the next test sees the change. Keep shared values read-only.
Simple lesson: test scope gives each test its own value. Worker scope shares one. auto runs it always.
Fixture Options
Option Fixtures
- An option is a fixture with a default value that tests and config can change.
- Declare it with
{ option: true }:currency: ['INR', { option: true }].
Setting Option Values
- Change it for a file or a group with
test.use({ currency: 'USD' }). - Change it for a whole project in the config, under
use. - Built-in settings such as
baseURL,viewportandlocaleare option fixtures too.
Simple lesson: option fixtures have defaults you can change with test.use() or the config.
Sharing Fixtures
Putting Fixtures in a Shared File
- Keep fixtures in files such as
tests/fixtures.ts. Exporttestandexpectfrom it. - Every test file imports from that file.
mergeTests()
- Big projects split fixtures by topic:
auth-fixtures.ts,cart-fixtures.ts. mergeTests(authTest, cartTest)combines them into onetestwith all their fixtures.
import { mergeTests } from '@playwright/test';
import { test as authTest } from './auth-fixtures';
import { test as cartTest } from './cart-fixtures';
export const test = mergeTests(authTest, cartTest);
Typed Fixtures (TypeScript)
base.extend<MyFixtures>({ ... })tells TypeScript each fixture's type.- Then the editor completes
loggedInPage.with page methods, and marks typos. - The second type argument lists worker fixtures:
base.extend<TestFixtures, WorkerFixtures>().
The first argument of a test or fixture must be an object pattern such as { page }. Playwright reads the names in it to know which fixtures to build. async (fixtures) => ... is an error.
Fixtures are where Page Object Model classes usually come from. A productsPage fixture can hand each test a ready-made page object.
Simple lesson: keep fixtures in a shared file, and combine several with mergeTests().
Try It in Your Project
- These steps take the lesson from the lab to your own app.
- Replace one
beforeEachthat creates data with a fixture that also cleans it up. - Put your fixtures in
tests/fixtures.tsand importtestfrom there in every spec. - Make one slow setup worker-scoped and measure the time saved.
Simple lesson: use one idea from this lesson on your own app this week.
TL;DR
- A fixture is setup a test asks for by name. Playwright builds and cleans it up.
- Built-ins:
page,context,browser,browserName,request. testInfodescribes the running test and can attach files.base.extend({ name: async (deps, use) => { setup; await use(value); teardown } }).- Scope is test (default) or worker.
autoruns a fixture always.optionmakes it configurable. - Share with a fixtures file and
mergeTests().
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
async (fixtures) => ... | "First argument must use the object destructuring pattern" | Write async ({ page }) => ... |
Forgetting await use(...) | The test never gets the value | Call await use(value) exactly once |
Importing test from @playwright/test in a spec that needs custom fixtures | "Test has unknown parameter" | Import test from your fixtures file |
Teardown code before use() | It runs before the test, not after | Put clean-up after await use(...) |
| Changing a worker-scoped value in a test | Other tests see the change | Treat worker fixtures as read-only |
Check Yourself
Exercises
What to Remember
- Fixtures are named setup that tests ask for.
- Setup before
use(), teardown after it. - Test scope by default. Worker scope for slow, shared, read-only setup.
autofixtures always run.optionfixtures are set withtest.use()or the config.- Share fixtures through one file, and
mergeTests()for several.
Next: Playwright Configuration