Playwright Coding Interview Questions and Answers: Complete 2026 Guide

Introduction: Why Coding Skills Matter in Playwright Interviews

Playwright coding interview questions are designed to test more than your knowledge of Playwright commands.

In a real QA Automation or SDET role, you must convert requirements into reliable automation code. You may be asked to write a login test, create a reusable Page Object, handle dynamic elements, validate an API, mock a backend response, debug a flaky test, or design a framework that can run hundreds of tests in CI.

That is why interviewers often combine theoretical questions with live coding.

Playwright’s locator model, auto-waiting, fixtures, authentication state, network interception, and parallel execution provide a strong foundation for writing maintainable automation.

This guide focuses on Playwright Coding Interview Questions and Answers using practical TypeScript examples.

The code assumes a standard Playwright Test project:

npm install -D @playwright/test

npx playwright install

The goal is not to memorize code. Instead, understand the design decisions behind each solution.


How Playwright Coding Interviews Are Conducted

A Playwright coding interview may follow one of these formats:

Interview TypeTypical Task
Live codingWrite a Playwright test
Take-home taskBuild a small automation framework
DebuggingFix a flaky test
Code reviewImprove existing Playwright code
Framework designCreate POM/fixtures/configuration
API automationWrite API tests and data setup
CI/CDConfigure GitHub Actions
MigrationConvert Selenium code to Playwright

For freshers, expect basic browser interactions and locators.

For 2–3 years of experience, expect POM, fixtures, dynamic elements, API testing, and debugging.

For senior SDETs, expect framework architecture, authentication, parallel execution, test isolation, CI/CD, and scalability.


Beginner Playwright Coding Interview Questions

1. Write a Basic Playwright Test

Difficulty: Beginner

Question: Write a Playwright test that opens a page and verifies its title.

Expected Approach

Use the page fixture, navigate with goto(), and validate the title with a web-first assertion.

Complete TypeScript Code

import { test, expect } from ‘@playwright/test’;

