QA and Software Testing | 45 questions | 2026
Playwright Interview Questions and Answers
Playwright interview questions for freshers 22
Q1FresherMost askedAnswerHideWhat is Playwright and why would you choose it for test automation?
Playwright is a free, open source tool from Microsoft for end-to-end testing. One API controls Chromium, Firefox and WebKit. You can write tests in TypeScript, JavaScript, Python, Java and .NET. It also comes with its own test runner (@playwright/test).
Reasons teams pick it:
- Auto-waiting: it checks the element is ready before acting, so you rarely need explicit waits.
- Isolated browser contexts make tests fast and independent.
- It has built-in parallel runs, retries, HTML reports, a trace viewer, codegen and network mocking.
- Web-first assertions retry until they pass or time out.
- It handles multiple tabs, iframes, shadow DOM and API testing in the same tool.
What they are checking: Whether you can explain the tool with clear, real advantages
Q2FresherMost askedAnswerHideWhat is the difference between Playwright, Selenium and Cypress?
| Playwright | Selenium | Cypress | |
|---|---|---|---|
| Architecture | Direct protocol link to the browser | WebDriver protocol via a driver | Runs inside the browser |
| Browsers | Chromium, Firefox, WebKit | All major, plus older and real devices through grids | Chromium family, Firefox, WebKit (experimental) |
| Languages | TS/JS, Python, Java, .NET | Java, Python, C#, JS, Ruby and more | JavaScript/TypeScript only |
| Waiting | Automatic readiness checks | Manual explicit waits | Automatic retry |
| Multi-tab / multi-origin | Supported natively | Supported | Limited, better with cy.origin |
| Parallel | Built in workers | Needs TestNG, xdist or Grid | Paid dashboard or manual split |
| Mobile apps | Emulation only | Appium adds it | No |
Choose Playwright for modern web apps. Choose Selenium when you need many languages or already have a large suite. Choose Cypress for JavaScript teams who like its interactive runner.
What they are checking: Whether you can compare tools in a fair way
Q3FresherMost askedAnswerHideWhat locators does Playwright provide and which should you prefer?
Prefer user-facing locators. They find elements the way people do:
page.getByRole('button', { name: 'Sign in' })(the best default, and it also checks accessibility)page.getByLabel('Email'),getByPlaceholder,getByText,getByAltText,getByTitlepage.getByTestId('submit')(usesdata-testid, and you can change the attribute name)page.locator('css=...')or XPath only as a last choice.
You can chain and filter: page.getByRole('listitem').filter({ hasText: 'Pro plan' }).getByRole('button', { name: 'Buy' }). Locators are lazy. They find the element again on every action. So they do not go stale like Selenium elements.
What they are checking: Whether you pick locators that do not break easily
Q4FresherMost askedAnswerHideExplain auto-waiting in Playwright.
Before an action such as click, Playwright checks that the element is attached, visible, stable (not moving), not covered and enabled. It retries until all of these are true or the action timeout (30 seconds by default) ends.
So you write await page.getByRole('button', { name: 'Save' }).click(); and add no sleeps or explicit waits. Assertions such as expect(locator).toBeVisible() also retry. You still wait yourself for things that are not elements, for example await page.waitForResponse(...) or await page.waitForURL('**/dashboard').
What they are checking: Whether you understand the checks Playwright runs before an action
Q5FresherMost askedAnswerHideWrite a login test in Playwright with TypeScript.
import { test, expect } from '@playwright/test';
test.describe('login', () => {
test('valid user reaches the secure area', async ({ page }) => {
await page.goto('https://the-internet.herokuapp.com/login');
await page.getByLabel('Username').fill('tomsmith');
await page.getByLabel('Password').fill('SuperSecretPassword!');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/\/secure/);
await expect(page.locator('#flash')).toContainText('You logged into a secure area');
});
test('invalid password shows an error', async ({ page }) => {
await page.goto('https://the-internet.herokuapp.com/login');
await page.getByLabel('Username').fill('tomsmith');
await page.getByLabel('Password').fill('wrong');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page.locator('#flash')).toContainText('Your password is invalid');
});
});
Run it with npx playwright test. Each test gets a fresh browser context, so you need no cleanup.
What they are checking: Whether you can write a clean test that runs, live in the interview
Q6FresherMost askedAnswerHideWhat are fixtures in Playwright Test and how do you create a custom one?
Fixtures give tests the objects they need for setup and cleanup. A test gets a fixture by name, and it is created only when a test asks for it. Built-in ones include page, context, browser and request.
Here is a custom fixture that gives the test a login page object:
import { test as base, expect } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';
type Fixtures = { loginPage: LoginPage };
export const test = base.extend<Fixtures>({
loginPage: async ({ page }, use) => {
const lp = new LoginPage(page);
await lp.goto();
await use(lp); // test runs here
// teardown code goes after use()
},
});
export { expect };
Fixtures replace beforeEach and afterEach hooks. They are typed, can depend on each other, and are created only when needed. You can scope them per test or per worker.
What they are checking: Whether you know how fixtures differ from hooks
Q7FresherMost askedAnswerHideHow do you implement the Page Object Model in Playwright?
Make one class per page. The class holds the Page, defines locators as properties and offers actions. Then tests read like steps.
import { Page, Locator, expect } from '@playwright/test';
export class LoginPage {
readonly username: Locator;
readonly password: Locator;
readonly submit: Locator;
constructor(private page: Page) {
this.username = page.getByLabel('Username');
this.password = page.getByLabel('Password');
this.submit = page.getByRole('button', { name: 'Login' });
}
async goto() { await this.page.goto('/login'); }
async login(u: string, p: string) {
await this.username.fill(u);
await this.password.fill(p);
await this.submit.click();
}
}
Give the page object to tests through a fixture. Set baseURL in the config. Keep assertions in the tests, or in clearly named expect... helpers. Locators are lazy, so it is safe to define them in the constructor.
What they are checking: Whether you can structure test code that is easy to maintain
Q8FresherMost askedFree with sign-inAnswerHideWhat are web-first assertions in Playwright?
These are expect(locator) assertions that retry on their own until the condition is true or the timeout (5 seconds by default) ends.
Q9FresherMost askedFree with sign-inAnswerHideWhat is the difference between Browser, BrowserContext and Page in Playwright?
- Browser: one browser instance (for example a Chromium process). It is slow to start and is shared by a worker.
- BrowserContext: an isolated, incognito-like profile inside a browser. It has its own cookies, storage and cache. It takes only milliseconds to create.
- Page: a single tab inside a context. A context can hold many pages.
Q10FresherMost askedFree with sign-inAnswerHideHow does Playwright achieve test isolation?
Each test runs in its own BrowserContext with clean cookies, local storage, session storage and cache. Nothing carries over between tests. So they can run in any order and at the same time.
Q11FresherMost askedFree with sign-inAnswerHideWhat are the key settings in playwright.config.ts?
testDir,timeout,expect.timeout: where tests live and the time limits.fullyParallel,workers,retries: speed and stability.reporter:html,list,junit,json, or several.use: shared options such asbaseURL,trace,screenshot,video,viewport,locale,storageState,...
Q12FresherMost askedFree with sign-inAnswerHideHow do you implement data-driven tests in Playwright?
Make tests from an array in a loop. Each turn of the loop adds its own test with a unique title.
Q13FresherMost askedFree with sign-inAnswerHideHow do you configure multiple browsers and mobile emulation?
Add entries to projects in the config. Every test runs once for each project.
Q14FresherMost askedFree with sign-inAnswerHideIs waitForTimeout acceptable, and what should you use instead?
page.waitForTimeout(ms) is a fixed sleep. It is slow and still makes tests unstable. Playwright's own docs discourage it, except while debugging.
Q15FresherMost askedFree with sign-inAnswerHideHow do you use hooks such as beforeEach and afterEach in Playwright?
Hooks run setup and cleanup around tests, inside a describe block or a file. They are test.beforeAll, test.beforeEach, test.afterEach and test.afterAll.
Q16FresherMost askedFree with sign-inAnswerHideWhat is Playwright codegen and how useful is it?
npx playwright codegen <url> opens a browser and a recorder window. The recorder writes test code as you click, and it uses role-based locators. You can also use it to pick locators and assertions.
Q17FresherMost askedFree with sign-inAnswerHideHow do you handle new tabs and popups in Playwright?
Start waiting for the event before the action that causes it.
Q18FresherMost askedFree with sign-inAnswerHideHow do you upload and download files in Playwright?
Upload: await page.getByLabel('Upload').setInputFiles('files/report.pdf');. You can also pass an array, or [] to clear the files. If a button opens a file chooser and there is no input, listen for filechooser.
Q19FresherMost askedFree with sign-inAnswerHideHow do you handle dialogs such as alert, confirm and prompt?
Register a handler before the action. If no listener exists, Playwright closes the dialog on its own.
Q20FresherMost askedFree with sign-inAnswerHideHow do you group tests and run only some of them, for example smoke tests?
Put tags in the title (or use the tag option) and filter with --grep.
Q21FresherMost askedFree with sign-inAnswerHideHow do timeouts work in Playwright?
There are several layers:
- Test timeout: 30 seconds by default for the whole test (
timeout). - Expect timeout: 5 seconds for each assertion (
expect.timeout). - Action timeout: no limit by default, except the test timeout (
actionTimeout). - Navigation timeout: for
gotoand page loads (navigationTimeout).
Q22FresherMost askedFree with sign-inAnswerHideWhat languages and tools does Playwright support, and what is the test runner?
Playwright has bindings for TypeScript/JavaScript, Python, Java and .NET. The Node version includes @playwright/test. It is a full test runner with fixtures, parallel runs, retries, reporters, snapshots and a UI mode. In Python you use pytest-playwright. In Java and .NET you pair it with JUnit, NUnit or MSTest.
Playwright interview questions for experienced 15
Q23ExperiencedMost askedAnswerHideHow do you do API testing with Playwright?
Use the request fixture (APIRequestContext). It sends HTTP calls with no browser.
import { test, expect } from '@playwright/test';
test('create and fetch a post', async ({ request }) => {
const created = await request.post('https://jsonplaceholder.typicode.com/posts', {
data: { title: 'hello', body: 'world', userId: 1 },
});
expect(created.status()).toBe(201);
const body = await created.json();
expect(body.title).toBe('hello');
const res = await request.get('https://jsonplaceholder.typicode.com/posts/1');
await expect(res).toBeOK();
expect((await res.json()).id).toBe(1);
});
Set baseURL and extraHTTPHeaders (for auth tokens) in the config. A good pattern is to prepare data through the API and check the result in the UI. You can also check status codes, schema, headers and error cases (401, 404, 422).
What they are checking: Whether you can mix API checks with UI work
Q24ExperiencedMost askedAnswerHideHow do you integrate Playwright tests with GitHub Actions?
name: e2e
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22, cache: npm }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
env:
BASE_URL: ${{ secrets.STAGING_URL }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 14
Tips: set retries: 1 and trace: 'on-first-retry' on CI. Use forbidOnly: !!process.env.CI. Cache the browsers. Use a matrix to shard the tests for speed. Keep secrets in repository secrets.
What they are checking: Whether you can run tests in CI from start to finish
Q25ExperiencedMost askedFree with sign-inAnswerHideHow do you mock network requests in Playwright?
Use page.route to catch a request. Then you can answer it, change it or block it.
Q26ExperiencedMost askedFree with sign-inAnswerHideWhat is the Playwright Trace Viewer and how do you use it?
A trace is a recording of a test run. It holds DOM snapshots before and after each action, a timeline, network calls, console logs, source code and screenshots. You open it with npx playwright show-trace trace.zip or from the HTML report.
Q27ExperiencedMost askedFree with sign-inAnswerHideHow does parallel execution work in Playwright?
Test files run in parallel across workers. Each worker is a separate process with its own browser. Tests inside one file run in order in the same worker, unless you set fullyParallel: true.
Q28ExperiencedMost askedFree with sign-inAnswerHideWhat are project dependencies and global setup in Playwright?
Both run work before the tests, such as adding data or logging in.
Q29ExperiencedMost askedFree with sign-inAnswerHideHow would you design a scalable Playwright framework structure?
A practical layout:
Q30ExperiencedMost askedFree with sign-inAnswerHideHow do you handle iframes and Shadow DOM in Playwright?
Iframes: use page.frameLocator.
Q31ExperiencedMost askedFree with sign-inAnswerHideWhat are soft assertions and expect.poll or toPass in Playwright?
- Soft assertions (
expect.soft(...)) record a failure but let the test go on. So you see all failures in one run. The test still fails at the end. They are good for checking many fields on a page. expect.pollretries a function that returns a value until the assertion passes. It is useful for data that...
Q32ExperiencedMost askedFree with sign-inAnswerHideHow do you do visual comparison testing in Playwright?
Use await expect(page).toHaveScreenshot('home.png'), or call it on a locator. The first run saves a baseline image. Later runs compare pixels and fail if the difference is above a limit (maxDiffPixelRatio). Update baselines with --update-snapshots.
Q33ExperiencedMost askedFree with sign-inAnswerHideWhat is the difference between a Locator and an ElementHandle?
A Locator is a lazy description of how to find an element. It looks in the DOM again on every action and waits automatically. So it still works after the page re-renders. An ElementHandle is a live link to one specific DOM node. It can go stale, and it does not wait in the same way.
Q34ExperiencedMost askedFree with sign-inAnswerHideHow do you test a dynamic table, such as filtering and sorting rows?
Chain locators and use filter. Use count assertions, because they retry.
Q35ExperiencedMost askedFree with sign-inAnswerHideHow do you run accessibility checks with Playwright?
Use the @axe-core/playwright package to scan a page for WCAG (web accessibility rules) violations.
Q36ExperiencedMost askedFree with sign-inAnswerHideHow do you shard Playwright tests across multiple CI machines?
Split the suite with --shard=x/y. Run each shard as a matrix job, then merge the reports.
Q37ExperiencedMost askedFree with sign-inAnswerHideHow would you test a multi-user feature such as chat in Playwright?
Create two independent browser contexts in one test. Log each one in as a different user.
Scenario based Playwright interview questions 8
Q38ExperiencedMost askedScenarioAnswerHideHow do you reuse login state across tests with storageState?
Log in once, save the cookies and storage to a file, and load that file in every test context. This removes the login screen from most tests and saves minutes.
// auth.setup.ts
import { test as setup, expect } from '@playwright/test';
setup('authenticate', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(process.env.USER_EMAIL!);
await page.getByLabel('Password').fill(process.env.USER_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/dashboard/);
await page.context().storageState({ path: 'playwright/.auth/user.json' });
});
In playwright.config.ts, define a setup project. Make the browser projects depend on it with use: { storageState: 'playwright/.auth/user.json' }. Add the .auth folder to .gitignore. For different roles, save one file per role. Keep one separate test that uses the real login form.
What they are checking: Whether you can speed up a suite by reusing login
Q39ExperiencedMost askedScenarioFree with sign-inAnswerHideYour Playwright tests are unstable on CI (they pass sometimes and fail other times). How do you handle it?
Find the cause before you add retries.
Q40ExperiencedMost askedScenarioFree with sign-inAnswerHideA Playwright test fails locally and you do not know why. How do you debug it?
Start with simple tools and move to detailed ones.
Q41ExperiencedMost askedScenarioFree with sign-inAnswerHideYou get a strict mode violation error. What does it mean and how do you fix it?
The locator matched more than one element. For actions like click or fill, Playwright will not guess which one you mean.
Q42ExperiencedMost askedScenarioFree with sign-inAnswerHideHow do you combine API calls and UI actions in one test?
Use the API for setup and checking. Use the UI only for what you are testing. This makes tests faster and less fragile.
Q43ExperiencedMost askedScenarioFree with sign-inAnswerHideA third-party service (payment or maps) is slow and breaks your tests. How do you handle it?
Keep the test apart from that dependency.
Q44ExperiencedMost askedScenarioFree with sign-inAnswerHideWhen would you use getByTestId instead of getByRole?
Use getByRole and getByLabel first. They test what users and assistive tools (like screen readers) see, and they also catch accessibility problems. Use getByTestId when:
- The element has no accessible role or name (a canvas, a chart, an icon button that cannot be named).
- The text changes with language or A/B experiments.
- Many identical elements need a stable handle.
Q45ExperiencedMost askedScenarioFree with sign-inAnswerHideHow would you migrate a Cypress or Selenium suite to Playwright?
Move step by step. Do not rewrite everything at once.