Skip to content

Fixtures and Hooks Interview Questions for Playwright Testing

35 Fixtures and Hooks questions with answers for playwright testing roles — 9 easy, 18 medium, 8 hard.

About Fixtures and Hooks

Covers built-in and custom fixtures, test and worker scope, setup and teardown with use, options, auto fixtures, hooks like beforeEach and beforeAll, describe modes, setup projects and testInfo. Interviewers use this topic to judge whether you can share setup cleanly, keep tests isolated and design reusable building blocks for a team.

Sheet progressStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What are the built-in fixtures page, context, browser and request?

Save to ▾
Show answer
page is a fresh tab for each test. context is the isolated browser context that owns the page, with its own cookies and storage. browser is the shared browser instance for the worker. request is an APIRequestContext for HTTP calls. You ask for them by name in the test function, and Playwright creates and cleans them up automatically.
02

What do beforeAll and afterAll do?

Save to ▾
Show answer
beforeAll runs once before the tests in its file or describe block, and afterAll runs once after them. In Playwright they run once per worker, so if tests are spread over workers they can run more than once. They suit cheap shared setup. They cannot use test-scoped fixtures like page, so open your own page from the browser fixture if needed.
03

How do you override options like baseURL or viewport for one file?

Save to ▾
Show answer
Call test.use at the top of the file or inside a describe block, for example test.use({ viewport: { width: 375, height: 812 }, locale: 'hi-IN' }). The options apply only to tests in that scope. Options you can set this way include baseURL, storageState, colorScheme and extraHTTPHeaders. Global defaults stay in the use block of playwright.config.
04

What does test.describe do?

Save to ▾
Show answer
test.describe groups related tests under one title, which shows up in reports. Hooks and test.use inside the group apply only to those tests. You can nest groups, for example Checkout then Guest user. Groups are only for organisation, they do not make tests share a page or state, so each test still gets fresh fixtures.
05

What are test.skip, test.fixme and test.fail?

Save to ▾
Show answer
test.skip skips a test, optionally with a condition such as browserName === 'webkit'. test.fixme marks a test as broken and does not run it, so it is visible in reports as work to do. test.fail marks a test as expected to fail and reports an error if it unexpectedly passes, which is useful while a known bug is open.
06

In what order do hooks and fixtures run?

Save to ▾
Show answer
Worker fixtures and beforeAll run first for the worker. For each test, the test fixtures it needs are set up, then beforeEach hooks run, then the test body. Afterwards afterEach hooks run, then test fixtures are torn down in reverse order. afterAll and worker fixture teardown run when the worker finishes. Fixtures are lazy, so unused ones never run.
07

Write a beforeEach hook that opens the home page and accepts the cookie banner.

Save to ▾
Show answer
test.beforeEach(async ({ page }) => { await page.goto('/'); const accept = page.getByRole('button', { name: 'Accept cookies' }); if (await accept.isVisible()) { await accept.click(); } });
08

Why is sharing state between tests through module-level variables a bad idea?

Save to ▾
Show answer
Each worker has its own copy of module variables, so values set in one worker are invisible to others, and order changes between runs. Tests that pass alone fail in parallel or after a retry. Pass data through fixtures, or store it in an external source like the API. Each test should be able to run alone, in any order.
09

How do you skip a test only in WebKit?

