Skip to content
SDETRole
SDETRole

Practice / Playwright

Playwright Practice Lab

Locators are where most Playwright tests succeed or fail, and a test is only as good as the bugs it catches. Write locators against real HTML pages, then run full Playwright tests against a live demo app: they must pass on the working app and fail on versions with planted bugs.

Challenges
22
Beginner
5
Intermediate
11
Advanced
6
Solved
0

Challenges

  1. 01 Find the Sign in button by role Use getByRole with an accessible name to target the login form's Sign in button when several other buttons also say Sign in.
  2. 02 Pick the right heading level Target a level 2 Shipping heading on a checkout page where Shipping also appears in an h3, a footer h2 and a paragraph styled as a title.
  3. 03 Locate inputs by their label Use getByLabel to find the Password field of a sign-up form whose labels mix for= and wrapping styles, next to a Confirm password field.
  4. 04 Exact versus substring text Locate the editor's Saved status indicator with getByText when saved also appears in a heading, a list item and a paragraph.
  5. 05 Filter product cards by text Combine getByTestId, filter({ hasText }) and getByRole to click Add to cart on one product card in a grid of near-identical cards.
  6. 06 Click a button in a table row Scope to the table row for Order #1042, then find its Refund button. Chaining locators is how you handle repeated row actions.
  7. 07 Reach into a payment iframe Locate the Card number field inside an embedded payment iframe with frameLocator. A page-level getByLabel finds the gift card field instead.
  8. 08 XPath where CSS cannot reach Select the price of the Pro plan by its heading text with an XPath sibling axis, something a CSS selector cannot express.
  9. 09 Replace manual checks with web-first assertions Rewrite a test that checks isVisible() inside an if, which can pass without asserting anything, using auto-retrying expect assertions.
  10. 10 Wait for the API, not the clock Replace a fixed waitForTimeout with page.waitForResponse registered before the click, then assert the results with web-first expect.
  11. 11 Handle a link that opens a new tab Capture the new tab opened by a target=_blank link with waitForEvent('popup'), then assert on the new page instead of the original one.
  12. 12 Mock an API with page.route Use page.route and route.fulfill to return an empty list and a 500 error from the products API, so empty and error states are testable on demand.
  13. 13 Move setup into a custom fixture Replace shared mutable state and beforeEach/afterEach hooks with a test.extend fixture that provides a ready CartPage and cleans up after use().
  14. 14 Log in once with storageState Stop logging in through the UI before every test: authenticate once in a setup project, save storageState, and reuse it via project dependencies.
  15. 15 Fix a flaky cart test A cart test passes locally and fails on a slow CI agent. Replace fixed sleeps and a one-time text read with assertions that wait for the real condition.
  16. 16 Write tests that catch the login bugs The sign-in page has three planted bugs. Write Playwright tests that pass on the working app and fail on every buggy version.
  17. 17 Write tests that catch the cart bugs The cart has three planted bugs: quantities, coupon codes and clearing. Write UI tests that pass on the working cart and fail on every buggy version.
  18. 18 Write tests that catch the search bugs Product search has three planted bugs. Write tests that check matching, case-insensitivity and the empty state, and fail on every buggy version.
  19. 19 Test the cart API with the request fixture Use Playwright's request fixture to check the cart API contract: status codes, response bodies and error handling. Three planted API bugs must fail.
  20. 20 Test the login and profile API contract Check the login and profile endpoints with the request fixture: successful and failed sign-in, the response shape and input validation. Three API bugs must fail.
  21. 21 Write tests that catch the profile bugs The profile settings page has three planted bugs, and the existing test checks only the success toast. Write Playwright tests that pass on the working app and fail on every buggy version.
  22. 22 Write tests that catch the order and invoice bugs The order details page and its invoice tab have four planted bugs. Write Playwright tests that check the line items, the totals and the invoice in its new tab.

Two kinds of Playwright challenge

Most Playwright practice stops at reading the docs. This lab has two kinds of exercise that check real work. Locator challenges give you an HTML page and a target element: you write the locator, and the lab shows exactly which elements it resolves to, so an ambiguous getByText or a locator that also matches a hidden duplicate fails visibly. Test challenges give you a demo shop and a task such as "test the login form" or "fix this flaky cart test": your spec runs against the working app, against a slow API, and against versions with planted bugs.

A test challenge only passes when your spec passes on the working app and fails on every buggy version. That is mutation testing in miniature, and it rewards the skill that matters on the job: writing tests that catch regressions, not tests that merely go green.

Locator practice: why getByRole comes first

Compare page.locator('.btn-primary') with page.getByRole('button', { name: 'Place order' }). The CSS version breaks when a designer renames a class and can match several buttons; the role version describes what the user sees, survives styling changes and fails if the accessible name disappears, which is itself an accessibility bug. Work through role and accessible name, labels, exact text, test ids with filters, chaining inside a table row and frames in that order.

Assertions, waits and debugging exercises

