Skip to content

Scenario-Based Playwright Testing Interview Questions

79 questions with answers. Real-work situations — broken dashboards, flaky tests, unclear requirements — and how a strong Playwright automation engineer would handle them.

How to approach these questions

Clarify the situation, list likely causes, say how you would check each one, then give the fix and how you would stop it happening again.

Solved — scenario-basedStart 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

How do you reuse login state across tests?

Save to ▾
Show answer
Log in once in global setup, save storageState to a JSON file and set use.storageState in the config so every test starts logged in.
02

How do you reduce the execution time of a 2000-test suite?

Save to ▾
Show answer
Run in parallel with sharding, reuse authentication state, set up data through APIs, avoid unnecessary waits, run smoke on every commit and the full suite nightly.
03

Tests are flaky in CI. How do you debug them?

Save to ▾
Show answer
Turn on trace: 'on-first-retry', open the trace viewer, check network and timing, replace hard waits with web-first assertions, isolate test data and check for sharding conflicts.
04

How would you handle a very flaky element that appears after an animation?

Save to ▾
Show answer
Rely on auto-waiting plus a web-first assertion on the final state, disable animations in config for tests and avoid fixed timeouts.
05

How do you handle token refresh in long API test runs?

Save to ▾
Show answer
Fetch tokens in a fixture with expiry tracking and refresh it when it is about to expire, keeping tests unaware of the details.
06

Design a Playwright framework for a 500-test suite.

Save to ▾
Show answer
TypeScript + POM + custom fixtures, environment configs, API helpers for test data, tags like @smoke, sharding across CI machines, retries with traces, HTML/Allure reports, lint and review rules.
07

How do you mock third-party APIs in UI tests?

Save to ▾
Show answer
Use page.route to intercept the call and fulfil it with fixed JSON so tests do not depend on external systems.
08

How would you design API test coverage for a new endpoint?

Save to ▾
Show answer
Cover happy path, validation errors, auth and permissions, boundary values, idempotency, schema, performance and data cleanup.
09

What happens if you forget an await?

Save to ▾
Show answer
The action runs without waiting, so the next step may run first — causing flaky failures or 'Target closed' errors. The @typescript-eslint/no-floating-promises rule catches it.
10

How do you test API error scenarios?

Save to ▾
Show answer
Send invalid payloads or missing auth and assert 400, 401 or 404 codes and the error message bodies.
11

How do you handle rate limits or slow APIs in tests?

Save to ▾
Show answer
Add retries with backoff for the API step, set a suitable timeout, and use mocks for non-critical dependencies.
12

A locator matches three Delete buttons and the test fails with a strict mode violation. How do you fix it?

Save to ▾
Show answer
First scope the locator to the item you mean, for example the row that contains the user's name: page.getByRole('row', { name: 'Ravi Kumar' }).getByRole('button', { name: 'Delete' }). Do not reach for first() or nth() as a quick fix, because the order can change and the test may delete the wrong record. Scoping by meaningful context is stable and readable.
13

Your test clicks a button before the page's JavaScript has attached its handler, so nothing happens. What do you do?

Save to ▾
Show answer
This is a hydration problem: the button is visible and enabled but not yet interactive. Wait for a signal that the app is ready, such as a loaded data request or a visible element that only appears after hydration, then click. A better fix is to report it to developers, because real users hit the same issue. Avoid fixed waitForTimeout calls.
14

How do you design a locator strategy for a team so tests survive UI redesigns?

Save to ▾
Show answer
Set a written priority order: role with name, then label, placeholder or text, then test id, and CSS or XPath only as a last resort. Agree with developers to add data-testid on complex widgets. Keep locators inside page objects so a change is fixed in one place. Add a lint rule or review check against long CSS chains and nth-child selectors.
15

Developers keep changing CSS class names and 40 tests break every sprint. How do you fix this long term?

Save to ▾
Show answer
Replace class-based selectors with role, label and text locators, and agree on data-testid for widgets without good semantics. Move all locators into page objects so future changes touch one file. Add a code review rule and a lint check that flags raw CSS selectors. Share a short locator guide with developers so they know which attributes tests depend on.
16

A toast message disappears after two seconds and the assertion on it is flaky. How do you test it reliably?

Save to ▾
Show answer
Assert immediately after the action that triggers it, using a web-first assertion like toBeVisible and toHaveText, which start checking at once. Do not add sleeps before the check. If the toast is still missed, control time with page.clock so it does not auto-hide, or verify the result through the data it confirms, such as the saved record.
17