test(‘verify page title’, async ({ page }) => {

  await page.goto(‘https://example.com’);

  await expect(page).toHaveTitle(/Example/);

});

Explanation

The page fixture provides an isolated page for the test. Playwright assertions automatically retry until the condition is satisfied or the assertion timeout is reached.

Interview Tip

Do not use waitForTimeout() before checking the title. Use Playwright’s assertion mechanism.


2. Write a Login Test

Difficulty: Beginner

Question: Automate a login form containing Username, Password, and Login fields.

Expected Approach

Use semantic locators rather than fragile CSS or XPath.

Complete TypeScript Code

import { test, expect } from ‘@playwright/test’;

test(‘user can log in’, async ({ page }) => {

  await page.goto(‘/login’);

  await page.getByLabel(‘Username’).fill(‘john’);

  await page.getByLabel(‘Password’).fill(‘secret’);

  await page.getByRole(‘button’, {

    name: ‘Login’

  }).click();

  await expect(page).toHaveURL(/dashboard/);

});

Explanation

getByLabel() is appropriate for form controls, while getByRole() is useful for buttons. Playwright recommends user-facing locators such as role and label because they are generally more resilient than selectors tied to DOM structure.

Interview Tip

Explain why you selected each locator. Interviewers often evaluate locator reasoning rather than syntax alone.


3. Write a Dashboard Validation Test

Difficulty: Beginner

Question: After login, verify that the dashboard heading and Logout button are displayed.

Expected Approach

Use web-first assertions.

Complete TypeScript Code

test(‘dashboard is displayed’, async ({ page }) => {

  await page.goto(‘/dashboard’);

  await expect(

    page.getByRole(‘heading’, { name: ‘Dashboard’ })

  ).toBeVisible();

  await expect(

    page.getByRole(‘button’, { name: ‘Logout’ })

  ).toBeVisible();

});

Explanation

toBeVisible() waits for the expected state instead of checking visibility once.

Interview Tip

Mention that assertions can act as synchronization points.


Locator and Assertion Coding Problems

4. Create a Robust Locator for a Dynamic Button

Difficulty: Beginner

Question: A button has changing CSS classes but always has the accessible name “Submit Order.” Write a stable locator.

Expected Approach

Use the button’s role and accessible name.

Complete TypeScript Code

const submitButton = page.getByRole(‘button’, {

  name: ‘Submit Order’

});

await submitButton.click();

Explanation

Avoid selectors such as:

page.locator(‘.css-x92ab-submit-button’).click();

Generated classes can change between builds.

Playwright specifically recommends prioritizing user-facing attributes and explicit contracts over brittle CSS/XPath selectors.

Interview Tip

A good locator should express what the user interacts with, not how the DOM happens to be implemented.


5. Handle a Locator That Matches Multiple Elements

Difficulty: Intermediate

Question: There are five “Edit” buttons on a page. Click Edit for the user named John.

Expected Approach

Locate the user’s row first, then find the Edit button within that row.

Complete TypeScript Code

const userRow = page

  .getByRole(‘row’)

  .filter({ hasText: ‘John’ });

await userRow

  .getByRole(‘button’, { name: ‘Edit’ })

  .click();

Explanation

This is better than:

await page

  .getByRole(‘button’, { name: ‘Edit’ })

  .nth(2)

  .click();

The filtered approach identifies the business entity rather than relying on position.

Interview Tip

If an interviewer asks about strict mode, explain that you first make the locator unique instead of blindly using nth().


6. Validate Multiple Elements

Difficulty: Intermediate

Question: Verify that a product list contains exactly five products.

Complete TypeScript Code

const products = page.getByRole(‘listitem’);

await expect(products).toHaveCount(5);

You can then inspect a specific product:

await expect(

  products.filter({ hasText: ‘Laptop’ })

).toBeVisible();

Explanation

Using assertions keeps the synchronization behavior inside Playwright’s test model.

Interview Tip

For dynamically loaded lists, avoid calling locator.all() before the list is stable because locator.all() does not wait for elements to appear.


Form, Dropdown, Table, Popup, Iframe, Upload, and Download Tasks

7. Automate a Dropdown

Difficulty: Beginner

Question: Select India from a native HTML <select>.

Complete TypeScript Code

await page.getByLabel(‘Country’).selectOption({

  label: ‘India’

});

Or:

await page.getByLabel(‘Country’).selectOption(‘IN’);

Explanation

selectOption() is designed for native <select> controls.

Interview Tip

First determine whether the application uses a native select or a custom JavaScript dropdown. They require different strategies.


8. Automate a Table Row

Difficulty: Intermediate

Question: Find the order belonging to ORD-1001 and click its View button.

Complete TypeScript Code

const orderRow = page

  .getByRole(‘row’)

  .filter({ hasText: ‘ORD-1001’ });

await orderRow

  .getByRole(‘button’, { name: ‘View’ })

  .click();

Explanation

The locator is scoped to the relevant row, reducing ambiguity.

Interview Tip

This is a common real-world coding exercise because it tests chaining and filtering.


9. Handle a New Tab or Popup

Difficulty: Intermediate

Question: Click a link that opens a report in a new tab and verify the report page.

Complete TypeScript Code

const popupPromise = page.waitForEvent(‘popup’);

await page.getByRole(‘link’, {

  name: ‘Open Report’

}).click();

const popup = await popupPromise;

await popup.waitForLoadState();

await expect(popup).toHaveTitle(/Report/);

Explanation

The event listener is established before the click that creates the popup.

Interview Tip

This demonstrates event-driven synchronization instead of fixed waits.


10. Handle an Iframe

Difficulty: Intermediate

Question: Enter a card number inside a payment iframe.

Complete TypeScript Code

const paymentFrame = page.frameLocator(‘#payment-frame’);

await paymentFrame

  .getByLabel(‘Card Number’)

  .fill(‘4111111111111111’);

await paymentFrame

  .getByRole(‘button’, { name: ‘Pay’ })

  .click();

Explanation

frameLocator() lets you continue using locator strategies inside the iframe.

Interview Tip

Remember that iframe content belongs to a separate document context.


11. Upload a File

Difficulty: Beginner

Question: Upload resume.pdf.

Complete TypeScript Code

await page

  .getByLabel(‘Upload Resume’)

  .setInputFiles(‘tests/data/resume.pdf’);

Explanation

setInputFiles() directly interacts with the file input.

Interview Tip

Do not unnecessarily automate the operating-system file picker.


12. Download and Validate a File

Difficulty: Intermediate

Question: Click Download and save the resulting PDF.

Complete TypeScript Code

const downloadPromise = page.waitForEvent(‘download’);

await page.getByRole(‘button’, {

  name: ‘Download’

}).click();

const download = await downloadPromise;

await download.saveAs(‘downloads/report.pdf’);

Explanation

The download event is captured before triggering the action.

Interview Tip

For robust tests, validate meaningful properties such as the suggested filename or file contents, not only that a download occurred.


Intermediate Playwright Automation Coding Questions

13. Create a Page Object Model

Difficulty: Intermediate

Question: Create a reusable Login Page Object.

Expected Approach

Encapsulate locators and business actions in a class.

Complete TypeScript Code

import type { Page, Locator } from ‘@playwright/test’;

export class LoginPage {

  readonly username: Locator;

  readonly password: Locator;

  readonly loginButton: Locator;

  constructor(private readonly page: Page) {

    this.username = page.getByLabel(‘Username’);

    this.password = page.getByLabel(‘Password’);

    this.loginButton = page.getByRole(‘button’, {

      name: ‘Login’

    });

  }

  async login(username: string, password: string) {

    await this.username.fill(username);

    await this.password.fill(password);

    await this.loginButton.click();

  }

}

Usage:

const loginPage = new LoginPage(page);

await loginPage.login(‘john’, ‘secret’);

Explanation

POM separates test intent from UI implementation.

Interview Tip

A senior answer should mention that POM should expose business actions rather than simply wrapping every Playwright command.


14. Create a Custom Fixture

Difficulty: Advanced

Question: Create a fixture that provides a reusable LoginPage.

Complete TypeScript Code

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 loginPage = new LoginPage(page);

    await use(loginPage);

  }

});

