Skip to content

Easy Playwright Testing Interview Questions

113 easy questions with answers. Definitions and fundamentals every candidate must answer quickly and correctly.

Topics in the easy set

Playwright Core: 20 JavaScript and TypeScript: 14 Locators and Assertions: 12 Debugging and Trace Viewer: 10 Fixtures and Hooks: 9 Visual & Accessibility Testing: 9 Parallel Runs, Sharding & Reporting: 9 API Testing: 8 Framework Design and CI/CD: 8
Solved — easyStart 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 install and start a Playwright project?

Save to ▾
Show answer
Run npm init playwright@latest, which sets up config, example tests and browsers; execute with npx playwright test.
02

What is the difference between API testing and UI testing?

Save to ▾
Show answer
API testing checks services directly and is fast and stable; UI testing checks the full user experience in the browser and is slower.
03

let vs const vs var?

Save to ▾
Show answer
var is function-scoped and hoisted. let and const are block-scoped; const can't be reassigned (though an object it points to can change). Prefer const, then let.
04

What is async/await?

Save to ▾
Show answer
Syntax over Promises: an async function returns a Promise and await pauses until it resolves. Every Playwright action returns a Promise, so you await each step.
05

Write a test that logs in and checks the dashboard heading.

Save to ▾
Show answer
test('login', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('a@b.com'); await page.getByLabel('Password').fill('secret'); await page.getByRole('button', { name: 'Login' }).click(); await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); });
06

How do you run tests on three browsers in parallel?

Save to ▾
Show answer
Define projects for chromium, firefox and webkit in playwright.config.ts, set workers, then run: npx playwright test
07

How do you run only smoke tests?

Save to ▾
Show answer
Tag tests (in the title or with { tag: '@smoke' }) and run: npx playwright test --grep @smoke (use --grep-invert to exclude).
08

What is auto-waiting in Playwright?

Save to ▾
Show answer
Before acting, Playwright waits for the element to be attached, visible, stable, enabled and able to receive events — so manual waits are rarely needed.
09

What is Playwright and which browsers does it support?

Save to ▾
Show answer
An open-source end-to-end testing framework from Microsoft that automates Chromium, Firefox and WebKit through one API, in multiple languages.
10

What is npm and package.json?

Save to ▾
Show answer
npm is the Node package manager. package.json lists the project's dependencies and scripts, such as the command that runs the tests.
11

How do you handle errors in async code?

Save to ▾
Show answer
Use try-catch with await, or .catch() on promises, and make sure rejected promises are never left unhandled.
12

Locator vs ElementHandle?

Save to ▾
Show answer
A Locator is lazy, re-resolved on every action and auto-waits (recommended). An ElementHandle points to one DOM node and can go stale.
13

How do you write a Page Object in Playwright?

Save to ▾
Show answer
A class receives page in its constructor, stores locators as properties and exposes actions like login(user, pass). Tests call page objects, not raw locators.
14

How do you work with iframes?

Save to ▾
Show answer
const frame = page.frameLocator('#payment-frame'); await frame.getByLabel('Card number').fill('4111 1111 1111 1111');
15

What are the main data types in JavaScript?

Save to ▾
Show answer
string, number, boolean, null, undefined, symbol, bigint and object (including arrays and functions).
16

How do you handle a new tab?

Save to ▾
Show answer
const [newPage] = await Promise.all([ context.waitForEvent('page'), page.getByText('Open').click(), ]); await newPage.waitForLoadState();
17

How do you make an API request in Playwright?

Save to ▾
Show answer
Use the request fixture: const res = await request.get('/api/users'); expect(res.ok()).toBeTruthy(); const body = await res.json();
18

What is a locator in Playwright?

Save to ▾
Show answer
An object describing how to find an element, re-evaluated on every action so it always targets the current DOM.
19

What is the difference between TypeScript and JavaScript?

Save to ▾
Show answer
TypeScript adds static types on top of JavaScript and compiles to it. Types catch errors early and give better autocomplete, which helps in larger test suites.
20