Save to ▾
Show answer
test('drag a file onto the upload zone', async ({ page, browserName }) => { test.skip(browserName === 'webkit', 'Known WebKit drag issue, ticket QA-123'); await page.goto('/upload'); // rest of the test });
10

How do you use test.step and test annotations?

Save to ▾
Show answer
test.step groups actions into named steps in reports; annotations such as test.skip, test.fixme and test.slow communicate intent and adjust behaviour.
11

What is the difference between beforeEach and fixtures?

Save to ▾
Show answer
beforeEach runs the same code before every test in scope; fixtures are lazy, composable and only set up what a test uses.
12

How do you handle authentication to avoid logging in every test?

Save to ▾
Show answer
Log in once in a setup project, save storageState to a file and reuse it in other projects or tests.
13

What are fixtures and how do you create a custom one?

Save to ▾
Show answer
Fixtures set up and tear down test dependencies. Extend with test.extend({ loggedInPage: async ({ page }, use) => { ...; await use(page); } }).
14

What are global setup and teardown?

Save to ▾
Show answer
Scripts that run once before or after the whole run, for seeding data, starting services or creating authentication state.
15

What is the difference between test-scoped and worker-scoped fixtures?

Save to ▾
Show answer
A test-scoped fixture is created and torn down for every test, which keeps tests isolated. A worker-scoped fixture is set up once per worker process and shared by all tests that run in it, which suits expensive things like a started server or a seeded account. Declare it with { scope: 'worker' }. Worker fixtures cannot depend on test fixtures.
16

Write a custom fixture that gives a logged-in page.

Save to ▾
Show answer
import { test as base } from '@playwright/test'; export const test = base.extend({ loggedInPage: async ({ page }, use) => { await page.goto('/login'); await page.getByLabel('Email').fill('qa@test.in'); await page.getByLabel('Password').fill('Pass@123'); await page.getByRole('button', { name: 'Sign in' }).click(); await use(page); }, });
17

What happens before and after await use() in a fixture?

Save to ▾
Show answer
Code before await use(value) is setup and runs before the test. use hands the value to the test and waits while the test runs. Code after it is teardown and runs when the test finishes, even if it failed. This keeps setup and cleanup for one resource in one place, which is cleaner than a separate beforeEach and afterEach pair.
18

Why can beforeAll run more than once in a Playwright run?

Save to ▾
Show answer
Each worker is a separate process with its own state. When tests from a file are split across workers, or a worker restarts after a failure, beforeAll runs again in the new worker. So never assume it runs only once globally. For one-time setup across the whole run, use a setup project with dependencies or globalSetup.
19

What are automatic fixtures?

Save to ▾
Show answer
A fixture defined with { auto: true } runs for every test even when the test does not ask for it. It is useful for cross-cutting work such as attaching console logs on failure, setting a feature flag or checking for leftover data. Keep auto fixtures light, because they add cost to every test in the suite.
20

A beforeAll creates one user and tests in the same file fail randomly in parallel mode. Why?

Save to ▾
Show answer
With fullyParallel, the file's tests run in different workers, so each worker creates its own user, or tests in one worker share one user and change its state. Shared mutable data causes random failures. Give each test its own data through a test-scoped fixture, or create a unique user per worker with workerInfo.workerIndex in the name.
21

How do you provide page objects as fixtures?

Save to ▾
Show answer
type Pages = { loginPage: LoginPage; cartPage: CartPage }; export const test = base.extend<Pages>({ loginPage: async ({ page }, use) => { await use(new LoginPage(page)); }, cartPage: async ({ page }, use) => { await use(new CartPage(page)); }, }); // test('x', async ({ loginPage }) => { ... })
22

What are the serial and parallel modes of test.describe.configure?

Save to ▾
Show answer
test.describe.configure({ mode: 'serial' }) runs tests in order in one worker, and if one fails the rest are skipped. mode: 'parallel' lets tests in one file run across workers. Serial mode suits a true step-by-step flow, but it makes tests depend on each other, so prefer independent tests and use serial only when there is no alternative.
23

What is testInfo and what can you do with it?

Save to ▾
Show answer
testInfo is passed as the second argument to tests and hooks. It gives the test title, project name, retry number, status and output path. You can attach files, add annotations, change the timeout with testInfo.setTimeout, or skip conditionally. For example, attach extra logs only when testInfo.status differs from testInfo.expectedStatus.
24

Test data is left behind when tests fail midway. How do you guarantee cleanup?

Save to ▾
Show answer
Create the data inside a fixture and delete it after await use(). Fixture teardown runs even when the test fails or times out, so cleanup is reliable. Avoid cleanup steps at the end of the test body, because they never run after a failed assertion. As a safety net, tag test data with a prefix and run a nightly cleanup job.
25

How do you attach a screenshot or log to the report from inside a test?

Save to ▾
Show answer
test('report', async ({ page }, testInfo) => { await page.goto('/reports'); await testInfo.attach('report page', { body: await page.screenshot(), contentType: 'image/png', }); await testInfo.attach('meta', { body: 'build 42', contentType: 'text/plain' }); });
26

Tell me about a time you refactored duplicated setup into fixtures.

Save to ▾
Show answer
Situation: forty test files each repeated twenty lines of login and data setup. Task: reduce duplication and maintenance. Action: I created fixtures for the logged-in page, a test customer and page objects, migrated files in small reviewed pull requests and wrote a short guide. Result: test files became half the size and setup changes now touch one file.
27

How do you share one authenticated API context across all tests in a worker?

Save to ▾
Show answer
Create a worker-scoped fixture that calls request.newContext with baseURL and an auth header, or logs in through the API and keeps the cookies. Pass it to use, and dispose it after use returns. Every test in that worker gets the same ready context, so login happens once per worker. Do not store per-test data on it, or tests start depending on each other.
28

How do you combine fixtures from several files with mergeTests?

Save to ▾
Show answer
When teams define fixtures in separate modules, such as dbTest and a11yTest, mergeTests(dbTest, a11yTest) returns one test object that has all their fixtures. mergeExpects does the same for custom matchers. This keeps fixture modules small and owned by different people. Watch for name clashes, because two modules defining the same fixture name will conflict.
29

A setup fixture creates expensive test data and suite time has doubled. How do you redesign it?

Save to ▾
Show answer
Measure first with the report timings. Then create data through the API instead of the UI, move read-only shared data into a worker-scoped fixture, and seed common reference data once in a setup project. Keep per-test data only for things a test changes. Cache login with storageState. This usually cuts setup time sharply without losing isolation.
30

What is a fixture option and how do you define one?

Save to ▾
Show answer
An option is a fixture whose value is configured rather than computed, declared with { option: true } and a default, for example defaultUser: ['standard', { option: true }]. Projects or test.use can override it, so one suite can run as admin in one project and as a viewer in another. Other fixtures can read the option to decide what to set up.
31

How do project dependencies differ from globalSetup?

Save to ▾
Show answer
A setup project is a normal test file that other projects list in dependencies. It shows in the HTML report, can use fixtures, and records traces, so failures are easy to debug. globalSetup is a plain function that runs before everything without fixtures or traces. The docs now recommend project dependencies for login and data seeding.
32

How do you test a flow that needs two user roles, such as an admin and a customer, in one test?

Save to ▾
Show answer
Create two browser contexts in the same test, each with its own storageState file, for example admin.json and user.json made by a setup project. Wrap them in fixtures like adminPage and userPage so tests stay short. The admin approves an order in one context and the customer sees the update in the other, with fully separate cookies.
33

A worker-scoped fixture holds shared data and some tests see stale values. How do you fix it?

Save to ▾
Show answer
Worker fixtures live across many tests, so any test that changes their data affects the next ones. Keep worker fixtures read-only, such as a connection or a reference catalogue. Move anything a test modifies into a test-scoped fixture that creates fresh data. If sharing is needed for speed, reset the relevant state in the test fixture before use.
34

Describe a time a broken fixture failed many tests at once and how you handled it.

Save to ▾
Show answer
Situation: one morning 300 tests failed in CI. Task: restore the pipeline quickly. Action: the trace showed every test failing inside an auth fixture after a login API change, so I fixed the fixture, added a dedicated setup test that fails fast with a clear message, and alerted the team. Result: the pipeline recovered within an hour and similar outages became easy to spot.
35

Describe a time you designed a fixture layer that other teams adopted.

Save to ▾
Show answer
Situation: three product teams each had their own login and data setup code. Task: give them one reliable layer. Action: I built shared worker-scoped auth fixtures, test-scoped data builders with automatic cleanup, and page object fixtures, published them as an internal package with examples and versioned releases. Result: two more teams adopted it within a quarter, duplicate setup code disappeared and onboarding time for new testers dropped from weeks to days.

Frequently asked questions

How important is Fixtures and Hooks in Playwright Testing interviews?

Covers built-in and custom fixtures, test and worker scope, setup and teardown with use, options, auto fixtures, hooks like beforeEach and beforeAll, describe modes, setup projects and testInfo. Interviewers use this topic to judge whether you can share setup cleanly, keep tests isolated and design reusable building blocks for a team.

How should I use the Fixtures and Hooks sheet?

Go top to bottom — easy to hard. Answer before opening each answer, tick what you solved and save misses to Last-Minute Revision.