export { expect };

Test:

import { test, expect } from ‘./fixtures’;

test(‘login’, async ({ loginPage, page }) => {

  await page.goto(‘/login’);

  await loginPage.login(‘john’, ‘secret’);

  await expect(page).toHaveURL(/dashboard/);

});

Explanation

Fixtures establish reusable test dependencies. Playwright fixtures are isolated and can be composed from other fixtures.

Interview Tip

Understand fixture scope. A worker-scoped fixture is appropriate when setup should happen once per worker rather than once per test.


Authentication and Storage State Coding Questions

15. Save and Reuse Authentication State

Difficulty: Advanced

Question: How would you authenticate once and reuse the session across tests?

Expected Approach

Perform login in a setup test, save storageState, and configure subsequent tests to use it.

Complete TypeScript Code

import { test as setup } from ‘@playwright/test’;

setup(‘authenticate’, async ({ page }) => {

  await page.goto(‘/login’);

  await page.getByLabel(‘Username’).fill(

    process.env.TEST_USERNAME!

  );

  await page.getByLabel(‘Password’).fill(

    process.env.TEST_PASSWORD!

  );

  await page.getByRole(‘button’, {

    name: ‘Login’

  }).click();

  await page.waitForURL(/dashboard/);

  await page.context().storageState({

    path: ‘playwright/.auth/user.json’

  });

});

Then:

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  use: {

    storageState: ‘playwright/.auth/user.json’

  }

});

Explanation

Reusing authenticated state avoids repeating UI login for every test. Playwright recommends keeping authentication-state files out of source control because they can contain sensitive cookies and headers.

Interview Tip

Always mention .gitignore and secret protection.


16. How Would You Handle Authentication Per Parallel Worker?

Difficulty: Advanced

Question: Tests modify server-side state, so one shared account creates conflicts. What would you do?

Expected Approach

Use a unique account per worker and generate or acquire worker-specific authentication state.

Complete TypeScript Pattern

import { test as base } from ‘@playwright/test’;