A test checks a price that is formatted differently per locale. How do you make the assertion robust?

Save to ▾
Show answer
Fix the locale for the test with the locale and timezoneId options so the format is predictable. Build the expected string with Intl.NumberFormat using the same locale, rather than hard-coding it. If you test several locales, run them as projects or parameterised tests. For business logic, also assert the raw number through the API response.
18

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.
19

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.
20

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.
21

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.
22

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.
23

Your mocked route never fires. What do you check?

Save to ▾
Show answer
Check that the route is registered before the request is sent, usually before goto. Compare the pattern with the real URL in the trace network tab, including query strings and host. Make sure a service worker is not handling the request, and set serviceWorkers: 'block' if it is. Also check that another handler is not matching first or the route was not removed.
24

How do you test how the UI handles a 500 error from the orders API?

Save to ▾
Show answer
Mock the endpoint with route.fulfill({ status: 500, json: { message: 'Server error' } }), then open the page. Assert the user sees a friendly error message and a retry button, and that no broken half-rendered table appears. Then make the retry return 200 and check the data loads. This covers a path that is hard to trigger on a real server.
25

Mocked responses drift from the real API and tests pass while production breaks. How do you prevent this?

Save to ▾
Show answer
Generate mock data from the API schema or real recorded responses instead of hand-writing it. Validate mocks against the OpenAPI schema in a unit test. Add contract tests on the backend side and re-record HAR files on a schedule. Keep a few unmocked end-to-end tests that run after each deploy. Treat mock files as code with owners and reviews.
26

A third-party analytics script makes tests slow and flaky. What do you do?

Save to ▾
Show answer
Block it in tests with context.route on its domain and route.abort, or fulfill it with an empty script. Analytics is not what you are testing, and blocking it removes delays and random network errors. If tracking events matter, write a few separate tests that capture the requests with waitForRequest and assert their parameters.
27

A feature is controlled by a flag served from a config API. How do you test both states?

Save to ▾
Show answer
Mock the config endpoint in a fixture option so each test chooses the flag value, for example featureFlags: { newCheckout: true }. Run the flow with the flag on and off and assert the different UI. Mocking avoids changing shared environment settings that would affect other testers. Also keep one test against the real config to catch wiring mistakes.
28

The app polls a status endpoint every few seconds. How do you test the change from Pending to Done?

Save to ▾
Show answer
Mock the endpoint with a counter: return Pending for the first two calls and Done after that. Then assert the UI shows Pending and later Done using web-first assertions with a suitable timeout. You can also use page.clock to speed up the polling interval instead of waiting real seconds. This makes a slow real-world process quick and deterministic.
29

A test passes locally but fails in CI with a timeout on a click. How do you use the trace?

Save to ▾
Show answer
Open the CI trace and go to the failed click. Check the action log, which shows what Playwright waited for, such as the element not being visible or another element intercepting pointer events. Compare before and after snapshots and the network tab for slow or failed calls. Common causes are a slower environment, a cookie banner or different screen size.
30

The suite has a 3 percent flaky rate. How do you find and fix the causes systematically?

Save to ▾
Show answer
Collect data first: flaky results from the reports across a few weeks, grouped by test, browser and error message. Run the worst offenders with --repeat-each and traces on. Fix common causes such as missing awaits, shared data, fixed sleeps and order-dependent tests. Quarantine tests you cannot fix quickly with a tag and a ticket, and track the rate weekly.
31

A trace shows the click landed on an overlay instead of the button. How do you fix it?

Save to ▾
Show answer
The call log will say another element intercepts pointer events. Find what the overlay is, such as a loading mask, cookie banner or chat widget. Wait for it to disappear with expect(overlay).toBeHidden(), or close it in a fixture. Do not use force: true, because it hides a real issue: a user would also be blocked by that overlay.
32

A test fails only in WebKit. How do you investigate?

Save to ▾
Show answer
Run it alone with --project=webkit --headed and record a trace. Compare it with the Chromium trace to see where behaviour differs, such as date input format, scrolling, font rendering or a missing browser API. Check the app's support matrix. If it is a real product bug, raise it, and skip the test for WebKit with a linked ticket until it is fixed.
33

Tests pass with one worker but fail with eight. How do you debug this?

Save to ▾
Show answer
This usually means tests share something: the same user account, the same records or a global server setting. Run the failing file with --workers=8 and --repeat-each to reproduce it. Look at which tests run at the same time in the report. Fix it by giving each test unique data, using workerIndex in names, or isolating shared settings per worker.
34