How do you run a single test or file in Playwright?

Save to ▾
Show answer
npx playwright test tests/login.spec.ts, add -g "test title" to match a name, or use test.only while debugging.
21

What are arrow functions?

Save to ▾
Show answer
A short function syntax that does not have its own this and arguments, taking them from the surrounding scope.
22

What does getByRole do and why is it the first-choice locator?

Save to ▾
Show answer
getByRole finds elements by their ARIA role and accessible name, the same way screen readers and users see the page. For example getByRole('button', { name: 'Save' }) keeps working when CSS classes or DOM structure change. It also pushes the team towards accessible markup. The trade-off is that badly built components without proper roles may need a test id instead.
23

What is the difference between getByText and getByLabel?

Save to ▾
Show answer
getByText matches visible text anywhere on the page, so it suits paragraphs, links and messages. getByLabel finds a form control through its associated label element, aria-label or aria-labelledby, so it is the right choice for inputs such as Email or Password. Using getByLabel for inputs also checks that labels are wired correctly, which getByText cannot do.
24

When should you use getByTestId?

Save to ▾
Show answer
Use getByTestId when no user-facing locator is stable or unique, for example icon-only buttons, dynamic grids or canvas wrappers. It matches the data-testid attribute by default, and you can change the attribute name with testIdAttribute in the config. Test ids are very stable but users never see them, so prefer role, label or text first and keep test ids as a fallback.
25

What is the difference between toHaveText and toContainText?

Save to ▾
Show answer
toHaveText checks that the element's full text matches the expected string or regex, after normalising whitespace. toContainText passes if the expected text appears anywhere inside it. Use toHaveText for exact labels like a heading, and toContainText for longer messages where only part matters. Both are web-first assertions, so they retry until the timeout before failing.
26

How is toBeVisible different from toBeAttached?

Save to ▾
Show answer
toBeAttached only checks that the element exists in the DOM. toBeVisible also needs it to have a non-empty bounding box and no visibility:hidden style. A hidden modal can be attached but not visible. Use toBeVisible for anything a user should see, and toBeAttached for hidden inputs or elements whose presence matters more than appearance.
27

How do you assert the number of rows in a table?

Save to ▾
Show answer
// waits until exactly 5 data rows are rendered const rows = page.getByRole('table').getByRole('row'); await expect(rows).toHaveCount(6); // 1 header + 5 rows // avoid: expect(await rows.count()).toBe(6) // that reads once and does not retry
28

Write code to fill a login form using label-based locators.

Save to ▾
Show answer
test('login form', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('user@test.in'); await page.getByLabel('Password').fill('Pass@123'); await page.getByRole('button', { name: 'Sign in' }).click(); await expect(page).toHaveURL(/dashboard/); });
29

How do you change the default assertion timeout?

Save to ▾
Show answer
Web-first assertions wait 5 seconds by default. Change it globally in playwright.config with expect: { timeout: 10000 }, or for one assertion with await expect(locator).toBeVisible({ timeout: 15000 }). Raise it only for genuinely slow steps like report generation. Raising it everywhere hides performance problems and makes failing tests slower to report.
30

What is the difference between await expect(locator) and a plain expect on a value?

Save to ▾
Show answer
await expect(locator).toHaveText('Paid') is a web-first assertion: it retries until the element matches or the timeout ends. expect(value).toBe('Paid') is a generic assertion that checks a value once, immediately. Use web-first assertions for anything on the page and generic ones for plain data such as an API JSON field you already have.
31

Tell me about a time you replaced brittle locators in an existing suite.

Save to ▾
Show answer
Situation: a suite I joined used long XPath selectors and about ten tests broke after every UI release. Task: make them stable. Action: I rewrote the locators with getByRole and getByLabel, added test ids for two custom grids and moved everything into page objects. Result: locator-related failures dropped to almost zero over the next three releases.
32

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

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

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

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

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

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

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(); } });
39

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

