PRACTICAL GUIDE / TypeScript Playwright interview questions
20 TypeScript Playwright Framework Interview Scenarios
Prepare for TypeScript Playwright interviews with 20 senior scenarios on typed fixtures, configuration contracts, models, narrowing, and review safety.
In this guide9 sections
- Turn Requirements into Contracts
- Core Type Decisions
- 1. Why should strict type checking be enabled for a Playwright framework?
- 2. Why is unknown safer than any for API responses and caught errors?
- 3. Why does declaring response.json as an interface not validate the server response?
- 4. How would a discriminated union improve a payment-status helper?
- Typed Fixtures
- 5. How would you type a fixture that supplies a role-specific dashboard model?
- 6. Why are worker fixtures declared separately from test fixtures?
- 7. How would you design a typed option fixture for locale?
- 8. Why can merging typed fixture modules still be unsafe?
- Models and Domain APIs
- 9. How would you type locators and page dependencies in a page model?
- 10. Why should a framework avoid one universal base page class?
- 11. When are branded identifier types worth using?
- Configuration Contracts
- 12. How would you validate environment variables before building the Playwright config?
- 13. Why use defineConfig rather than exporting an untyped object?
- 14. How would you type custom project metadata used by tests?
- Async and Error Safety
- 15. Why are floating promises especially dangerous in Playwright tests?
- 16. How should a helper report an unknown caught error?
- 17. Why should async helper return types be explicit at framework boundaries?
- Evolution and Code Review
- 18. How would you publish framework types without coupling specs to internals?
- 19. How would you migrate a widely used fixture type?
- 20. What would you inspect in a senior TypeScript Playwright code review?
- TypeScript Interview Checklist
- Make Illegal Usage Obvious
What you will learn
- Turn Requirements into Contracts
- Core Type Decisions
- Typed Fixtures
- Models and Domain APIs
TypeScript interview questions should test more than syntax. In a Playwright framework, types define which fixtures exist, which options are legal, what a model promises, and where untrusted runtime data must be checked. Weak contracts spread uncertainty; overengineered types make ordinary tests harder to read.
The twenty scenarios below focus on design choices a senior SDET makes during implementation and review. For each one, explain the compile-time protection, the runtime behavior TypeScript cannot guarantee, and the maintenance cost of the chosen contract.
Turn Requirements into Contracts
The official Playwright TypeScript guide recommends running a separate type check alongside tests because Playwright can execute TypeScript without acting as a complete project type checker. That is a useful architecture boundary: transpilation enables execution, while CI type analysis enforces the framework's contracts.
Animated field map
Typed Playwright Framework Flow
Translate a framework requirement into a type, expose it through a fixture or model, enforce it at compile time, and review runtime gaps.
01 / framework requirement
Framework requirement
Name valid roles, resources, states, and environment inputs.
02 / type contract
Type contract
Model options, data, results, and ownership without unsafe escape hatches.
03 / fixture model api
Fixture or model API
Expose a small typed boundary to specs and domain modules.
04 / compile safeguard
Compile-time safeguard
Reject invalid calls, missing awaits, and incompatible composition.
05 / code review
Candidate code review
Check runtime validation, lifecycle behavior, and type complexity.
A senior answer avoids both any and ornamental type puzzles. The goal is to make illegal framework usage difficult while leaving the test's business intent easy to read.
Core Type Decisions
1. Why should strict type checking be enabled for a Playwright framework?
Strict checking exposes nullable values, incompatible fixture contracts, unsafe indexing, and incomplete return paths before a browser run. I would introduce it with a measured migration if the suite is large, fixing production test APIs before cosmetic internals. Strictness does not prove locators or data are correct at runtime, but it narrows the class of failures and makes framework refactors safer for many consumers.
2. Why is unknown safer than any for API responses and caught errors?
any disables checking and lets the value flow through the suite with invented properties. unknown requires a parser, type guard, or narrowing step before use. I would validate external JSON at the boundary and narrow caught errors before reading a message. This preserves a truthful distinction between data the framework has verified and data it merely received.
3. Why does declaring response.json as an interface not validate the server response?
Interfaces disappear at runtime. A type assertion can make the compiler trust a shape even when the payload is missing fields or uses the wrong values. I would parse critical test data with runtime validation or explicit guards, then return the validated domain type. For a low-risk local fixture, a smaller guard may be enough. The candidate should match validation effort to consequence.
4. How would a discriminated union improve a payment-status helper?
I would model states such as pending, approved, and declined with a shared discriminant and state-specific fields. A switch can then require exhaustive handling, preventing code from reading an approval ID on a decline. The union should reflect real API semantics rather than every transient implementation detail. If the service adds a state, compilation identifies the framework locations requiring an explicit decision.
Typed Fixtures
5. How would you type a fixture that supplies a role-specific dashboard model?
Define the role as a union, include it as an option fixture, type the dashboard model's constructor, and export the extended test object. Consumers then receive completion and compile-time rejection for invalid roles. I would still validate environment-derived role strings before assigning them. A union protects TypeScript callers; it cannot make arbitrary process input trustworthy by itself.
import { test as base, type Page } from '@playwright/test'
type Role = 'admin' | 'viewer'
class DashboardPage {
constructor(
private readonly page: Page,
readonly role: Role,
) {}
async open(): Promise<void> {
await this.page.goto('/dashboard')
}
}
type Fixtures = {
role: Role
dashboard: DashboardPage
}
export const test = base.extend<Fixtures>({
role: ['viewer', { option: true }],
dashboard: async ({ page, role }, use) => {
await use(new DashboardPage(page, role))
},
})6. Why are worker fixtures declared separately from test fixtures?
Their values have different lifetimes and dependency rules. Declaring the worker map in the appropriate generic makes invalid scope dependencies visible and documents which resources are shared by a process. I would reserve worker scope for expensive resources that are safe to reuse, such as an exclusive account lease. A type can enforce shape and fixture availability, but reviewers must still assess mutation and cleanup.
7. How would you design a typed option fixture for locale?
Use a domain union or validated configuration type for supported locales, provide a sensible default, and allow project or suite overrides through the fixture mechanism. Models can depend on that value without reading environment variables. If the supported list changes frequently, derive the union from a readonly source of truth. Avoid a plain string when only specific values produce a valid test environment.
8. Why can merging typed fixture modules still be unsafe?
Two modules may use the same fixture name with different semantics, trigger hidden setup, or depend on conflicting options even if structural types happen to align. I would enforce unique domain names, expose one composition boundary, and run lifecycle contract tests. TypeScript catches many incompatible shapes; it cannot prove that teardown is idempotent or that requesting one fixture will not mutate another team's state.
Models and Domain APIs
9. How would you type locators and page dependencies in a page model?
Accept a Page in the constructor, type stored locators as Locator, and make stable fields readonly. Methods that complete work return Promise<void> or a meaningful typed result. I would avoid storing element handles because locators re-resolve against current DOM state. The public surface should expose domain operations and only the locators needed for clear scenario assertions.
10. Why should a framework avoid one universal base page class?
A universal class often accumulates unrelated methods, nullable properties, generic type parameters, and inheritance assumptions that do not hold across products. I prefer small composition helpers for shared navigation or diagnostics and cohesive domain models for behavior. Inheritance is appropriate only for a real substitutable contract. If every subclass overrides most methods, the base type is creating ceremony rather than safety.
11. When are branded identifier types worth using?
They help when structurally identical strings, such as account and order IDs, are frequently mixed across APIs with costly consequences. A brand can prevent that at compile time after a validated creation boundary. I would not brand every string in a small suite; conversions and fixtures add friction. Introduce the technique where confusion is recurring and the domain distinction matters to correctness.
Configuration Contracts
12. How would you validate environment variables before building the Playwright config?
Read them once in a configuration module, require mandatory values, parse booleans and numbers explicitly, validate URLs and domain enums, and return a typed immutable object. Fail before test discovery with a safe message that names the missing key but not its secret. Scattered non-null assertions defer configuration errors into unrelated tests and make local, CI, and project behavior difficult to compare.
13. Why use defineConfig rather than exporting an untyped object?
It provides contextual typing and catches misplaced or invalid configuration values while preserving readable configuration code. I would keep runner options at their supported level and browser-context options under use. A typed config still needs behavioral review: a valid worker count can overload CI, and a valid retry value can conceal instability. Schema correctness is the beginning of policy review.
14. How would you type custom project metadata used by tests?
Prefer option fixtures or a validated project configuration extension whose values have an explicit domain type. Tests should consume a typed capability such as environment tier or tenant, not reach into loosely shaped metadata and cast it. I would keep secrets out of report-visible project metadata. The contract should make project differences discoverable while avoiding a second hidden configuration system.
Async and Error Safety
15. Why are floating promises especially dangerous in Playwright tests?
An unawaited action or assertion can continue after the test advances or finishes, so failures become detached, cleanup races with browser work, and a test may pass without checking its outcome. I would use compiler and lint checks for floating promises, review callback signatures, and require explicit handling for intentionally detached work. Most test operations should be awaited at the line where their result matters.
16. How should a helper report an unknown caught error?
Narrow with error instanceof Error, preserve the original error as a cause or attachment where appropriate, and add safe domain context such as the operation and correlation ID. Do not cast blindly or replace the stack with a new generic message. Expected response states should be modeled as typed results when they are not exceptional. The caller needs both a stable contract and useful failure evidence.
17. Why should async helper return types be explicit at framework boundaries?
An explicit Promise<Order> or Promise<void> documents whether a helper returns a capability, completes an action, or may omit a value. It catches accidental return changes that inference might propagate through many consumers. I allow inference inside small private functions, but exported fixtures, clients, and model operations benefit from deliberate contracts. The annotation should describe real behavior rather than force a convenient cast.
Evolution and Code Review
18. How would you publish framework types without coupling specs to internals?
Export the extended test, selected domain types, and stable model interfaces from a small entry point. Keep transport DTOs, helper generics, and fixture implementation details private. I would use type-only imports where suitable and avoid deep imports into domain modules. This makes refactoring possible and gives consumers one supported boundary whose breaking changes can be reviewed intentionally.
19. How would you migrate a widely used fixture type?
I would inventory consumers with the type checker, introduce the new contract with an explicit migration path, update representative domains, and remove compatibility code on a stated schedule. If both shapes coexist, use a discriminant rather than optional fields that permit impossible combinations. Compile the whole repository and run fixture lifecycle tests because a type-correct migration can still alter setup order or resource ownership.
20. What would you inspect in a senior TypeScript Playwright code review?
I would examine unsafe casts, runtime boundaries, fixture scopes, exported APIs, async handling, nullability, model cohesion, environment parsing, and whether generics clarify or obscure usage. Then I would read the failure path: types should lead to actionable setup and assertion errors, not wrap everything in abstraction. I would request simpler code when a clever type costs more comprehension than the invalid states it prevents.
TypeScript Interview Checklist
- Explain what the compiler can prove and what still needs runtime validation.
- Use
unknownat untrusted boundaries and narrow before use. - Type fixture lifetime, options, model inputs, and exported results deliberately.
- Keep model APIs cohesive and avoid inheritance without substitutability.
- Validate environment input once before tests run.
- Catch floating promises with tooling and explicit async contracts.
- Judge type complexity by the real invalid states it prevents.
Make Illegal Usage Obvious
End the interview by drawing the contract from configuration input to fixture, model, and spec. State where runtime validation occurs, what the compiler rejects, and how the API can evolve without exposing internals. Choose strict, small types that make ordinary tests clearer. A strong TypeScript framework does not attempt to encode the whole application; it blocks costly misuse while keeping product intent visible.
// LIVE COURSE / THE TESTING ACADEMY
Playwright Automation Mastery
Go beyond Selenium. Master Playwright with JS/TS in 90 days.
From the instructor behind this guide.
Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.
PRIMARY REFERENCES
Verify the details at the source
QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.
- 01Playwright documentation
Microsoft
Canonical API, locator, fixture, browser, and test-runner behavior.
- 02Playwright best practices
Microsoft
Official guidance for resilient tests, isolation, and user-facing locators.
- 03
FAQ / QUICK ANSWERS
Questions testers ask
Does Playwright require a separate TypeScript compilation step?
Playwright can run TypeScript tests directly, but a separate type-check command is still valuable because execution transpilation does not replace full project type analysis.
Why should external API data be treated as unknown?
A TypeScript annotation cannot validate runtime JSON. Parsing or narrowing unknown data prevents malformed responses from entering the framework under an assumed type.
How are custom Playwright fixtures typed?
Declare test-scoped and worker-scoped fixture maps in the extend generics, type option fixtures with domain unions, and export the resulting test boundary for specs.
Should page-model fields be public?
Expose only the locators or operations consumers need. Private and readonly fields reduce accidental coupling, while selected public locators can support clear scenario assertions.
What TypeScript mistake causes many silent Playwright failures?
Floating promises are especially dangerous. Missing await on actions or async assertions can let a test continue or finish before the intended work settles.
RELATED GUIDES
Continue the learning route
GUIDE 01
Strict TypeScript Patterns for Playwright Fixtures, Models, and Test Data
Apply strict TypeScript to Playwright fixtures, models, environment data, and case tables with compiler checks, runtime validation, and safe narrowing.
GUIDE 02
Type-Safe Environment Configuration for Playwright Test
Create type-safe Playwright environment configuration with validated inputs, explicit base URLs, protected secrets, and predictable CI commands.
GUIDE 03
Composing Modular Playwright Fixtures with mergeTests and Boxed Steps
Compose modular Playwright fixtures with mergeTests, explicit dependency ownership, boxed reporting, and a stable test-support import surface.
GUIDE 04
How to Build a Test Automation Framework from Scratch
Learn how to build a test automation framework from scratch with layers, design patterns, reporting, CI/CD hooks, and a practical starter architecture.