SoftwareTestPilot
24 Q&A

Playwright TypeScript Interview Questions and Answers (24 with Code)

24 Playwright TypeScript interview questions with answers: typed fixtures, interfaces, generics, async/await, error handling, page objects, plus code-reading and debugging exercises.

  • 12 min read
  • Difficulty: Mixed (Easy → Hard)
  • Freshers → Experienced
  • Updated October 16, 2026
  • SoftwareTestPilot
SoftwareTestPilot
QA Editorial Team
Published:
0 / 24 reviewed
0%

TypeScript basics in a Playwright project

Hard Very Common 1 minQ1 / 24

Q1.Why use TypeScript instead of JavaScript for Playwright tests?

Asked byAirbnbShopifyUberStripe
Why interviewers ask this

"Why" questions on use TypeScript instead of JavaScript for Playwright tests probe your reasoning, not your memory. Strong candidates connect the choice to a business or reliability outcome — flaky tests, slower feedback loop, or missed defects — instead of parroting a rule.

Detailed explanation

Answer: TypeScript catches a class of mistakes before the test runs: a misspelled fixture name, a wrong argument type, a missing property on test data, or calling a method that a page object does not have. Playwright ships its own type definitions, so editors give accurate autocomplete for page, Locator and expect. In a large suite this matters more than in a small one, because refactoring a page object safely depends on the compiler finding every caller.

Reasoning: A good answer ties types to test maintenance, not to general opinions about languages. Mention the cost too: a build step for type-checking and some learning time for the team.

Follow-up: "Does Playwright type-check my tests when I run them?" No. Playwright transpiles TypeScript and strips the types; it does not report type errors. Run npx tsc --noEmit separately, usually as a CI step before the tests.

// package.json scripts (example)
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "test": "npm run typecheck && playwright test"
  }
}
Tips to remember
  • Tie the "why" for use TypeScript instead of JavaScript for Playwright tests back to a measurable outcome — flake rate, execution time, defect leakage — instead of an opinion.
  • Be ready to whiteboard the use TypeScript instead of JavaScript for Playwright tests snippet live — panels often ask you to type it, not describe it.
  • Add one sentence on what does NOT belong in a page object (assertions, test data) — that boundary is what separates mid from senior answers.
RelatedQ3
Hard Very Common 1 minQ2 / 24

Q2.What tsconfig settings matter for a Playwright project?

Asked byGoogleAirbnbShopifyUber
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on What tsconfig settings matter for a Playwright project and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: strict: true is the important one, because it turns on strictNullChecks and noImplicitAny, which catch the bugs you actually care about in tests. A modern target such as ES2022 keeps async/await native. Path aliases through paths help imports such as @pages/LoginPage, and Playwright respects the paths in your tsconfig.