type Fixtures = {

  account: {

    username: string;

    password: string;

  };

};

export const test = base.extend<

  Fixtures,

  { workerAccount: Fixtures[‘account’] }

>({

  workerAccount: [async ({}, use, workerInfo) => {

    const account = {

      username: `worker-${workerInfo.workerIndex}`,

      password: ‘test-password’

    };

    await use(account);

  }, { scope: ‘worker’ }],

  account: async ({ workerAccount }, use) => {

    await use(workerAccount);

  }

});

Explanation

When tests modify server-side state, Playwright’s authentication guidance recommends approaches such as one account per parallel worker rather than sharing a single account across conflicting tests.

Interview Tip

The important concept is test-data isolation, not simply generating random usernames.


API Testing Coding Questions

17. Write an API Test

Difficulty: Intermediate

Question: Send a POST request and verify the response.

Complete TypeScript Code

import { test, expect } from ‘@playwright/test’;

test(‘create user through API’, async ({ request }) => {

  const response = await request.post(‘/api/users’, {

    data: {

      name: ‘John’,

      role: ‘tester’

    }

  });

  expect(response.ok()).toBeTruthy();

  const body = await response.json();

  expect(body.name).toBe(‘John’);

  expect(body.role).toBe(‘tester’);

});

Explanation

The Playwright request fixture provides an API request context suitable for API testing and test-data setup.

Interview Tip

Mention that API setup is often faster and more deterministic than creating data through the UI.


18. Create Test Data Through an API Before a UI Test

Difficulty: Advanced

Question: Create an order using an API and verify it through the UI.

Complete TypeScript Code

test(‘order appears in UI’, async ({

  request,

  page

}) => {

  const response = await request.post(‘/api/orders’, {

    data: {

      productId: 101,

      quantity: 2

    }

  });

  expect(response.ok()).toBeTruthy();

  const order = await response.json();

  await page.goto(`/orders/${order.id}`);

  await expect(

    page.getByText(‘Order created’)

  ).toBeVisible();

});

Explanation

This hybrid approach keeps UI tests focused on UI behavior while using APIs for efficient setup.

Interview Tip

Explain the test boundary: API creates the precondition; UI validates the user-facing behavior.


Network Mocking and Interception Coding Tasks

19. Mock an API Response

Difficulty: Advanced

Question: The /api/products endpoint is unstable. Mock it so the UI always receives one product.

Complete TypeScript Code

test(‘display mocked product’, async ({ page }) => {

  await page.route(‘**/api/products’, async route => {

    await route.fulfill({

      status: 200,

      contentType: ‘application/json’,

      body: JSON.stringify({

        products: [

          {

            id: 1,

            name: ‘Laptop’

          }

        ]

      })

    });

  });

  await page.goto(‘/products’);

  await expect(

    page.getByText(‘Laptop’)

  ).toBeVisible();

});

Explanation

Playwright can intercept and modify HTTP and HTTPS traffic, including XHR and fetch requests. Network routing can be used for deterministic API mocking.

Interview Tip

Register the route before the request is made.


20. Simulate a Server Error

Difficulty: Scenario-Based

Question: How would you test the UI behavior when the backend returns HTTP 500?

Complete TypeScript Code

await page.route(‘**/api/orders’, async route => {

  await route.fulfill({

    status: 500,

    contentType: ‘application/json’,

    body: JSON.stringify({

      error: ‘Internal server error’

    })

  });

});

await page.goto(‘/orders’);

await expect(

  page.getByRole(‘alert’)

).toContainText(‘Unable to load orders’);

Explanation

This allows you to test failure handling without depending on an actual backend outage.

Interview Tip

Senior candidates should mention that mocks must be maintained carefully so they do not diverge from the real API contract.


Data-Driven Playwright Coding Questions

21. Write a Data-Driven Login Test

Difficulty: Intermediate

Question: Test multiple login scenarios.

Complete TypeScript Code

import { test, expect } from ‘@playwright/test’;

const users = [

  {

    username: ‘valid-user’,

    password: ‘valid-pass’,

    expected: ‘success’

  },

  {

    username: ‘invalid-user’,

    password: ‘wrong-pass’,

    expected: ‘failure’

  }

];