How do you test the difference between 401 and 403 responses?

Save to ▾
Show answer
401 Unauthorized means the caller is not authenticated, such as a missing or expired token. 403 Forbidden means the caller is known but lacks permission. Test 401 by calling without a token or with an invalid one. Test 403 by calling an admin endpoint with a normal user's token. Assert the status and that no data leaks in the body.
35

An API returns 200 but the body contains an error field. How should your test catch this?

Save to ▾
Show answer
Never trust status alone. Assert the body structure, for example that error is absent and data has the expected fields, ideally with a schema check. Report the issue, because returning 200 for errors breaks clients and monitoring. Add a helper that validates both status and body shape so every test checks it consistently.
36

An API test fails randomly because another test changes the same record. How do you fix it?

Save to ▾
Show answer
Make each test own its data. Create the record inside the test or a fixture with a unique name, such as one using a timestamp or the worker index, and delete it in teardown. Avoid shared seed records for anything that gets modified. Shared read-only reference data is fine. This also lets tests run fully in parallel.
37

How do you test an async job API that returns 202 and finishes later?

Save to ▾
Show answer
Start the job and assert the 202 status and the returned job id. Then poll the status endpoint with expect.poll, with sensible intervals and a timeout, until it reports completed. Finally fetch the result and validate it. Also test the failure path, for example invalid input leading to a failed status with a clear error message.
38

How do you keep API tests independent of environment data?

Save to ▾
Show answer
Do not depend on records that happen to exist in a shared environment. Each test or fixture creates what it needs through the API and cleans up after. Read environment-specific values such as base URL and credentials from config. For reference data that must exist, seed it in a setup project and verify it before tests run.
39

An endpoint should reject invalid email addresses. Which negative tests would you write?

Save to ▾
Show answer
Cover empty string, missing field, null, wrong type such as a number, no at sign, no domain, spaces, very long strings and a duplicate existing email. For each, assert a 400 or 422 status, a clear error message naming the field, and that nothing was created. Also check that a valid email with uppercase letters is accepted.
40

How do you test that duplicate POST requests do not create duplicate orders?

Save to ▾
Show answer
If the API supports an idempotency key header, send the same POST twice with the same key and assert one order exists and both responses return the same id. Send it with different keys and expect two orders. Also try concurrent requests with Promise.all to check race conditions. Without a key, document the risk to the team.
41

A product list uses infinite scroll. How do you test that more items load?

Save to ▾
Show answer
Count the items, then scroll the last item into view with lastItem.scrollIntoViewIfNeeded() or page.mouse.wheel. Assert with expect(items).toHaveCount greater than before, for example using expect.poll on items.count(). Repeat until an end-of-list message appears. Also check no duplicates appear and that a loading indicator shows while fetching.
42

The app logs in through a third-party OAuth pop-up. How do you automate it?

Save to ▾
Show answer
For most tests, avoid the pop-up: get a session through a test login API or a test identity provider and save it with storageState. Keep one test for the real flow, using const popup = page.waitForEvent('popup') before clicking, then fill the provider's form inside popup. Third-party pages can change and add captchas, so limit how often you depend on them.
43

A test uses forEach with an async callback and the checks inside never seem to run. Why?

Save to ▾
Show answer
forEach does not wait for async callbacks, so it starts each callback and returns at once. The test may finish before the assertions run, or their errors are lost. Use for...of with await to run steps in order, or Promise.all with map when the steps can safely run in parallel. A lint rule can flag this pattern.
44

CI fails with an error saying the browser executable does not exist. How do you fix it?

Save to ▾
Show answer
The browsers are not installed on the CI machine. Add a step that runs npx playwright install --with-deps after npm ci, which downloads the browsers and the OS libraries they need. Or run inside the official Playwright Docker image that matches your Playwright version. Cache browsers to speed this step up.
45

Ten engineers write tests and quality varies a lot. How do you keep the framework consistent?

Save to ▾
Show answer
Write a short contribution guide with examples. Add ESLint with the Playwright plugin and the no-floating-promises rule, plus Prettier, enforced in CI. Require reviews from framework owners for shared fixtures and page objects. Provide generators or templates for new page objects, and run regular sessions to review flaky tests together.
46

How do you manage flaky tests without hiding real failures?

Save to ▾
Show answer
Use retries in CI so one-off failures do not block merges, but treat any test marked flaky in the report as a defect. Track flaky tests on a dashboard, quarantine repeat offenders with a tag and an owner, and set a deadline to fix or delete them. Never retry without investigating, or real intermittent bugs will be missed.
47

Retries make the build green, but nobody notices flaky tests. How do you surface them?

Save to ▾
Show answer
Playwright already marks tests that passed on retry as flaky in the HTML and JSON reports. Read the JSON report in a small script after each run, post flaky test names to the team channel, and fail the build if the flaky count crosses a threshold. Over time you can track trends per test and per area.
48

How do you upgrade Playwright safely in a large suite?

Save to ▾
Show answer
Read the release notes for breaking changes and deprecations. Upgrade on a branch, update the browsers and the Docker image to the same version, and run the full suite on all projects several times. Compare visual snapshots, which often change after browser updates. Upgrade regularly in small steps rather than skipping many versions.
49

Visual tests pass on developers' laptops but fail in CI with tiny font differences. Why, and how do you fix it?

Save to ▾
Show answer
Font rendering, anti-aliasing and installed fonts differ between Windows, macOS and Linux, so the same page produces slightly different pixels. The fix is to generate and compare baselines in one fixed environment, usually the official Playwright Docker image used in CI. Developers update baselines by running that container locally or through a CI job, not from their own machines. Loosening thresholds should be the last resort.
50

Baselines are always rendered in Docker, yet the repo has separate Windows and Linux image files. How do you keep one baseline per browser?

Save to ▾
Show answer
The default file name includes the platform, so a developer who updated baselines on Windows created a second set. Set snapshotPathTemplate in the config without the {platform} token, for example '{testDir}/__screenshots__/{testFilePath}/{arg}-{projectName}{ext}', delete the stray files and only update baselines through the Docker command or a CI job. Document the rule so it does not happen again.
51

A designer changes the primary button colour and 300 visual tests fail at once. How do you handle it?

Save to ▾
Show answer
First confirm the change is intended and check a sample of diffs to make sure nothing else moved. Then regenerate baselines in the CI Docker environment in a separate commit, so reviewers can see only image changes. Longer term, reduce the count: most of those tests should not snapshot full pages. Keep a few page-level shots and move detail checks to component-level screenshots of key states.
52

An axe scan reports 40 violations on a legacy page. How do you add accessibility checks without blocking every build?

Save to ▾
Show answer
Record the current violations as a known baseline, for example by snapshotting violation ids and targets, and fail only on new ones. Fix the worst issues first, such as missing labels and contrast on key flows, and shrink the baseline every sprint. Make new pages and components meet zero violations from day one. Report the trend to the team so the debt is visible rather than silently ignored.
53

How do you test that a modal dialog traps focus and returns it when closed?

Save to ▾
Show answer
Open the dialog with a button and assert the dialog role is visible and focus moved inside it. Press Tab more times than there are controls and check with toBeFocused that focus never leaves the dialog. Press Escape, assert the dialog is hidden, and check that the opening button is focused again. Running the same test with Shift+Tab covers backward navigation as well.
54

A screenshot test fails with only a few pixels different because of anti-aliasing. What do you do?

Save to ▾
Show answer
Open the diff image in the HTML report to confirm it is just edge smoothing and not a real change. If baselines were made on a different machine, regenerate them in the CI image. If the noise is genuine and repeatable, allow a small maxDiffPixels for that assertion or project. Avoid large ratios, because they also let real layout shifts through.
55

A screenshot of a search page is flaky because a blinking text cursor appears in the input. How do you fix it?

Save to ▾
Show answer
toHaveScreenshot hides the text caret by default with caret: 'hide', so check that nobody set it to 'initial' and that you are not using page.screenshot with toMatchSnapshot, which lacks some of these defaults. Also blur the input or click elsewhere before the capture if focus styles change. Using the dedicated assertion gives you stable captures and retries.
56

Images load lazily and are sometimes missing from full-page screenshots. How do you make them stable?

Save to ▾
Show answer
Scroll the content into view or remove loading=lazy for the test, then wait until every image has loaded, for example with expect.poll checking that all img elements report complete and a natural width above zero. Serving images from mocked routes removes network timing too. Only after that call toHaveScreenshot, which then waits for two identical frames.
57

An endpoint streams server-sent events. How would you test it with Playwright?

Save to ▾
Show answer
The request fixture returns the full body only after the stream ends, so for a short finite stream you can read text() and parse each data line. For long-lived streams, test in the browser: open the page that uses EventSource, or open it inside page.evaluate, collect events into an array and assert with expect.poll. Mock the source with a route when you need precise timing.
58

A multi-select filter test passes even when an extra option stays selected. How do you tighten it?

Save to ▾
Show answer
The test probably checks only that the wanted options are selected, for example with a loop of toBeChecked or a contains check. Replace it with await expect(select).toHaveValues(['red', 'green']), which passes only when exactly those values are selected, and it retries until the timeout. For custom multi-select widgets, assert the full list of selected chips with toHaveText on the chip locator.
59

A test must confirm that an error banner does not appear, but it always waits the full timeout. How do you fix it?

Save to ▾
Show answer
Use a web-first negative assertion such as await expect(banner).toBeHidden() or not.toBeVisible(); they pass as soon as the element is absent, so they do not wait the full timeout. The real problem is timing: assert after a positive signal, such as the success message appearing, otherwise the banner may simply not have rendered yet and the check passes too early.
60

A component under test needs a complex class instance as a prop and the test fails to serialise it. What do you do?

Save to ▾
Show answer
Create a small test story component in a separate file that builds the class instance inside the browser and renders the real component with it. The test then mounts the story with simple props, such as an id or a scenario name. This keeps the data creation on the browser side of the boundary and also documents test scenarios as reusable stories.
61

Component tests fail because imports like @/utils cannot be resolved, though the app builds fine. How do you fix it?

Save to ▾
Show answer
The app uses a bundler alias that the component test bundle does not know. Add the same alias in ctViteConfig under resolve.alias, or reuse the project's Vite config by importing it. Also make sure tsconfig paths match, so editors and type checks agree. After that, clear the cache folder that the component bundler writes under playwright/.cache so the bundle rebuilds.
62

Component tests render without any styling. What is missing?

Save to ▾
Show answer
Global CSS, CSS variables and fonts are normally loaded by the app's entry file, which component tests do not use. Import them in playwright/index.tsx so they are part of the test bundle. If the styling comes from a provider, such as a theme or CSS-in-JS setup, wrap the app in beforeMount. Without this, visibility and layout checks may give misleading results.
63

The team wants to replace all end-to-end tests with component tests to save time. What do you advise?

Save to ▾
Show answer
Agree to move detailed UI checks down to component tests, because they are faster and more precise. But keep a thin layer of end-to-end tests for critical journeys like signup, checkout and payment, since component tests use mocked data and cannot catch broken APIs, routing or deployment issues. Decide per risk, measure runtime savings, and track escaped defects after the change.
64

Component and end-to-end tests run together and slow down every commit. How do you separate them?

Save to ▾
Show answer
Give them separate configs, such as playwright-ct.config.ts with its own testDir for component specs and playwright.config.ts for end-to-end tests, because component tests also need the bundler options and framework test import. In CI, run component tests on every commit as a fast job and end-to-end tests later or in parallel. Shared settings like reporters can live in a common module both configs import.
65

A component test passes alone but fails when the full component suite runs. What do you check?

Save to ▾
Show answer
Look for state that leaks between mounts: global stores or singletons created at module level in index.tsx, timers or listeners not cleaned up on unmount, and shared mock data mutated by one test. Make the providers create fresh state in beforeMount each time and reset mocks per test. Running with --repeat-each and a single worker often reproduces the leak quickly.
66

How do you test a dropdown component's keyboard support in a component test?

Save to ▾
Show answer
Mount the dropdown, focus the trigger and press Enter or ArrowDown to open it. Assert the listbox is visible and the first option has aria-selected or focus. Press ArrowDown again and check the active option moves, then press Enter and assert the trigger shows the chosen value and the list is closed. Finally press Escape on an open list to confirm it closes without changing the value.
67

A fixture mocks every /api call, but one test needs a different response for /api/cart. How do you override it?

Save to ▾
Show answer
Register a new page.route for /api/cart inside that test. Handlers run in reverse order of registration, so the newer one runs first. Fulfil the cart request with the special data, and for anything else call route.fallback() so the request moves on to the fixture's general handler. This keeps the shared mock untouched and makes the override local and easy to read.
68

How do you handle a page that opens a browser permission prompt for notifications?

Save to ▾
Show answer
Browser permission prompts are not part of the page, so you cannot click them. Instead grant the permission up front with the permissions option in the config or context, for example permissions: ['notifications'], or call context.grantPermissions. To test the denied path, create a context without the permission and assert that the app shows its fallback message.
69