What does page.route do?

Save to ▾
Show answer
page.route registers a handler for requests whose URL matches a pattern. Inside the handler you can let the request continue, change it, return a fake response or abort it. It lets you test the UI against controlled data without depending on a real backend. Register routes before the action that triggers the request, usually before page.goto.
41

What is the difference between route.fulfill, route.continue and route.abort?

Save to ▾
Show answer
route.fulfill returns a response you define, such as a status, headers and JSON body, without contacting the server. route.continue sends the request on, optionally with changed URL, method, headers or body. route.abort fails the request with a network error such as 'failed' or 'blockedbyclient'. route.fallback passes it to the next matching handler.
42

How do you block images and fonts to speed up tests?

Save to ▾
Show answer
await page.route(/\.(png|jpe?g|webp|woff2?)$/, route => route.abort()); // or by resource type await page.route('**/*', route => route.request().resourceType() === 'image' ? route.abort() : route.continue() );
43

Why mock the network in UI tests at all?

Save to ▾
Show answer
Mocking makes tests fast, stable and independent of backend data or third-party outages. It also lets you test states that are hard to create for real, such as empty lists, errors or huge responses. The trade-off is lower confidence that frontend and backend work together, so keep some unmocked end-to-end tests for critical journeys.
44

Describe a time you argued against mocking every API in the suite.

Save to ▾
Show answer
Situation: a teammate proposed mocking all APIs to make the suite fast. Task: keep speed without losing integration coverage. Action: I showed two recent bugs caused by API changes that mocks would have hidden and proposed mocking only third parties and error states, keeping ten real end-to-end journeys. Result: the team agreed and the next contract change was caught before release.
45

What is a HAR file?

Save to ▾
Show answer
HAR stands for HTTP Archive. It is a JSON file that records the requests and responses a browser made, including URLs, headers, bodies and timings. Browsers can export one from DevTools, and Playwright can record and replay them. In testing it is used for mocking whole sets of API calls and for sharing network evidence in bug reports.
46

What is the Playwright Inspector and how do you open it?

Save to ▾
Show answer
The Inspector is a debug window that lets you step through test actions one by one, see the locator being used and highlight it on the page. Open it with npx playwright test --debug, with PWDEBUG=1, or by calling page.pause(). It runs headed with no timeout, so you can explore the page at each step and edit locators live.
47

What does page.pause() do?

Save to ▾
Show answer
page.pause() stops the test at that line and opens the Inspector, as long as the test is running headed. You can then inspect the page, try locators and resume or step forward. It is useful for checking the state just before a failing step. Remove it before committing, because it would hang a headless CI run.
48

How do you open a trace file?

Save to ▾
Show answer
Download trace.zip from the test results or CI artifact. Run npx playwright show-trace path/to/trace.zip to open it locally, or drag the file into trace.playwright.dev, which processes it in the browser without uploading it. In the HTML report, failed tests with a trace show a trace link you can click directly.
49

What do headed mode and slowMo do?

Save to ▾
Show answer
--headed shows the browser window instead of running headless, so you can watch the test. slowMo, set in launchOptions, adds a delay in milliseconds before every action, which makes fast steps visible. Both help when you are writing or debugging a test. Do not leave slowMo on in CI, because it slows every action.
50

What is the HTML report and how do you open it?

Save to ▾
Show answer
The HTML reporter creates a playwright-report folder with every test, its steps, errors, attachments, screenshots and trace links. Open it with npx playwright show-report. You can filter by status, project and tags. In CI, upload the folder as an artifact so anyone can download and open it, and the report opens automatically locally when tests fail.
51

What does the Pick locator tool do?

Save to ▾
Show answer
In the Inspector, UI mode and the VS Code extension, Pick locator lets you hover over any element on the page and see the locator Playwright recommends for it, usually a role or label based one. You can copy it into your test. It is a fast way to write locators and to check whether an existing one is unique.
52

What does npx playwright test --last-failed do?