for (const user of users) {

  test(`login – ${user.expected}`, async ({ page }) => {

    await page.goto(‘/login’);

    await page.getByLabel(‘Username’)

      .fill(user.username);

    await page.getByLabel(‘Password’)

      .fill(user.password);

    await page.getByRole(‘button’, {

      name: ‘Login’

    }).click();

    if (user.expected === ‘success’) {

      await expect(page).toHaveURL(/dashboard/);

    } else {

      await expect(

        page.getByRole(‘alert’)

      ).toBeVisible();

    }

  });

}

Explanation

The test data is separated from the interaction logic.

Interview Tip

For larger projects, consider Playwright projects, fixtures, or parameterization patterns rather than generating enormous numbers of test cases in one file.


Debugging and Flaky-Test Coding Scenarios

22. Fix a Test Using waitForTimeout()

Difficulty: Scenario-Based

Question: Improve this code:

await page.click(‘#save’);

await page.waitForTimeout(5000);

expect(await page.locator(‘.success’).isVisible()).toBeTruthy();

Expected Approach

Replace fixed waiting with a web-first assertion.

Complete TypeScript Code

await page.getByRole(‘button’, {

  name: ‘Save’

}).click();

await expect(

  page.getByRole(‘status’)

).toContainText(‘Saved’);

Explanation

Playwright’s locators and assertions are designed around auto-waiting and retryability.

Interview Tip

Say: “I wait for a meaningful application condition, not an arbitrary amount of time.”


23. Debug a CI-Only Failure

Difficulty: Scenario-Based

Question: A test passes locally but fails in CI. Modify the configuration to collect useful diagnostics.

Complete TypeScript Code

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  retries: process.env.CI ? 1 : 0,

  use: {

    trace: ‘retain-on-failure’,

    screenshot: ‘only-on-failure’,

    video: ‘retain-on-failure’

  }

});

Explanation

Artifacts can reveal whether the failure is caused by timing, rendering, navigation, network behavior, or test-data problems.

Interview Tip

Do not immediately increase the timeout. Diagnose first.


24. Configure Parallel Workers

Difficulty: Intermediate

Question: Configure Playwright to use four workers in CI.

Complete TypeScript Code

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  workers: process.env.CI ? 4 : undefined

});

Explanation

Workers allow tests to execute concurrently. However, excessive workers can cause resource contention and failures. Playwright’s CI guidance warns that increasing workers beyond the runner’s available resources can cause unnecessary timeouts and failures.

Interview Tip

Always discuss CPU, memory, application capacity, and test isolation when discussing worker count.


Parallel Execution and Sharding

25. Write a Sharding Command

Difficulty: Advanced

Question: Your regression suite is too slow. How would you run one of four shards?

Complete TypeScript/CLI Example

npx playwright test –shard=1/4

Other jobs execute:

npx playwright test –shard=2/4

npx playwright test –shard=3/4

npx playwright test –shard=4/4

Explanation

Workers parallelize execution within a CI job. Shards split the suite between separate machines or CI jobs. Playwright supports sharding specifically for distributing tests across machines.

Interview Tip

Explain the difference clearly. This is a common Senior SDET coding question.


CI/CD and Configuration Coding Questions

26. Create a GitHub Actions Playwright Workflow

Difficulty: Intermediate

Question: Write a basic CI workflow.

Complete YAML

name: Playwright Tests

on:

  push:

    branches: [main]

  pull_request:

jobs:

  test:

    runs-on: ubuntu-latest

    steps:

      – name: Checkout

        uses: actions/checkout@v4

      – name: Setup Node

        uses: actions/setup-node@v4

        with:

          node-version: 20

          cache: npm

      – name: Install dependencies

        run: npm ci

      – name: Install browsers

        run: npx playwright install –with-deps

      – name: Run tests

        run: npx playwright test

      – name: Upload report

        if: always()

        uses: actions/upload-artifact@v4

        with:

          name: playwright-report

          path: playwright-report/

Explanation

The pipeline establishes a repeatable environment, installs browsers, executes tests, and preserves the report after failures.

Interview Tip

Know why if: always() matters. Without it, a failed test step can prevent artifact upload.


Screenshots, Traces, and Reporting Coding Questions

27. Configure Failure Diagnostics

Difficulty: Intermediate

Question: Capture screenshots and traces only when tests fail.

Complete TypeScript Code

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  use: {

    screenshot: ‘only-on-failure’,

    trace: ‘retain-on-failure’,

    video: ‘retain-on-failure’

  }

});

Explanation

This provides useful failure evidence without storing large artifacts for every successful test.

Interview Tip

Explain the trade-off between observability and CI storage.


Advanced Playwright Coding Interview Questions

28. Build a Reusable Framework Structure

Difficulty: Advanced

Question: Design a scalable Playwright framework.

Expected Approach

Separate responsibilities.

Example Structure

tests/

pages/

components/

fixtures/

api/

data/

utils/

auth/

config/

Example API Client

import type { APIRequestContext } from ‘@playwright/test’;

export class UserApi {

  constructor(

    private readonly request: APIRequestContext

  ) {}

  async createUser(name: string) {

    return this.request.post(‘/api/users’, {

      data: { name }

    });

  }

}

Explanation

This architecture keeps API operations, UI objects, fixtures, and test cases separate.

Interview Tip

A framework is not good because it has many folders. It is good when its boundaries make change easier.


29. Create a Reusable API Fixture

Difficulty: Advanced

Question: Make a reusable UserApi available to tests.

Complete TypeScript Code

import {

  test as base,

  expect

} from ‘@playwright/test’;

import { UserApi } from ‘./api/UserApi’;

type Fixtures = {

  userApi: UserApi;

};

export const test = base.extend<Fixtures>({

  userApi: async ({ request }, use) => {

    await use(new UserApi(request));

  }

});

export { expect };

Usage:

test(‘create user’, async ({ userApi }) => {

  const response =

    await userApi.createUser(‘John’);

  expect(response.ok()).toBeTruthy();

});

Explanation

This demonstrates dependency injection through Playwright fixtures.

Interview Tip

Fixtures are especially useful when a dependency needs controlled setup and teardown.


30. Design a Multi-Role Test

Difficulty: Advanced

Question: An admin and normal user must interact in the same scenario. Implement isolated contexts.

Complete TypeScript Code

test(‘admin and user workflow’, async ({ browser }) => {

  const adminContext = await browser.newContext({

    storageState: ‘playwright/.auth/admin.json’

  });

  const userContext = await browser.newContext({

    storageState: ‘playwright/.auth/user.json’

  });

  const adminPage = await adminContext.newPage();

  const userPage = await userContext.newPage();

  await adminPage.goto(‘/admin’);

  await userPage.goto(‘/dashboard’);

  await expect(

    adminPage.getByRole(‘heading’, {

      name: ‘Admin Dashboard’

    })

  ).toBeVisible();

  await expect(

    userPage.getByRole(‘heading’, {

      name: ‘Dashboard’

    })

  ).toBeVisible();

  await adminContext.close();

  await userContext.close();

});

Explanation

Browser contexts provide isolated sessions, making multi-user scenarios practical. Playwright’s authentication documentation also demonstrates separate authenticated contexts for multiple roles.

Interview Tip

This is an excellent Senior SDET coding problem because it tests authentication, isolation, and context management together.


Scenario-Based Playwright Coding Questions

31. Fix a Brittle Locator

Difficulty: Scenario-Based

Question: Replace this locator:

await page.locator(

  ‘#app > div:nth-child(2) > div:nth-child(3) > button’

).click();

Expected Approach

Find a stable semantic or testing contract.

Complete TypeScript Code

await page.getByRole(‘button’, {

  name: ‘Save’

}).click();

Explanation

Long CSS paths depend heavily on DOM structure. Playwright recommends user-facing locators and explicit test IDs instead.

Interview Tip

Explain why the new locator survives unrelated DOM changes.


32. Fix a Strict Mode Violation

Difficulty: Scenario-Based

Question: This fails because there are multiple Delete buttons:

await page.getByRole(‘button’, {

  name: ‘Delete’

}).click();

Solution

const account = page

  .getByRole(‘row’)

  .filter({ hasText: ‘John Smith’ });

await account.getByRole(‘button’, {

  name: ‘Delete’

}).click();

Explanation

The locator is scoped to the business entity.

Interview Tip

Avoid using .nth(0) unless ordering is intentionally part of the requirement.


33. Debug a Detached Element Scenario

Difficulty: Scenario-Based

Question: A React component is re-rendered after every save. How do you make the test resilient?

Expected Approach

Use a Locator rather than storing a DOM element reference.

Complete TypeScript Code

const saveButton = page.getByRole(‘button’, {

  name: ‘Save’

});

await saveButton.click();

await expect(

  page.getByRole(‘status’)

).toContainText(‘Saved’);

await saveButton.click();

Explanation

Playwright locators resolve the current matching element when used, which helps when the DOM changes between actions.

Interview Tip

Explain locator re-resolution rather than describing this simply as “Playwright waits.”


Real-World Playwright Framework Coding Challenge

34. Build a Mini E-Commerce Automation Framework

Difficulty: Senior SDET

Question: Design an automation framework that tests:

  1. Login.
  2. Product search.
  3. Add to cart.
  4. Checkout.
  5. Order validation.
  6. API-based test data.
  7. CI execution.

Expected Approach

Use:

tests/

pages/

api/

fixtures/

data/

auth/

playwright.config.ts

Product Page

import type { Page } from ‘@playwright/test’;

export class ProductPage {

  constructor(private readonly page: Page) {}

  async search(product: string) {

    await this.page

      .getByPlaceholder(‘Search products’)

      .fill(product);

    await this.page.getByRole(‘button’, {

      name: ‘Search’

    }).click();

  }

  async addToCart(product: string) {

    const card = this.page

      .getByRole(‘listitem’)

      .filter({ hasText: product });

    await card.getByRole(‘button’, {

      name: ‘Add to cart’

    }).click();

  }

}

API Data Setup

export async function createProduct(

  request: APIRequestContext,

  name: string

) {

  return request.post(‘/api/products’, {

    data: { name }

  });

}

Test

test(‘buy product’, async ({

  page,

  request

}) => {

  const response = await createProduct(

    request,

    ‘Laptop’

  );

  const product = await response.json();

  await page.goto(‘/products’);

  const productCard = page

    .getByRole(‘listitem’)

    .filter({ hasText: product.name });

  await productCard

    .getByRole(‘button’, {

      name: ‘Add to cart’

    })

    .click();

  await page.getByRole(‘link’, {

    name: ‘Cart’

  }).click();

  await expect(

    page.getByText(product.name)

  ).toBeVisible();

});

Explanation

This combines POM, API setup, semantic locators, assertions, and UI validation.

Interview Tip

For an architect-level answer, discuss test isolation, authentication, data cleanup, parallel execution, CI artifacts, and environment configuration.


Common Playwright Coding Interview Mistakes

Mistake 1: Using waitForTimeout()

Avoid:

await page.waitForTimeout(5000);

Prefer a condition:

await expect(

  page.getByRole(‘status’)

).toBeVisible();

Mistake 2: Choosing brittle locators

Avoid deeply nested CSS and XPath selectors. Playwright recommends user-facing locators and explicit test contracts.

Mistake 3: Ignoring async/await

Playwright APIs are asynchronous.

Use:

await page.goto(‘/’);

await page.getByRole(‘button’).click();

not:

page.goto(‘/’);

page.getByRole(‘button’).click();

Playwright’s own best practices recommend TypeScript linting such as no-floating-promises to catch missing awaits.

Mistake 4: Overusing force: true

force: true can hide genuine UI/actionability problems.

Mistake 5: Sharing mutable test data

Parallel tests need isolated accounts, records, files, and other mutable state.

Mistake 6: Putting everything in POM

Do not put API clients, random utilities, environment configuration, and unrelated business logic into every page class.

