25. Strict mode violation
This Playwright line fails with "strict mode violation: resolved to 2 elements". A Save button exists in the page and inside an open dialog. What is the best fix?
await page.locator('button', { hasText: 'Save' }).click()- A.Use .first() so it always clicks the first match
- B.Use page.click() with force: true
- C.Scope it to the dialog and use a role locator: page.getByRole('dialog').getByRole('button', { name: 'Save', exact: true }).click()
- D.Turn off strict mode in the config
Show answer
Answer: C. Scope it to the dialog and use a role locator: page.getByRole('dialog').getByRole('button', { name: 'Save', exact: true }).click()
Strict mode protects you from clicking the wrong element. .first() hides the ambiguity and can click the background Save button when the layout changes. Scoping to the dialog and using an exact accessible name targets the element the user means. force: true skips actionability checks, which hides real bugs.
26. Hidden race in a test
What is wrong with this Playwright test?
test('shows cart count', async ({ page }) => {
await page.getByRole('button', { name: 'Add to cart' }).click()
expect(page.getByTestId('cart-count')).toHaveText('1')
})- A.getByTestId does not exist in Playwright
- B.click() must be called twice
- C.The assertion is not awaited, so the test can finish before it is checked and pass or fail unpredictably
- D.toHaveText cannot compare numbers
Show answer
Answer: C. The assertion is not awaited, so the test can finish before it is checked and pass or fail unpredictably
Web-first assertions return a promise. Without await, the test function may end before the retrying assertion completes, so failures are missed or reported as unhandled errors. The eslint rule no-floating-promises catches this.
27. Reusing one page for speed
To save time, a framework reuses one browser page for all tests in a file. Failures now depend on test order and memory grows. What is the better design?
- A.Restart the CI machine after each file
- B.Use a fresh browser context per test (cheap in Playwright), and speed up setup with saved auth state and API seeding instead
- C.Reuse one page for the entire suite
- D.Clear cookies with JavaScript between tests and keep the page
Show answer
Answer: B. Use a fresh browser context per test (cheap in Playwright), and speed up setup with saved auth state and API seeding instead
Browser contexts are lightweight, isolated profiles that start in milliseconds, so isolation costs little. The real time savings come from skipping UI login and setting up data through APIs.
28. Testing a 15-minute session timeout
The app logs users out after 15 minutes of inactivity and shows a warning at 14 minutes. How do you test this quickly and reliably?
- A.Wait 15 real minutes with page.waitForTimeout(900_000)
- B.Change the CI machine's system clock forward by 15 minutes during the test
- C.Install the Playwright clock (page.clock.install()) and fast-forward time in the test
- D.Skip the test, because time-based behaviour cannot be automated
Show answer
Answer: C. Install the Playwright clock (page.clock.install()) and fast-forward time in the test
page.clock lets you control Date, timers and intervals in the page: install it, then use fastForward or runFor to jump ahead and assert the warning and logout. Real waiting is slow, and changing the OS clock affects everything else on the machine.
29. Replaying recorded API traffic
A third-party pricing API used by the page is slow and rate-limited in test environments. You want realistic responses without calling it every run. Which Playwright feature fits?
- A.Disable JavaScript so that the page never calls the API
- B.Record the traffic to a HAR file once and replay it with page.routeFromHAR()
- C.Use ignoreHTTPSErrors so the API calls fail faster
- D.Increase the test timeout to 5 minutes to allow for rate limits
Show answer
Answer: B. Record the traffic to a HAR file once and replay it with page.routeFromHAR()
routeFromHAR serves matching requests from a recorded HAR, and with update: true it can refresh the recording. This gives stable, realistic data. The trade-off is that recordings get stale, so keep a separate contract or integration check against the real API.
30. A five-second assertion in a long test
The test timeout is 60 seconds, but this assertion fails after about 5 seconds even though the message appears after 8 seconds. Why?
await page.getByRole('button', { name: 'Generate' }).click()
await expect(page.getByText('Report ready')).toBeVisible()- A.The 60-second test timeout is split equally between all the steps in the test
- B.toBeVisible() never waits, so it fails right away when the text is missing
- C.expect has its own timeout, 5 seconds by default, apart from the test timeout
- D.Playwright stops waiting when the network is idle for 5 seconds
Show answer
Answer: C. expect has its own timeout, 5 seconds by default, apart from the test timeout
expect has its own timeout (default 5 s), configurable globally with expect: { timeout } or per call: toBeVisible({ timeout: 15_000 }). Raise it only where the app is known to be slow, rather than making every assertion wait longer.
31. A row that is not in the DOM
A table of 10,000 transactions uses virtual scrolling, so only about 30 rows exist in the DOM at a time. The test cannot find transaction TX-9876. What is the best approach?
- A.Increase the locator timeout to 2 minutes so that the row eventually loads
- B.Use the app's search or filter to bring it up, or scroll in steps until it renders
- C.Use page.evaluate() to read all 10,000 rows from the DOM at once
- D.Set the viewport height to 50,000 pixels so that every single row renders
Show answer
Answer: B. Use the app's search or filter to bring it up, or scroll in steps until it renders
Virtualised lists render only visible rows, so a far-off row simply does not exist yet; waiting longer will not create it. Narrowing the data via search or filter is the most reliable, and scrolling with a bounded loop is a fallback.
32. A variable that is undefined in evaluate
Why does this code throw "orderId is not defined"?
const orderId = 'ORD-77'
const status = await page.evaluate(() => {
return window.app.getStatus(orderId)
})- A.page.evaluate only accepts functions that take no data at all
- B.orderId must be declared with var instead of const to be visible
- C.window.app is not available until the test calls page.reload()
- D.The function runs inside the page, so test variables must be passed as an argument
Show answer
Answer: D. The function runs inside the page, so test variables must be passed as an argument
Playwright serialises the function and runs it in the browser, where test-side closures do not exist. Pass data explicitly: page.evaluate((id) => window.app.getStatus(id), orderId). Only serialisable values can be passed in and returned.
33. A click that does nothing
A server-rendered Next.js page shows the "Add to cart" button instantly. Playwright clicks it within milliseconds of load and sometimes nothing happens. Manual users never see this. What is the likely cause and best fix?
- A.The click lands before hydration adds handlers; wait for a ready signal first
- B.The button is covered by an overlay; use click({ force: true }) instead
- C.Playwright clicks too slowly; reduce the action timeout to 100 ms for this button
- D.The browser cache is stale; clear the cache before each test
Show answer
Answer: A. The click lands before hydration adds handlers; wait for a ready signal first
Server-rendered HTML looks ready before JavaScript has hydrated it, so early clicks are lost. Humans are slower, so they rarely notice. A reliable fix is a readiness marker the app sets after hydration, or asserting the result with a retry, rather than adding fixed waits.
34. Simulating a slow network everywhere
The team wants to check that loading skeletons show on slow networks in Chromium, Firefox and WebKit using Playwright. Why is CDP-based throttling a poor fit, and what works?
- A.CDP throttling works in all browsers, but it is too slow to use in CI pipelines
- B.CDP throttling is Chromium-only; delaying responses in page.route works in all browsers
- C.Throttling is impossible in tests, so skeleton screens must be tested manually
- D.Setting offline: true in the context gives the same effect as a slow network
Show answer
Answer: B. CDP throttling is Chromium-only; delaying responses in page.route works in all browsers
Network emulation via a CDP session exists only in Chromium. Adding a delay inside a route handler before route.continue() or fulfill() slows chosen requests in every browser, which is enough to see loading states. offline simply fails the requests.
35. Moving off a flaky Selenium suite
A Java team has 1,500 Selenium tests on a Grid, with a 12% flaky rate. Leadership wants to "switch to Playwright". What is the most sensible plan?
- A.Rewrite all 1,500 tests in Playwright TypeScript over one sprint
- B.Switch to Cypress, since it supports Java and multi-tab flows well
- C.Keep everything as is, and turn on three automatic retries
- D.Find flake causes, pilot Playwright for Java on a flaky area, and compare
Show answer
Answer: D. Find flake causes, pilot Playwright for Java on a flaky area, and compare
Flakiness often comes from waits, data and environments, which a new tool alone will not fix. A pilot gives real evidence on stability and speed, and Playwright for Java lets the team keep its language. Big-bang rewrites are risky, and retries only hide problems.