Save to ▾
Show answer
It reruns only the tests that failed in the previous run, using the results stored in the test-results folder. It saves time while you fix failures locally because you do not rerun the whole suite. Combine it with --headed or --debug to investigate. Run the full suite again before pushing to confirm nothing else broke.
53

Tell me about a hard bug you found while debugging a test.

Save to ▾
Show answer
Situation: a search test failed about once in ten runs. Task: find the cause. Action: I ran it with --repeat-each and traces, and saw two search requests return out of order, so the older result replaced the newer one. Result: I proved it was a real race condition in the app, developers fixed it with request cancellation, and the test became stable.
54

What is the difference between the request fixture and request.newContext()?

Save to ▾
Show answer
The request fixture is a ready APIRequestContext that uses the config's baseURL and extraHTTPHeaders and is cleaned up automatically per test. playwright.request.newContext() creates your own context with custom settings, such as a different base URL or auth token, for example in a worker fixture. You must dispose a manually created context yourself.
55

What does response.ok() check?

Save to ▾
Show answer
response.ok() returns true when the status code is in the 200 to 299 range. It is a quick success check but not enough on its own. Also assert the exact status, such as 201 for a create, and the body content. For a negative test, assert the specific error status like 400 or 404 and the error message.
56

How do you send query parameters in an API request?

Save to ▾
Show answer
// GET /api/products?category=books&page=2 const res = await request.get('/api/products', { params: { category: 'books', page: 2 }, }); expect(res.ok()).toBeTruthy(); const body = await res.json(); expect(body.items.length).toBeGreaterThan(0);
57

What are idempotent HTTP methods and why do they matter in testing?

Save to ▾
Show answer
An idempotent method gives the same result when repeated. GET, PUT and DELETE are idempotent, POST is not. This matters for retries: a retried PUT is safe, but a retried POST may create duplicates. Test that repeating a PUT leaves one updated record and that repeating DELETE returns a sensible status such as 404 or 204.
58

What is the difference between path parameters and query parameters?

Save to ▾
Show answer
Path parameters identify a specific resource and are part of the URL path, like /users/42. Query parameters filter, sort or paginate and follow a question mark, like /users?city=Delhi&page=2. In tests, check invalid path ids return 404, and that each query parameter changes results correctly, including invalid and missing values.
59

Describe a time an API changed without notice and broke your tests.

Save to ▾
Show answer
Situation: dozens of tests failed after a field was renamed from user_name to username. Task: fix quickly and prevent repeats. Action: I updated the shared types and helper, so the fix touched two files, and proposed schema checks on key endpoints plus a heads-up in release notes. Result: the next breaking change was caught in the pull request.
60

What is a browser context and why is it cheap?

Save to ▾
Show answer
A browser context is an isolated session inside one browser, like a fresh incognito profile with its own cookies, storage and cache. Creating one takes milliseconds, unlike launching a new browser. Playwright gives every test a new context, so tests do not leak state into each other, and you can open several contexts to simulate different users.
61

What does the waitUntil option of page.goto do?

Save to ▾
Show answer
waitUntil decides when goto considers navigation finished: 'load' waits for the load event and is the default, 'domcontentloaded' waits only for the HTML to parse, 'networkidle' waits for no network for 500 ms, and 'commit' returns when the response starts. Avoid networkidle, which is discouraged and flaky; use assertions on the content you need instead.
62

What is the difference between @playwright/test and the playwright package?

Save to ▾
Show answer
@playwright/test is the test runner with fixtures, assertions, parallel workers, retries, reports and config. The playwright package is the automation library alone, used for scripts like scraping or generating PDFs, where you launch browsers yourself. For testing, install @playwright/test. Both share the same browser automation API underneath.
63

How do you select an option from a native select dropdown?

Save to ▾
Show answer
const country = page.getByLabel('Country'); await country.selectOption('India'); // by value or label await country.selectOption({ label: 'India' }); await expect(country).toHaveValue('IN'); // multi-select: selectOption(['a', 'b'])
64

What does the channel option do?

Save to ▾
Show answer
By default Playwright uses its own bundled Chromium, Firefox and WebKit builds. Setting channel: 'chrome' or 'msedge' in a project runs tests in the installed branded Chrome or Edge browser instead. This is useful when you must test on the exact browser users run, for example for codecs or policies. Install with npx playwright install chrome.
65

How do you check a checkbox and verify it is checked?

Save to ▾
Show answer
const terms = page.getByRole('checkbox', { name: 'I agree to the terms' }); await terms.check(); await expect(terms).toBeChecked(); await terms.uncheck(); await expect(terms).not.toBeChecked(); // setChecked(true) works for both cases
66

How do you emulate a mobile device in Playwright?

Save to ▾
Show answer
Import devices from @playwright/test and spread a profile into a project or test.use, for example use: { ...devices['Pixel 7'] }. This sets viewport, user agent, device scale factor, touch support and isMobile. It emulates the browser, not a real phone, so it is good for responsive layout tests but not a replacement for real-device testing.
67

Why did you choose to build a career in Playwright automation?

Save to ▾
Show answer
I like that automation combines coding with product quality. I learned Selenium first, then moved to Playwright because auto-waiting, tracing and API support let me write stable tests faster. In my college project I automated twenty flows with TypeScript and a CI pipeline. I want a role where I can grow into framework design and CI ownership.
68

What is the difference between == and === in JavaScript?

Save to ▾
Show answer
=== compares value and type without conversion, so '5' === 5 is false. == converts types first, so '5' == 5 is true and null == undefined is true. Implicit conversion causes surprising bugs, so test code should always use === and !==. TypeScript and lint rules such as eqeqeq help enforce this.
69

What is a Promise and what states can it have?

Save to ▾
Show answer
A Promise represents a value that will be available later, such as an API response. It is pending at first, then either fulfilled with a value or rejected with an error, and it never changes after that. You consume it with await or then and catch. Almost every Playwright call returns a Promise, which is why tests use await so much.
70

What is the difference between ES modules and CommonJS?

Save to ▾
Show answer
ES modules use import and export and are the modern standard, loaded statically. CommonJS uses require and module.exports and is the older Node.js style. Playwright supports both, and TypeScript test projects usually write import syntax. Mixing them causes errors such as require is not defined, so set type in package.json and tsconfig consistently.
71

How do you read test data from a JSON file and loop over it?

Save to ▾
Show answer
import users from './data/users.json'; for (const u of users) { test(`login as ${u.role}`, async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill(u.email); await page.getByLabel('Password').fill(u.password); await page.getByRole('button', { name: 'Sign in' }).click(); }); }
72

What does the nullish coalescing operator do?

Save to ▾
Show answer
a ?? b returns b only when a is null or undefined. Unlike ||, it keeps valid falsy values such as 0, false and an empty string. In config this matters: process.env.RETRIES ?? '2' keeps a value of 0 if someone sets it, whereas || would wrongly replace it. It is often combined with optional chaining.
73

Tell me how you learned TypeScript quickly for a project.

Save to ▾
Show answer
Situation: I joined a team whose Playwright suite was in TypeScript while I knew only basic JavaScript. Task: become productive in two weeks. Action: I studied types, interfaces and generics in the evenings, read the team's page objects, and fixed small compiler errors as practice. Result: by week three I was writing new tests and reviewing simple pull requests.
74

What are the key options in playwright.config.ts?

Save to ▾
Show answer
Main options are testDir for where tests live, timeout, retries, workers, fullyParallel, reporter, and the use block for shared settings like baseURL, trace, screenshot and video. projects define browsers or setups, and webServer can start the app before tests. Most values can depend on process.env.CI so local and CI runs behave differently.
75

What is forbidOnly and why use it in CI?