Mistake 7: Treating retries as a fix

Retries can reduce transient CI failures, but persistent flakiness needs investigation.

Mistake 8: Committing authentication state

Authentication files can contain sensitive cookies and headers. Playwright recommends keeping the .auth directory out of source control.


Playwright Coding Interview Preparation Roadmap

Freshers

Master:

  • TypeScript basics
  • async/await
  • test()
  • expect()
  • page
  • goto()
  • click()
  • fill()
  • Locators
  • Basic assertions
  • Forms
  • Screenshots

Practice the beginner Playwright Coding Questions first.

2–3 Years Experience

Add:

4–5 Years Experience

Focus on:

  • Custom fixtures
  • Worker fixtures
  • API/UI hybrid testing
  • Parallel execution
  • Sharding
  • CI/CD
  • Docker
  • Authentication architecture
  • Flaky-test debugging
  • Framework organization

Senior SDET

Be prepared to code:

  • Multi-user workflows
  • Worker-specific authentication
  • API clients
  • Custom fixtures
  • Network mocks
  • Data factories
  • CI matrices
  • Sharded execution
  • Reporting configuration
  • Failure diagnostics

Automation Architect

Expect design questions involving:

  • Framework scalability
  • Dependency boundaries
  • Test isolation
  • Authentication architecture
  • Test-data services
  • CI cost
  • Browser strategy
  • Observability
  • Migration from Selenium
  • Long-term maintainability

Playwright Coding Interview Checklist

Before your interview, make sure you can code these without documentation:

  • Basic Playwright test
  • Login flow
  • Dashboard validation
  • Role-based locator
  • Filtered table row
  • Dynamic element
  • Strict-mode fix
  • Form submission
  • Dropdown
  • Iframe
  • Popup
  • File upload
  • File download
  • POM class
  • Custom fixture
  • Authentication setup
  • storageState
  • API request
  • API test-data setup
  • Network mock
  • Multiple browser contexts
  • Data-driven tests
  • Parallel workers
  • Test sharding
  • CI workflow
  • Trace configuration
  • Screenshot configuration
  • Flaky-test debugging

FAQs: Playwright Coding Interview Questions

What are common Playwright coding interview questions?

Common tasks include writing login tests, creating robust locators, handling dynamic elements, building Page Objects, creating fixtures, performing API requests, mocking network responses, managing authentication, and debugging flaky tests.

Is TypeScript required for Playwright coding interviews?

Not always. Playwright supports multiple programming languages, but TypeScript is especially common in Playwright automation roles. If the job description specifies TypeScript, expect hands-on TypeScript coding.

What should freshers practice?

Freshers should practice navigation, locators, actions, assertions, forms, dropdowns, popups, frames, uploads, and downloads.

What should experienced SDETs practice?

Experienced candidates should focus on POM, fixtures, authentication, API testing, network mocking, test-data management, parallel execution, CI/CD, and framework architecture.

What is the most important coding concept in Playwright?

There is no single answer, but reliable locator design and synchronization are foundational. Playwright describes locators as central to its auto-waiting and retryability model.

How do I prepare for Playwright live coding?

Build small applications or use a public demo application and practice implementing complete workflows without copying code. Focus on explaining your choices while coding.

What is a good Playwright coding challenge for Senior SDET interviews?

A strong challenge combines POM, custom fixtures, authentication, API setup, test-data isolation, network mocking, parallel execution, and CI/CD.

How should I debug a Playwright coding problem?

Start with the failure symptom. Check the locator, application state, synchronization, browser context, network, test data, and environment. Use traces, screenshots, logs, and Playwright Inspector when appropriate.

Should I use CSS or XPath in coding interviews?

You can use them when appropriate, but demonstrate that you know how to select stable user-facing locators. Playwright recommends role, label, text, placeholder, and test-ID strategies before brittle DOM-dependent selectors.

How do I demonstrate senior-level Playwright knowledge?

Do not just produce working code. Explain isolation, maintainability, scalability, failure diagnostics, security, CI performance, and test-data strategy.

Leave a Comment

Your email address will not be published. Required fields are marked *