How do you verify that an API returns consistent data across two versions of an endpoint?

Save to ▾
Show answer
Call both versions, for example /v1/orders/42 and /v2/orders/42, with the same test data. Map the fields that should match, since names may differ, and compare them with toEqual. Also assert that fields removed in v2 are really absent and new ones have correct types. Running this during a migration catches breaking changes before clients switch.
70

Two test files edit the same global settings page and break each other when run in parallel. How do you handle it?

Save to ▾
Show answer
The best fix is to remove the shared resource, for example by giving each test its own tenant or user whose settings it can change. If that is impossible, put those tests in one file with test.describe.configure({ mode: 'serial' }), or in a separate project that runs with one worker after the main project. Document why, so the exception does not quietly spread.
71

One shard finishes in 4 minutes and another takes 15. How do you balance them?

Save to ▾
Show answer
Check whether fullyParallel is off, because file-level sharding puts big files together. Turn it on if tests are independent, or split the largest files. Use reportSlowTests and the merged report's durations to find heavy files, and move slow setup into API calls or shared storage state. Also check that one shard is not getting all the tests of a slow project such as WebKit.
72

CI runners have 2 CPU cores and workers is set to 8. Tests start timing out randomly. Why?

Save to ▾
Show answer
Eight browsers compete for two cores and limited memory, so pages render slowly, actions hit timeouts and the app under test may also be overloaded. More workers than cores rarely helps. Set workers to match the runner, such as 2, and scale out with shards on more machines instead. Watch CPU and memory metrics in CI to confirm.
73

Parallel tests create users with the same email and fail with 'already exists'. How do you fix it?

Save to ▾
Show answer
Generate unique data per test, for example by adding testInfo.testId, the parallel index or a random suffix to the email, or by using a data builder that creates a fresh user through the API. Avoid hard-coded shared records in test files. Clean up created users in a fixture teardown so the database does not fill up over time.
74

How would you build a flaky-test dashboard from Playwright results?

Save to ▾
Show answer
Write a custom reporter or parse the JSON report after each CI run, and store per test: id, status, retry count, duration, branch and commit. A test that passed after a retry counts as flaky. Aggregate over the last few hundred runs to rank tests by flake rate and duration, and show trends. Use it to assign owners and quarantine tests above an agreed threshold.
75

How do you rerun only the tests that failed in a sharded CI run?

Save to ▾
Show answer
--last-failed works only on the machine that kept the .last-run.json file, so it does not help across shards. Instead collect the failed tests from the merged JSON report or the blob reports, then run them in a follow-up job by file and line or with --grep on their titles. Many teams simply rely on retries and treat any test needing a rerun as flaky.
76

How do you run tests against a preview deployment created for each pull request?

Save to ▾
Show answer
Make baseURL come from an environment variable, such as process.env.BASE_URL, with a default for local runs. In the pipeline, wait for the preview deployment to be ready, read its URL from the deployment step and pass it to the test job. Add a quick health check request first, so a failed deployment is reported clearly instead of as hundreds of test failures.
77

A test fails with 'Target page, context or browser has been closed'. What usually causes it?

Save to ▾
Show answer
Most often an action was not awaited, so the test finished and Playwright closed the page while the action was still running. Other causes are a test timeout closing the page, the code closing the page or context itself, or the browser crashing. Check the stack for the missing await, look at whether a timeout happened first, and turn on the lint rule for floating promises.
78

How do you test that the app retries a request that failed the first time?

Save to ▾
Show answer
Register a route with a counter: on the first call use route.fulfill with status 503, and on later calls fulfil with a success body. Perform the action, then assert the UI shows the final data and the counter equals 2. You can also check that no error message flashed. This proves the retry logic works without waiting for a real outage.
79

An API receives a payload with an unknown extra field. How do you test what it should do?

Save to ▾
Show answer
First confirm the contract: should unknown fields be rejected with 400 or silently ignored? Then send a valid body with an extra field and assert that behaviour. If they are ignored, fetch the record and check the extra field was not stored. Also try sending a field that should be read-only, such as role or id, to catch mass assignment bugs.

Frequently asked questions

Why are scenario-based questions important?

They show how you think on real problems. Interviewers use them to separate people who memorised definitions from people who have done the work.

How should I answer them?

Clarify the situation, list likely causes, say how you would check each one, then give the fix and how you would stop it happening again.