Save to ▾
Show answer
test.only runs only that test and is handy locally, but if committed by mistake, CI would run one test and report success. forbidOnly: !!process.env.CI makes the run fail when any test.only is present on CI. It is a cheap safety net that most generated configs already include, and it should stay on.
76

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

What is the use block in playwright.config?

Save to ▾
Show answer
The use block sets default options for every test, such as baseURL, headless, viewport, locale, trace, screenshot and video. Each project can override them in its own use block, and a file can override again with test.use. This layered setup keeps shared settings in one place while still allowing browser- or file-specific changes.
78

What happens the first time toHaveScreenshot runs and no baseline image exists?

Save to ▾
Show answer
Playwright cannot compare anything, so it captures the screenshot, saves it as the new baseline in the snapshots folder and marks the test as failed with a message that the snapshot was missing. On the next run the test compares against that file. This is why you review new baselines before committing them, and why baselines should be generated in the same environment that CI uses.
79

What is the difference between toHaveScreenshot and toMatchSnapshot?

Save to ▾
Show answer
toHaveScreenshot is for images of a page or locator. It waits for the page to become visually stable, retries the capture until two shots match, and supports options like mask and animations. toMatchSnapshot compares any value you pass in, such as a string, a buffer or text output, against a stored file, without waiting or retrying. Use toHaveScreenshot for UI and toMatchSnapshot for generated text or file content.
80

Why should CSS animations be disabled for visual comparisons?

Save to ▾
Show answer
An animation captured at a slightly different frame produces a different image, so the test fails even though nothing is broken. With animations: 'disabled', which is the default for toHaveScreenshot, Playwright fast-forwards finite animations to their end state and resets infinite ones to their start. This gives the same picture every run. Transitions triggered by hover or focus are handled the same way.
81

Where does Playwright store baseline screenshots and how are the files named?

Save to ▾
Show answer
By default baselines go into a folder next to the test file named after it, for example checkout.spec.ts-snapshots. The file name combines the name you give, the project name and the platform, such as home-chromium-linux.png. Because the browser and operating system are part of the name, each project keeps its own baseline. You commit these images to the repository so every run compares against the same files.
82

How do you update screenshot baselines after an intended UI change?

Save to ▾
Show answer
Run the tests with npx playwright test --update-snapshots, optionally filtered to the affected files or a tag. Playwright rewrites the baselines with the new images. Newer versions also accept modes such as --update-snapshots=changed or missing so only the needed files are touched. Always look at the diff in the pull request before merging, because blindly updating hides real regressions.
83

Write a test that compares only the pricing card instead of the full page.

Save to ▾
Show answer
test('pricing card looks right', async ({ page }) => { await page.goto('/pricing'); const card = page.getByRole('region', { name: 'Pro plan' }); // screenshot is clipped to the element await expect(card).toHaveScreenshot('pro-plan.png'); });
84

How do you check colour contrast in Playwright tests?

Save to ▾
Show answer
Playwright has no built-in contrast assertion, so you run axe-core through @axe-core/playwright, whose color-contrast rule checks text against WCAG ratios such as 4.5 to 1 for normal text. Scan pages in each theme, for example after emulating dark mode with colorScheme. Axe may report some elements as needing review, for example text over images, and those need a manual look.
85

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

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

What is the difference between page.goto and page.waitForURL?

Save to ▾
Show answer
page.goto starts a navigation to a URL and waits for the load state you choose. page.waitForURL does not navigate; it waits until the current page reaches a URL that matches a string, glob or regular expression, which is useful after a click that redirects, such as a login followed by a jump to the dashboard. Pair it with the click instead of adding fixed sleeps.
88

How do you test a site protected by HTTP basic authentication?

Save to ▾
Show answer
Set httpCredentials with a username and password in the use block of the config, or pass it to browser.newContext. Playwright then answers the browser's authentication challenge automatically, so no pop-up appears. Read the values from environment variables rather than hard-coding them. You can also limit the credentials to a specific origin with the origin field.
89

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

Tell me about the first time you used the trace viewer to solve a failure.

Save to ▾
Show answer
Situation: during my internship a login test failed only in CI and I could not reproduce it. Task: find the cause. Action: I enabled trace on first retry, downloaded the trace and stepped through the actions, and saw a cookie banner covering the sign-in button in the CI viewport. Result: I added a step to accept the banner, the test became stable, and I shared the method with my team.
91

What is Playwright component testing?

Save to ▾
Show answer
Component testing mounts a single UI component, such as a React or Vue button or form, in a real browser page and tests it with the normal Playwright API. Playwright bundles the component with Vite, serves it on a small page and gives you a mount fixture. You get real browser rendering and events, which unit tests in jsdom cannot give, while staying much faster than full end-to-end flows. The feature is still marked experimental.
92

How do you set up Playwright component testing in an existing React project?

Save to ▾
Show answer
Run npm init playwright@latest -- --ct and choose React. It installs @playwright/experimental-ct-react, creates playwright-ct.config.ts and adds a playwright folder containing index.html and index.tsx. index.html hosts the mounted component and index.tsx is where global styles, themes and providers go. Tests then live in files such as Button.spec.tsx and run with npx playwright test -c playwright-ct.config.ts.
93

Write a component test for a Counter that increments on click.

Save to ▾
Show answer
import { test, expect } from '@playwright/experimental-ct-react'; import { Counter } from './Counter'; test('increments on click', async ({ mount }) => { const component = await mount(<Counter initial={2} />); await component.getByRole('button', { name: 'Add' }).click(); await expect(component.getByTestId('count')).toHaveText('3'); });
94

What does the mount fixture return?

Save to ▾
Show answer
mount renders the component into the test page and returns a locator pointing at the component root. You can call getByRole, click, and use web-first assertions on it like any locator. It also has helpers: update to re-render with new props or children, and unmount to remove it. Because it is a locator, the auto-waiting and retry behaviour of end-to-end tests applies here too.
95

How is a component test different from an end-to-end test?

Save to ▾
Show answer
An end-to-end test opens the full deployed app, logs in and goes through pages backed by a real server. A component test mounts one component in isolation with props you control, so there is no backend, routing or login. Component tests are faster and pinpoint the failing piece, while end-to-end tests prove the parts work together. A healthy suite has many component tests and fewer end-to-end journeys.
96

Which frameworks does Playwright component testing support?

Save to ▾
Show answer
Official packages exist for React, Vue and Svelte, named like @playwright/experimental-ct-react and @playwright/experimental-ct-vue. Each package provides the mount fixture and hooks in the style of its framework, such as slots and events for Vue. Support has changed between versions and the feature is experimental, so check the current docs and pin the package version alongside @playwright/test.
97

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

Why are component tests usually faster than end-to-end tests?

Save to ▾
Show answer
They skip the expensive parts: no full app start, no backend calls, no login and no navigation through several pages. Playwright builds the component bundle once and each test simply mounts into an already loaded page. A typical component test finishes in well under a second, so hundreds can run in a pull request check, while end-to-end flows take several seconds each.
99

Tell me about a time you explained a failing test report to a non-technical stakeholder.

Save to ▾
Show answer
Situation: a product manager saw a red build and wanted to delay the release. Task: explain what actually failed. Action: I opened the HTML report, grouped failures into one real bug in the coupon flow and two flaky tests, and showed the screenshot of the real bug in plain words. Result: we shipped after the coupon fix, and the manager asked for that short summary on every release.
100

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

What is a worker process in Playwright Test?

Save to ▾
Show answer
A worker is a separate operating system process that runs test files. Each worker starts its own browser, and tests inside a worker run one after another, while different workers run at the same time. Workers do not share memory, so you cannot pass variables between them. Worker-scoped fixtures are created once per worker, which is why expensive setup is often placed there.
102

How many workers does Playwright use by default, and how do you change it?

Save to ▾
Show answer
By default Playwright uses about half of the logical CPU cores on the machine. You can set workers in playwright.config as a number or a percentage string such as '50%', or override it on the command line with --workers=4. Many teams use process.env.CI ? 2 : undefined so CI runners with few cores are not overloaded while laptops use their full power.
103

How do you use more than one reporter in the same run?

Save to ▾
Show answer
// playwright.config.ts export default defineConfig({ reporter: [ ['list'], ['html', { open: 'never', outputFolder: 'playwright-report' }], ['junit', { outputFile: 'results/junit.xml' }], ], });
104

What does the JUnit reporter produce and why do CI tools need it?

Save to ▾
Show answer
It writes an XML file in the JUnit format, with test suites, test cases, durations and failure messages. Most CI servers and test management tools read this format to show test counts, failures and history in their own dashboards. Set outputFile so the path is predictable, and publish that file as a test result in the pipeline.
105

What does the github reporter do?

Save to ▾
Show answer
The github reporter prints failures in the format GitHub Actions understands, so each failed test appears as an annotation on the right line of the pull request diff. It is usually combined with the html or blob reporter, for example reporter: process.env.CI ? [['github'], ['html']] : 'list'. It saves reviewers from digging through raw logs.
106

What does --repeat-each do?

Save to ▾
Show answer
--repeat-each=N runs every selected test N times in the same run, spread across workers. It is useful for checking a new or fixed test for flakiness before merging, for example npx playwright test checkout.spec.ts --repeat-each=20. Combined with several workers it also surfaces tests that collide with each other over shared data.
107

How do you open an HTML report downloaded from a CI artifact?

Save to ▾
Show answer
Unzip the artifact and run npx playwright show-report followed by the folder path, for example npx playwright show-report ./playwright-report. This starts a small local server, which is needed because traces load through it. Opening index.html directly from disk often fails to show traces. You can also upload a single trace zip to the online trace viewer.
108

What does the open option of the HTML reporter control?

Save to ▾
Show answer
open decides whether the report opens in a browser after the run: 'always', 'never' or 'on-failure', which is the default. In CI you set it to 'never' so the process does not try to start a browser or hang waiting. Locally on-failure is convenient. You can also set the PLAYWRIGHT_HTML_OPEN environment variable instead of editing config.
109

What is the difference between the list, line and dot reporters?

Save to ▾
Show answer
All three print to the terminal. list prints one line per test with its status and is the default locally. line shows a single updating line with progress and prints only failures in full, which suits long runs. dot prints one character per test, the most compact output, and is the default on CI. Choose based on how much log noise you want.
110

How can you view a trace file without a local Playwright install?

Save to ▾
Show answer
Open trace.playwright.dev in a browser and drag the trace zip onto the page. It is a static web app that loads the trace locally in the browser, so the file is not uploaded to a server. This lets developers or managers look at a failed CI run quickly. For full features and offline use, npx playwright show-trace works too.
111

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 });
112

Tell me about a time you learned a new testing tool under a deadline.

Save to ▾
Show answer
Situation: my team moved from another tool to Playwright two weeks before a release. Task: I had to migrate the smoke tests. Action: I spent two evenings on the official docs and codegen, rewrote one test end to end, then asked a senior to review it before converting the rest with the same pattern. Result: all 25 smoke tests ran in Playwright before the release and ran faster than before.
113

How do you add, read and clear cookies in a browser context?

Save to ▾
Show answer
await context.addCookies([ { name: 'consent', value: 'yes', url: 'https://shop.example.test' }, ]); const cookies = await context.cookies(); expect(cookies.find((c) => c.name === 'consent')?.value).toBe('yes'); await context.clearCookies({ name: 'consent' });

Frequently asked questions

Who should practise easy Playwright Testing questions?

Freshers and career switchers should start here, and experienced candidates should skim them the day before an interview.

How should I practise these?

Answer each question aloud before opening the answer, mark it as solved only when your answer matches the key idea, and save misses to Last-Minute Revision.

Other difficulty levels