Weak answer: "We turned strict off because it showed too many errors." That usually means the errors were real.

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": { "@pages/*": ["pages/*"], "@fixtures/*": ["fixtures/*"] }
  },
  "include": ["tests", "pages", "fixtures", "playwright.config.ts"]
}
Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on What tsconfig settings matter for a Playwright project over textbook wording.
  • Be ready to whiteboard the What tsconfig settings matter for a Playwright project snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Hard Very Common 1 minQ3 / 24

Q3.What is the difference between an interface and a type alias, and which do you use for test data?

Asked byUberStripeMicrosoftAdobe
Why interviewers ask this

Interviewers open with "difference between an interface and a type alias, and which do you use for test data" to confirm you can define the concept in one crisp line before going deeper. In Playwright rounds this filters out candidates who only remember syntax and can't articulate the underlying idea to a non-expert teammate.

Detailed explanation

Answer: Both describe the shape of an object. Interfaces can be extended with extends and merged by redeclaring them; type aliases can also express unions, intersections and mapped types. For plain test data and API payloads either works. Many teams use interfaces for object shapes and type aliases for unions such as type Role = 'admin' | 'viewer'. The important thing is consistency, not the choice.

type Role = 'admin' | 'editor' | 'viewer';

interface TestUser {
  email: string;
  password: string;
  role: Role;
  displayName?: string; // optional
}

const viewer: TestUser = {
  email: 'viewer@example.test',
  password: process.env.VIEWER_PASSWORD ?? '',
  role: 'viewer',
};

Note the placeholder environment variable: never commit real credentials in test data files.

Tips to remember
  • Open with a one-sentence definition of difference between an interface and a type alias, and which do you use for test data, then a concrete Playwright example — never start with history or theory.
  • Be ready to whiteboard the difference between an interface and a type alias, and which do you use for test data snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Confidence check

If you can confidently answer the TypeScript basics in a Playwright project questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Typed fixtures with test.extend

Hard Very Common 1 minQ4 / 24

Q4.How do you create a typed custom fixture?

Asked byShopifyUberStripeMicrosoft
Why interviewers ask this

Hands-on "how would you create a typed custom fixture" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: Declare a type that lists the fixtures, pass it as the generic argument to test.extend, and implement each fixture as an async function that receives existing fixtures and a use callback. Code before use is setup, code after it is teardown. Tests then import this extended test, and the compiler knows every fixture's type.

// fixtures/test.ts
import { test as base, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
import { CartPage } from '../pages/CartPage';

type ShopFixtures = {
  loginPage: LoginPage;
  cartPage: CartPage;
};

export const test = base.extend<ShopFixtures>({
  loginPage: async ({ page }, use) => {
    await use(new LoginPage(page));
  },
  cartPage: async ({ page }, use) => {
    await use(new CartPage(page));
  },
});

export { expect };
// tests/cart.spec.ts
import { test, expect } from '../fixtures/test';

test('adds an item to the cart', async ({ cartPage }) => {
  await cartPage.open();
  await cartPage.addItem('Blue mug');
  await expect(cartPage.itemCount).toHaveText('1');
});

Follow-up: "What happens if you misspell cartPage in the test signature?" The compiler reports that the property does not exist on the fixtures type. In plain JavaScript the test would fail at runtime instead.

Tips to remember
  • Walk through create a typed custom fixture as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the create a typed custom fixture snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Hard Very Common 1 minQ5 / 24

Q5.How do you type a worker-scoped fixture?

Asked byMicrosoftAdobeNetflixGoogle
Why interviewers ask this

Hands-on "how would you type a worker-scoped fixture" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: test.extend takes two type parameters: test-scoped fixtures first, worker-scoped fixtures second. A worker fixture is declared as a tuple with { scope: 'worker' }, and it can only depend on other worker fixtures, not on page. Use it for expensive setup that can be shared by every test in one worker process, such as creating a test account once.

import { test as base } from '@playwright/test';

type WorkerFixtures = { accountEmail: string };

export const test = base.extend<{}, WorkerFixtures>({
  accountEmail: [async ({}, use, workerInfo) => {
    // Fictional helper that calls a local test API.
    const email = 'qa+' + workerInfo.workerIndex + '@example.test';
    await createAccount(email);
    await use(email);
    await deleteAccount(email);
  }, { scope: 'worker' }],
});

Weak answer: making a fixture worker-scoped just for speed when tests change its state. Shared mutable state across tests in one worker causes order-dependent failures.

Tips to remember
  • Walk through type a worker-scoped fixture as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the type a worker-scoped fixture snippet live — panels often ask you to type it, not describe it.
  • Call out test isolation and shared-state risk (data, sessions, ports) before you talk about worker counts.
Hard Very Common 1 minQ6 / 24

Q6.How do you add typed configuration options to fixtures?

Asked byStripeMicrosoftAdobeNetflix
Why interviewers ask this

Hands-on "how would you add typed configuration options to fixtures" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: Declare an option fixture with { option: true } and a default value. Projects in playwright.config.ts can then override it, and the config is type-checked against the option type when you pass the generic to defineConfig.

// fixtures/test.ts
import { test as base } from '@playwright/test';

export type ShopOptions = { locale: 'en-IN' | 'en-US' };

export const test = base.extend<ShopOptions>({
  locale: ['en-IN', { option: true }],
});

// playwright.config.ts
import { defineConfig } from '@playwright/test';
import type { ShopOptions } from './fixtures/test';

export default defineConfig<ShopOptions>({
  projects: [
    { name: 'india', use: { locale: 'en-IN' } },
    { name: 'us', use: { locale: 'en-US' } },
  ],
});

Here locale is our own custom option, which is why its type is a narrow union; a typo such as 'en-UK' would fail type-checking.

Tips to remember
  • Walk through add typed configuration options to fixtures as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the add typed configuration options to fixtures snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Medium Very Common 1 minQ7 / 24

Q7.How do you combine fixtures from several files?

Asked byNetflixGoogleAirbnbShopify
Why interviewers ask this

Hands-on "how would you combine fixtures from several files" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: Use mergeTests to combine extended test objects, and mergeExpects for custom matchers. Each module stays small and owned by one area, and the merged object keeps all the types.

import { mergeTests } from '@playwright/test';
import { test as pageFixtures } from './pages.fixtures';
import { test as apiFixtures } from './api.fixtures';

export const test = mergeTests(pageFixtures, apiFixtures);
Tips to remember
  • Walk through combine fixtures from several files as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the combine fixtures from several files snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Confidence check

If you can confidently answer the Typed fixtures with test.extend questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Interfaces, generics and test data

Hard Very Common 1 minQ8 / 24

Q8.How do you type an API response in a Playwright API test?

Asked byAdobeNetflixGoogleAirbnb
Why interviewers ask this

Hands-on "how would you type an API response in a Playwright API test" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: Describe the expected shape with an interface and annotate the parsed JSON. Be honest about the limit: response.json() returns Promise<any> at runtime, so the annotation is a promise you are making to the compiler, not a check. For important contracts, validate the body at runtime as well, with assertions or a schema library.

import { test, expect } from '@playwright/test';

interface Product {
  id: number;
  name: string;
  priceInPaise: number;
}

test('product endpoint returns a valid product', async ({ request }) => {
  const res = await request.get('/api/products/42');
  expect(res.ok()).toBeTruthy();

  const product: Product = await res.json();
  expect(product).toEqual(expect.objectContaining({
    id: 42,
    name: expect.any(String),
    priceInPaise: expect.any(Number),
  }));
});

For more on the request fixture, see our Playwright API testing interview questions.

Tips to remember
  • Walk through type an API response in a Playwright API test as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the type an API response in a Playwright API test snippet live — panels often ask you to type it, not describe it.
  • Tie contract checks to the consumer/provider workflow and where the contract is stored — that's the senior detail panels wait for.
Hard Very Common 1 minQ9 / 24

Q9.Write a small generic helper that would be useful in a test suite.

Asked byAirbnbShopifyUberStripe
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on Write a small generic helper that would be useful in a test suite and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: A typed GET helper is a common example: one type parameter describes the body, so each caller gets the right type back without casting at every call site.

import type { APIRequestContext } from '@playwright/test';
import { expect } from '@playwright/test';

export async function getJson<T>(request: APIRequestContext, url: string): Promise<T> {
  const res = await request.get(url);
  expect(res.ok(), 'GET ' + url + ' returned ' + res.status()).toBeTruthy();
  return (await res.json()) as T;
}

// usage
const product = await getJson<Product>(request, '/api/products/42');
product.priceInPaise; // typed as number

Follow-up: "Is that as T safe?" Not fully: it trusts the server. Say that, and mention adding runtime validation for critical endpoints.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on Write a small generic helper that would be useful in a test suite over textbook wording.
  • Be ready to whiteboard the Write a small generic helper that would be useful in a test suite snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Medium Common 1 minQ10 / 24

Q10.How do generics and utility types help with test data builders?

Asked byGoogleAirbnbShopifyUber
Why interviewers ask this

Hands-on "how would you How do generics and utility types help with test data builders" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: A builder that accepts Partial<T> lets each test override only the fields it cares about while the defaults stay valid. Pick, Omit and Required help describe variations, such as a create payload that omits the server-generated id.

type NewProduct = Omit<Product, 'id'>;

export function buildProduct(overrides: Partial<NewProduct> = {}): NewProduct {
  return {
    name: 'Test mug ' + Date.now(),
    priceInPaise: 49900,
    ...overrides,
  };
}

const freeItem = buildProduct({ priceInPaise: 0 }); // edge-case data in one line
Tips to remember
  • Walk through How do generics and utility types help with test data builders as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the How do generics and utility types help with test data builders snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Medium Common 1 minQ11 / 24

Q11.When would you use unknown instead of any?

Asked byUberStripeMicrosoftAdobe
Why interviewers ask this

Timing questions like this check whether you understand the trade-offs of use unknown instead of any. Interviewers want to hear the specific signals in a project that make you pick it over the alternative, plus one case where it's the wrong choice.

Detailed explanation

Answer: Whenever the type is genuinely not known, such as a value from page.evaluate, a parsed file or a caught error. any switches checking off; unknown forces you to narrow the value before using it, so mistakes stay visible.

const raw: unknown = await page.evaluate(() => window.localStorage.getItem('cart'));
if (typeof raw === 'string') {
  const cart = JSON.parse(raw) as { items: string[] };
  expect(cart.items.length).toBeGreaterThan(0);
}

Weak answer: "We use any for API responses because they change." That hides breaking changes instead of catching them.

Tips to remember
  • Answer in the form "Use use unknown instead of any when …, avoid it when …" so the interviewer hears both sides in one breath.
  • Be ready to whiteboard the use unknown instead of any snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Confidence check

If you can confidently answer the Interfaces, generics and test data questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Promises, async/await and error handling

Medium Common 1 minQ12 / 24

Q12.Why does almost every Playwright line start with await?

Asked byShopifyUberStripeMicrosoft
Why interviewers ask this

"Why" questions on es almost every Playwright line start with await probe your reasoning, not your memory. Strong candidates connect the choice to a business or reliability outcome — flaky tests, slower feedback loop, or missed defects — instead of parroting a rule.

Detailed explanation

Answer: Playwright talks to the browser over a protocol, so actions such as click, fill and goto return Promises. await pauses the test until the action finishes. Creating a Locator, however, is synchronous: page.getByRole('button') just describes how to find the element, so it does not need await.

const submit = page.getByRole('button', { name: 'Place order' }); // no await: just a description
await submit.click();                                              // await: talks to the browser
await expect(page.getByText('Order confirmed')).toBeVisible();     // await: web-first assertion retries
Tips to remember
  • Tie the "why" for es almost every Playwright line start with await back to a measurable outcome — flake rate, execution time, defect leakage — instead of an opinion.
  • Be ready to whiteboard the es almost every Playwright line start with await snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Medium Common 1 minQ13 / 24

Q13.What happens if you forget await on a web-first assertion?

Asked byMicrosoftAdobeNetflixGoogle
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on What happens if you forget await on a web-first assertion and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: The assertion starts but the test does not wait for it. The test can finish and pass before the check completes, and a failure may surface later as a confusing error or not at all. Enable the @typescript-eslint/no-floating-promises lint rule so the mistake is flagged automatically.

Reasoning: This is a favourite because it shows whether you understand that expect(locator).toBeVisible() returns a Promise, while expect(value).toBe(1) does not.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on What happens if you forget await on a web-first assertion over textbook wording.
  • Be ready to whiteboard the What happens if you forget await on a web-first assertion snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Hard Common 1 minQ14 / 24

Q14.How do you wait for a response that is triggered by a click?

Asked byStripeMicrosoftAdobeNetflix
Why interviewers ask this

Hands-on "how would you wait for a response that is triggered by a click" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: Start waiting before the action, then await both. Creating the wait promise first avoids a race where the response arrives before you begin listening.

const responsePromise = page.waitForResponse(
  (res) => res.url().includes('/api/orders') && res.request().method() === 'POST'
);
await page.getByRole('button', { name: 'Place order' }).click();
const response = await responsePromise;
expect(response.status()).toBe(201);

Follow-up: "When would you use Promise.all?" For truly independent work, such as creating two unrelated test records through the API. Do not use it for steps that must happen in order on the same page.

Tips to remember
  • Walk through wait for a response that is triggered by a click as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the wait for a response that is triggered by a click snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Medium Common 1 minQ15 / 24

Q15.How should you handle errors in Playwright tests?

Asked byNetflixGoogleAirbnbShopify
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on How should you handle errors in Playwright tests and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: Mostly by not catching them. A thrown error is how a test fails, and Playwright attaches the trace and screenshot. Use try/finally for cleanup that a fixture cannot do, and catch only when you can add useful context and rethrow. For clearer failures, add a custom message to expect or group actions with test.step.

await test.step('apply coupon', async () => {
  await page.getByLabel('Coupon code').fill('SAVE10');
  await page.getByRole('button', { name: 'Apply' }).click();
  await expect(page.getByTestId('discount'), 'coupon should reduce the total').toBeVisible();
});
Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on How should you handle errors in Playwright tests over textbook wording.
  • Be ready to whiteboard the How should you handle errors in Playwright tests snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Medium Common 1 minQ16 / 24

Q16.How do you narrow a caught error in TypeScript?

Asked byAdobeNetflixGoogleAirbnb
Why interviewers ask this

Hands-on "how would you narrow a caught error in TypeScript" questions reveal whether you've actually shipped Playwright code or only read about it. Interviewers listen for concrete steps, the tools you'd reach for first, and the failure mode you'd guard against.

Detailed explanation

Answer: With strict mode, the variable in catch is typed unknown by default (useUnknownInCatchVariables). Check instanceof Error before reading message, and rethrow anything you did not expect.

try {
  await seedOrders(request);
} catch (err) {
  const reason = err instanceof Error ? err.message : String(err);
  throw new Error('Could not seed orders for the checkout test: ' + reason);
}

Weak answer: catch (e: any) { console.log(e) } with no rethrow. The test keeps going in a broken state and fails somewhere unrelated, or passes when it should not.

Tips to remember
  • Walk through narrow a caught error in TypeScript as numbered steps and call out the tool, command, or API used at each step.
  • Be ready to whiteboard the narrow a caught error in TypeScript snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Confidence check

If you can confidently answer the Promises, async/await and error handling questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Typed page-object design

Hard Common 1 minQ17 / 24

Q17.Show a well-typed page object.

Asked byAirbnbShopifyUberStripe
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on Show a well-typed page object and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: A class that takes a Page in its constructor, exposes readonly Locators for elements tests need to check, and async methods for user actions. Methods return Promise<void> or a typed value. Most assertions stay in the test so the intent is visible there.

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

export class LoginPage {
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;
  readonly errorMessage: Locator;

  constructor(private readonly page: Page) {
    this.emailInput = page.getByLabel('Email');
    this.passwordInput = page.getByLabel('Password');
    this.submitButton = page.getByRole('button', { name: 'Sign in' });
    this.errorMessage = page.getByRole('alert');
  }

  async open(): Promise<void> {
    await this.page.goto('/login');
  }

  async signIn(email: string, password: string): Promise<void> {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}
Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on Show a well-typed page object over textbook wording.
  • Be ready to whiteboard the Show a well-typed page object snippet live — panels often ask you to type it, not describe it.
  • Add one sentence on what does NOT belong in a page object (assertions, test data) — that boundary is what separates mid from senior answers.
Hard Occasional 1 minQ18 / 24

Q18.Inheritance or composition for page objects?

Asked byGoogleAirbnbShopifyUber
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on Inheritance or composition for page objects and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: Prefer composition. A shallow base class for truly shared behaviour is fine, but deep hierarchies make changes risky. Shared UI pieces such as a header or a date picker work better as component classes that a page owns.

export class HeaderComponent {
  constructor(private readonly root: Locator) {}
  readonly cartBadge = () => this.root.getByTestId('cart-count');
  async search(term: string): Promise<void> {
    await this.root.getByRole('searchbox').fill(term);
    await this.root.getByRole('searchbox').press('Enter');
  }
}

export class ProductListPage {
  readonly header: HeaderComponent;
  constructor(private readonly page: Page) {
    this.header = new HeaderComponent(page.getByRole('banner'));
  }
}
Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on Inheritance or composition for page objects over textbook wording.
  • Be ready to whiteboard the Inheritance or composition for page objects snippet live — panels often ask you to type it, not describe it.
  • Add one sentence on what does NOT belong in a page object (assertions, test data) — that boundary is what separates mid from senior answers.
Medium Occasional 1 minQ19 / 24

Q19.Should a page-object method return the next page object?

Asked byUberStripeMicrosoftAdobe
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on Should a page-object method return the next page object and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: It can, and typing helps: async signIn(...): Promise<DashboardPage> tells callers where they land. The trade-off is coupling, because a login that can end on different pages makes the return type awkward. With fixtures, many teams skip chaining and inject each page object directly. Either is defensible if you explain the trade-off.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on Should a page-object method return the next page object over textbook wording.
  • Be ready to whiteboard the Should a page-object method return the next page object snippet live — panels often ask you to type it, not describe it.
  • Add one sentence on what does NOT belong in a page object (assertions, test data) — that boundary is what separates mid from senior answers.
Confidence check

If you can confidently answer the Typed page-object design questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Code-reading questions

Hard Occasional 1 minQ20 / 24

Q20.What is wrong with this test?

Asked byShopifyUberStripeMicrosoft
Why interviewers ask this

Interviewers open with "wrong with this test" to confirm you can define the concept in one crisp line before going deeper. In Playwright rounds this filters out candidates who only remember syntax and can't articulate the underlying idea to a non-expert teammate.

Detailed explanation
test('shows welcome message', async ({ page }) => {
  await page.goto('/login');
  page.getByLabel('Email').fill('viewer@example.test');
  await page.getByLabel('Password').fill(process.env.VIEWER_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  expect(page.getByText('Welcome back')).toBeVisible();
});

Answer: Two missing awaits. The email fill may not finish before the password field is filled, and the final assertion is never awaited, so the test can pass without checking anything. The non-null assertion ! on the environment variable also hides a missing value: if it is unset, the test sends undefined and fails with a misleading login error. Read it once with a clear failure message instead.

Tips to remember
  • Open with a one-sentence definition of wrong with this test, then a concrete Playwright example — never start with history or theory.
  • Be ready to whiteboard the wrong with this test snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Hard Occasional 1 minQ21 / 24

Q21.What will TypeScript say about this fixture, and why?

Asked byMicrosoftAdobeNetflixGoogle
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on What will TypeScript say about this fixture, and why and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation
type Fixtures = { adminPage: Page };

export const test = base.extend<Fixtures>({
  adminPage: async ({ browser }, use) => {
    const context = await browser.newContext({ storageState: 'auth/admin.json' });
    const page = context.newPage();
    await use(page);
    await context.close();
  },
});

Answer: context.newPage() returns Promise<Page>, and use expects a Page, so the compiler reports a type mismatch. That is TypeScript catching a real bug: without await, the test would receive a Promise instead of a page. The fix is const page = await context.newPage();. Closing the context after use is correct teardown.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on What will TypeScript say about this fixture, and why over textbook wording.
  • Be ready to whiteboard the What will TypeScript say about this fixture, and why snippet live — panels often ask you to type it, not describe it.
  • Explain setup/teardown ordering and what runs per-test vs per-suite; ordering mistakes are the follow-up question.
Confidence check

If you can confidently answer the Code-reading questions questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Debugging exercises

Medium Occasional 1 minQ22 / 24

Q22.Tests pass locally but fail in CI with "Cannot find module '@pages/LoginPage'". How do you debug it?

Asked byStripeMicrosoftAdobeNetflix
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on Tests pass locally but fail in CI with "Cannot find module '@pages/LoginPage'". How do you debug it and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: This is an import-resolution problem, not a test logic problem. Check that tsconfig.json defines the paths alias and a matching baseUrl, that the file name casing matches exactly (local macOS or Windows file systems may be case-insensitive, Linux CI runners are not), and that the tsconfig Playwright picks up is the one you expect. A loginPage.ts file imported as LoginPage is the classic cause.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on Tests pass locally but fail in CI with "Cannot find module '@pages/LoginPage'". How do you debug it over textbook wording.
  • Be ready to whiteboard the Tests pass locally but fail in CI with "Cannot find module '@pages/LoginPage'". How do you debug it snippet live — panels often ask you to type it, not describe it.
  • Mention auto-waiting, user-facing locators, or trace viewer — one of those three usually earns a follow-up.
Hard Occasional 1 minQ23 / 24

Q23.A custom fixture's teardown never runs and test data piles up. What do you check?

Asked byNetflixGoogleAirbnbShopify
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on A custom fixture's teardown never runs and test data piles up. What do you check and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: First, whether the fixture actually calls await use(...); code after it only runs once the test finishes. Second, whether setup threw before use, in which case teardown is skipped and setup itself must clean partial state. Third, whether the cleanup call is awaited. A missing await on a delete request lets the worker move on before the request completes.

order: async ({ request }, use) => {
  const res = await request.post('/api/orders', { data: buildOrder() });
  const order = (await res.json()) as { id: string };
  await use(order);
  await request.delete('/api/orders/' + order.id); // awaited teardown
},
Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on A custom fixture's teardown never runs and test data piles up. What do you check over textbook wording.
  • Be ready to whiteboard the A custom fixture's teardown never runs and test data piles up. What do you check snippet live — panels often ask you to type it, not describe it.
  • Call out test isolation and shared-state risk (data, sessions, ports) before you talk about worker counts.
Medium Occasional 1 minQ24 / 24

Q24.After a refactor, a page-object method compiles but the test times out on a click. How do you narrow it down?

Asked byAdobeNetflixGoogleAirbnb
Why interviewers ask this

This Playwright question checks whether you can go beyond textbook knowledge on After a refactor, a page-object method compiles but the test times out on a click. How do you narrow it down and reason about it the way a working QA engineer does — with a definition, an example, and the edge case that usually comes up next.

Detailed explanation

Answer: The compiler only proves the code fits the types, not that the locator matches the page. Run the test with --debug or open the trace with npx playwright show-trace, look at the action log for the step that waited, and check the DOM snapshot at that moment. Usual causes: a locator now matching zero or several elements, an accessible name that changed, or an element inside a new iframe that needs frameLocator. Fix the locator rather than adding force: true or a fixed timeout.

Tips to remember
  • Anchor the answer in a real Playwright project — panels reward specificity on After a refactor, a page-object method compiles but the test times out on a click. How do you narrow it down over textbook wording.
  • Be ready to whiteboard the After a refactor, a page-object method compiles but the test times out on a click. How do you narrow it down snippet live — panels often ask you to type it, not describe it.
  • Finish by saying you always return to the default content after frame work — forgetting that is the classic failure this question hunts for.
RelatedQ22
Confidence check

If you can confidently answer the Debugging exercises questions above, you're well prepared for this section of your interview. Move on, or rehearse the trickier ones aloud with our AI mock interviewer.

Quick revision

  1. Q1: Why use TypeScript instead of JavaScript for Playwright tests — Answer: TypeScript catches a class of mistakes before the test runs: a misspelled fixture name, a wrong argument type, a missing property on test data, or calling a method that a p
  2. Q2: What tsconfig settings matter for a Playwright project — Answer: strict: true is the important one, because it turns on strictNullChecks and noImplicitAny , which catch the bugs you actually care about in tests.
  3. Q3: What is the difference between an interface and a type alias, and which do you use for test data — Answer: Both describe the shape of an object.
  4. Q4: How do you create a typed custom fixture — Answer: Declare a type that lists the fixtures, pass it as the generic argument to test.extend , and implement each fixture as an async function that receives existing fixtures and
  5. Q5: How do you type a worker-scoped fixture — Answer: test.extend takes two type parameters: test-scoped fixtures first, worker-scoped fixtures second.

Playwright automation jobs hiring now

Live, indexable Playwright openings — updated daily in Jobs Radar.

Browse all QA jobs on Jobs Radar

Loading current openings…

Home

References

  1. 1
    Playwright: Fixtures— playwright.dev
  2. 2
    Playwright: TypeScript— playwright.dev
  3. 3
  4. 4
    TypeScript Handbook: Generics— typescriptlang.org
  5. 5
    TypeScript Handbook: Narrowing— typescriptlang.org

Discussion

Ask a question, share your experience, or correct us. Be kind — real people are reading.