Playwright auto-waits before actions: click() waits until the element is attached, visible, stable, enabled and receives events. Assertions are a separate mechanism. await expect(locator).toHaveText('Paid') retries until the text matches or the timeout expires, while expect(await locator.textContent()).toBe('Paid') reads the text once and fails if the page is a few milliseconds slow. The web-first assertions and wait for a response challenges train this difference.

The debugging exercises go further. In fix the flaky cart test the spec passes on a fast app and fails on the slow-API scenario, so you have to find the race rather than add a waitForTimeout. The "catch the bugs" challenges for login, cart, search, profile and orders ask you to decide what to assert, which is the hardest part of test design.

What the lab can and cannot check

Locators are resolved by SDETRole's locator engine, which implements a documented subset of Playwright's locator semantics against a real DOM. Test specs run on a Playwright-compatible runtime in a sandboxed worker, not on Playwright itself, and the demo app's network is simulated, so browser-specific behaviour and the full API surface are out of scope. The storageState challenge is still checked by pattern rules. Everything you write uses standard Playwright syntax, so it carries over to a real project unchanged.

Where this fits in interview preparation

Interviewers ask about locator strategy, auto-waiting, fixtures, network mocking and flaky tests, and they often follow up with "show me". After a few challenges, answer the Playwright interview questions in your own words, then test yourself under time pressure in a mock interview.

Frequently asked questions

What is Playwright in automation testing?

Playwright is an open-source framework from Microsoft for end-to-end testing of web applications. One API drives Chromium, Firefox and WebKit, and its test runner (@playwright/test) adds auto-waiting, web-first assertions, parallel execution, fixtures, network mocking, tracing and an HTML report. It supports JavaScript/TypeScript, Python, Java and .NET. Teams use it for UI tests and, through its built-in request context, for API tests that share the same runner and reports.

How can I practise Playwright online?

Use this lab. Locator challenges ask you to find elements on a page fixture with getByRole, getByLabel and other locators. Test challenges run your Playwright spec against a demo app: once on the working version, once with a slow API and once per version with a planted bug. Start with getByRole, move on to web-first assertions, then try the “catch the bugs” challenges. Nothing needs installing.

What are the most important Playwright interview topics?

Interviewers focus on locator strategy and why role-based locators are preferred; auto-waiting and web-first assertions; browser, context and page; fixtures; authentication with storageState; network mocking with page.route; parallelism and sharding; and debugging flaky tests with the trace viewer. Be ready to compare Playwright with Selenium and Cypress, and to explain how you structured a real suite. The Playwright interview questions cover each topic with code.

What are Playwright locators?

A locator is Playwright's way of finding elements. It is lazy: it describes how to find an element and is re-evaluated every time you act or assert, so it survives re-renders. Recommended locators reflect what users see, such as page.getByRole('button', { name: 'Sign in' }), getByLabel, getByPlaceholder and getByText, with getByTestId for elements without an accessible name. Locators are strict: an action fails if more than one element matches. See the Playwright locators lesson.

What is the difference between getByRole and locator?

page.locator() takes a CSS or XPath selector, such as page.locator('#submit'), so it is tied to the page's markup. page.getByRole() finds elements by ARIA role and accessible name, the way assistive technology sees them: page.getByRole('button', { name: 'Submit' }). Role-based locators survive class and structure changes and expose accessibility problems, so they are the recommended default. Use locator() for chaining, filtering or when no user-facing attribute exists. The Playwright cheat sheet lists both.

How does auto-waiting work in Playwright?

Before an action, Playwright waits until the element is actionable. Before click(), for example, it must be attached, visible, stable (not animating), able to receive events and enabled. Web-first assertions such as await expect(locator).toHaveText('Saved') retry until they pass or time out (5 seconds by default). This removes most manual sleeps, but it does not wait for your app's business logic, so assert on the state you need instead of adding waitForTimeout. More in auto-waiting explained.

How do I handle flaky tests in Playwright?

Find the cause first. Re-run the test with --repeat-each and record a trace (--trace on) to see the page at the moment of failure. Common fixes: replace waitForTimeout with web-first assertions, wait for the specific network response, isolate test data so parallel tests don't collide, and use stable role-based locators. Configure retries in CI to keep the pipeline moving, but track retried tests and fix them. Practise on the fix the flaky cart test challenge.

Can I run Playwright tests in a browser-based practice environment?

Yes, in this lab. Your specs run in a sandboxed worker on a Playwright-compatible runtime against a demo app in a real DOM, so you need no Node.js, browsers or npm packages. It implements a subset of the Playwright API rather than Playwright itself, and the demo app's network is simulated. The syntax is standard, so the code you write here works in a real project. To run the same tests locally, follow the Playwright getting-started lesson.

How are "catch the bugs" challenges graded?

Your spec must pass on the working app and fail on each version with a planted bug. A test that passes everywhere is not checking enough; a test that fails on the working app is wrong.

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →