Resource library

QA Interview

Playwright API Testing Interview Questions (2026)

Study Playwright API testing interview questions with 46 practical answers on request contexts, authentication, contracts, mocking, fixtures, and CI.

24 min read | 4,379 words

TL;DR

Playwright API interviews test whether you can use APIRequestContext correctly, validate contracts and business behavior, manage authentication and data, combine API and UI checks, and operate the suite reliably in CI. Strong answers name the boundary being tested, show precise assertions, and explain isolation and failure diagnostics.

Key Takeaways

  • Explain APIRequestContext lifecycle, cookie isolation, and disposal instead of treating request as a generic HTTP helper.
  • Assert status, headers, schema, and business invariants because a 2xx response alone proves little.
  • Use API calls for fast setup while preserving focused browser coverage for critical user journeys.
  • Design parallel-safe data with unique identifiers, explicit ownership, and idempotent cleanup.
  • Separate request mocking from direct API testing and state which boundary each technique validates.
  • Debug with sanitized request and response evidence, traces, correlation IDs, and controlled retries.
  • Frame senior answers around risk, tradeoffs, observability, and measurable feedback quality.

Playwright API testing interview questions assess more than whether you can call request.get(). Interviewers want to know if you can build trustworthy service checks, create browser prerequisites efficiently, protect credentials, diagnose failures, and choose the right boundary for each risk.

This interview hub contains 46 questions with model answers and current TypeScript examples. Use the answers as reasoning patterns, then adapt the details to systems you have actually tested. For broader foundations, compare this guide with the API testing interview questions guide and practice realistic delivery in the QA interview simulator.

TL;DR

Topic What your answer should prove
Request contexts You understand lifecycle, configuration, cookies, and disposal
Assertions You validate protocol, contract, and business meaning
Authentication You can handle tokens and shared state without leaking secrets
Data Your tests remain independent under parallel execution
API plus UI You know when API setup helps and when it hides risk
Mocking You distinguish browser routing from direct service validation
CI Failures are reproducible, observable, and owned

A convincing response usually identifies the test boundary, gives a concrete Playwright implementation, and names one tradeoff. Avoid claiming that every API check belongs in an end-to-end suite.

1. Playwright API Testing Interview Questions: Core Concepts

Q: What API testing capabilities does Playwright provide?

Playwright Test exposes an APIRequestContext through the built-in request fixture and through playwright.request.newContext(). It can send HTTP methods, serialize JSON or form data, attach headers, and return an APIResponse for status, headers, text, body, or JSON inspection. The same tooling can prepare server state for browser tests or test an HTTP service directly. I would still add schema or domain-specific validation because Playwright is the transport and runner, not a complete contract-testing platform.

Q: What is APIRequestContext?

APIRequestContext is an isolated HTTP client context with configuration such as baseURL, extraHTTPHeaders, credentials, proxy settings, and cookie storage. Requests made through it can retain cookies returned by the server, which enables session-based flows. A context created manually should be disposed when its work finishes so stored response bodies and related resources are released. Its lifecycle should match the data and authentication boundary of the tests using it.

Q: How does the built-in request fixture differ from playwright.request.newContext()?

The request fixture is managed by Playwright Test and is convenient when each test needs an isolated client. playwright.request.newContext() gives explicit control and is useful in setup scripts or custom fixtures with a deliberate scope. With the manual form, I use try/finally or fixture teardown to call dispose(). I choose based on ownership and lifecycle, not because one sends better HTTP requests.

Q: How is direct API testing different from intercepting a browser request?

Direct API testing sends a request from APIRequestContext to a server and validates the real service response. Browser interception with page.route() observes, modifies, aborts, or fulfills traffic initiated by a page. The first tests the API boundary; the second controls a dependency while testing browser behavior. Confusing them can produce a mocked UI test that is incorrectly reported as backend coverage.

Q: Why use Playwright for API tests instead of a separate library?

Using one runner can share fixtures, configuration, reporters, parallelism, and artifacts across API and browser checks. It is especially effective when API calls create prerequisites for a focused UI scenario. A dedicated client or contract tool may be better when the service suite needs generated clients, deep OpenAPI validation, consumer contracts, or specialized load behavior. The decision should reduce operational complexity without forcing every testing need into one abstraction.

2. Requests, Responses, and Assertions

Q: Show a basic GET test with meaningful assertions.

The test should validate more than status by checking content type and a domain property. Parse JSON only after confirming that the response represents JSON, which makes an HTML gateway error easier to diagnose. Use a stable test record rather than assuming production-like data exists.

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

test('returns the requested customer', async ({ request }) => {
  const response = await request.get('/api/customers/cus-42');
  expect(response.status()).toBe(200);
  expect(response.headers()['content-type']).toContain('application/json');
  const customer = await response.json();
  expect(customer).toMatchObject({ id: 'cus-42', status: 'active' });
  expect(customer.email).toMatch(/@/);
});

Q: What should you assert besides a 200 status?

Assert the exact acceptable status, media type, required headers, response shape, and business invariants relevant to the scenario. For a created order, that might include a nonempty ID, the requested line items, a server-calculated total, and a retrievable location. Avoid asserting volatile values such as timestamps down to the millisecond unless the contract requires that precision. Every assertion should distinguish a meaningful defect from harmless implementation variation.

Q: How do you test a POST request with JSON data?

Pass a plain object through the data option and Playwright serializes it as JSON when appropriate. Assert 201 for a creation contract if that is the documented behavior, then verify both the representation and persisted state. A follow-up GET catches services that echo the request but fail to commit it.

test('creates and persists a project', async ({ request }) => {
  const create = await request.post('/api/projects', {
    data: { name: 'Release audit', ownerId: 'usr-7' },
  });
  expect(create.status()).toBe(201);
  const project = await create.json();
  expect(project.id).toEqual(expect.any(String));

  const read = await request.get(`/api/projects/${project.id}`);
  expect(read.status()).toBe(200);
  await expect(read).toBeOK();
  expect(await read.json()).toMatchObject({ name: 'Release audit', ownerId: 'usr-7' });
});

Q: When would you use response.ok() or expect(response).toBeOK()?

Both express success across the 200 through 299 range, with toBeOK() integrating naturally into Playwright assertions. I use them when any documented success code is acceptable, such as an endpoint that legitimately returns either 200 or 204. When the status itself is part of the contract, I assert the exact code instead. Broad success checks should not hide an accidental change from synchronous 201 creation to an undocumented 200.

Q: How do you validate headers and cookies?

Read normalized response headers through headers() or use headersArray() when duplicate header entries matter. For cookies, inspect the context storage state or verify the next authenticated request succeeds, because the observable session behavior is often more valuable than matching the entire Set-Cookie string. Security-sensitive tests can check required attributes such as HttpOnly, Secure, and an expected SameSite policy. Do not log complete session cookies into CI artifacts.

3. Authentication and Authorization

Q: How do you test a bearer-token API?

Create a context with an Authorization header or pass the header on a specific request when identities vary. Obtain the token through an approved test identity flow, keep it in a secret store, and never commit it. I also add negative checks for missing, malformed, expired, and insufficient-scope tokens. Authentication proves identity, while those authorization scenarios prove access boundaries.

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

test('reader can view but cannot delete reports', async ({ playwright }) => {
  const api = await playwright.request.newContext({
    baseURL: process.env.API_URL,
    extraHTTPHeaders: { Authorization: `Bearer ${process.env.READER_TOKEN}` },
  });
  try {
    await expect(await api.get('/reports/rpt-8')).toBeOK();
    expect((await api.delete('/reports/rpt-8')).status()).toBe(403);
  } finally {
    await api.dispose();
  }
});

Q: How would you test role-based access control?

Build a small matrix of roles, resources, and operations from the authorization policy rather than duplicating happy paths. Give each role its own context and attempt allowed plus denied actions against owned and unowned records. Assert 401 for unauthenticated requests and the product's documented 403 or concealment-style 404 for forbidden resources. Include a server-state check so a rejected write is proven not to have changed data.

Q: Can API and browser contexts share authentication?

The request context associated with a browser context can share cookie storage with that browser context, enabling API login followed by authenticated page navigation. A separately created APIRequestContext has independent storage unless you explicitly transfer storage state. This distinction matters because accidental cookie sharing can make isolation tests pass for the wrong reason. I state which identity owns each context and verify it with a small authenticated endpoint.

Q: How do you protect credentials in API tests?

Load secrets from the CI secret manager or environment, restrict their permissions, and use dedicated nonproduction identities. Redact authorization headers, cookies, and sensitive response fields from logs and attachments. Rotate credentials on a schedule and immediately after suspected exposure. Tests should fail clearly when a required secret is absent, without printing the secret value.

Q: How would you test token refresh?

Use a controllable short-lived token or identity-provider test mode instead of sleeping until a production token expires. Trigger a request after expiry, verify one refresh occurs, and confirm the original operation is replayed safely. Add concurrent requests to detect a refresh stampede and a failed-refresh case that returns the user to a secure unauthenticated state. Check that refresh tokens never appear in browser-readable storage when the architecture requires protected cookies.

4. Contracts, Schemas, and Negative Testing

Q: How do you validate a JSON schema in Playwright?

Playwright does not provide a full JSON Schema assertion API, so I integrate a maintained validator such as Ajv when schema enforcement is needed. Compile schemas once in a fixture or module, validate the parsed payload, and include readable validation errors on failure. Schema checks catch structural drift, while separate domain assertions cover relationships such as totals and permissions. I avoid replacing every focused assertion with one enormous schema that is hard to diagnose.

Q: What negative tests would you write for a create endpoint?

Cover missing required fields, wrong types, boundary lengths, invalid enum values, malformed JSON, duplicate idempotency keys, unauthorized callers, and references to nonexistent entities. Assert the documented error status and stable machine-readable code rather than brittle prose alone. Then query the service or datastore through an allowed interface to confirm no partial record was created. Select cases from actual validation and threat boundaries, not every random malformed string imaginable.

Q: How do you test idempotency?

Send the same semantically identical request twice with one idempotency key and assert that the service creates only one result. Compare stable resource identifiers and query the collection to confirm there is no duplicate side effect. Then reuse the key with a materially different payload and validate the documented conflict behavior. Run the duplicate calls concurrently as well because sequential success does not expose race conditions in key registration.

Q: How would you verify pagination?

Create enough known records to cross a page boundary, request a fixed page size, and verify ordering, uniqueness, and cursor or link metadata. Walk all pages and assert that the union matches the seeded IDs without gaps or duplicates. Insert or delete data during a cursor-based scenario if the API promises stable traversal under change. Avoid depending on an uncontrolled shared collection whose ordering changes while the test runs.

Q: How do you test rate limiting without making the suite abusive?

Use a dedicated environment or configurable low threshold agreed with the service team. Send a bounded burst, assert 429, and validate documented metadata such as Retry-After without hammering the endpoint. Verify recovery using controlled time or a reset hook when available. Keep this test out of broad parallel runs because multiple workers can combine traffic and corrupt the result.

5. Fixtures, Configuration, and Test Data

Q: How would you configure baseURL and common headers?

Put environment-specific origins and genuinely universal headers in Playwright configuration or a typed request fixture. Keep identity-specific headers out of global configuration when tests exercise multiple roles. Validate required environment variables at startup so a missing URL cannot silently point tests somewhere unintended. For a complete project structure, review building a Playwright TypeScript framework.

Q: When should an API fixture be test-scoped or worker-scoped?

Test scope is the safer default because credentials, cookies, and mutable state cannot leak between tests. Worker scope can reduce repeated authentication cost when the client is read-only or each worker owns a distinct account and namespace. If a worker-scoped fixture creates data, its teardown must handle all records created by that worker. I justify the optimization with measured runtime rather than assuming shared state is necessary.

Q: How do you create parallel-safe test data?

Generate identifiers from a run ID, worker index, and random component, then create records through a supported API. Never have parallel tests update the same customer, cart, or feature flag unless the collision is the behavior under test. Record ownership in fixture state so cleanup deletes only what that test created. Database snapshots can accelerate reset, but they require coordination so one worker does not reset another worker's world.

Q: What is a good cleanup strategy?

Prefer idempotent API deletion in fixture teardown and tolerate 404 when the test itself already removed the record. Preserve the original assertion failure if cleanup also fails, but attach the cleanup problem for investigation. Add a scheduled janitor keyed by test-run tags for process crashes that skip teardown. Never issue a broad delete based only on a common prefix in a shared environment.

Q: Should setup and teardown use the UI or API?

Use the API when setup is merely a prerequisite and the endpoint is stable, because it is faster and yields clearer failures. Use the UI when the setup journey is itself the product behavior under examination, such as first-time onboarding. A layered suite can retain one critical browser journey while most focused scenarios create state through APIs. This split reduces runtime without pretending that API setup validates the same integration as a user flow.

6. Combining API and UI Testing

Q: Give an example of API setup followed by UI verification.

Create the entity through the request fixture, navigate directly to its page, and assert how the browser renders the server state. Keep creation assertions small but explicit so a setup failure is not misreported as a UI defect. Delete the record through the API afterward. This pattern is valuable for testing edit, display, and permission behavior without repeating a long creation wizard.

Q: How would you verify that a UI action called the correct API?

Register page.waitForResponse() or page.waitForRequest() before clicking, and use a predicate that checks method plus a precise URL. Inspect the request payload when the contract matters, then assert the response and visible UI result. The network evidence localizes failures, while the screen assertion proves the user outcome. Do not treat interception alone as proof that the backend persisted the change.

test('saves notification preference', async ({ page }) => {
  await page.goto('/settings');
  const responsePromise = page.waitForResponse(r =>
    r.url().endsWith('/api/preferences') &&
    r.request().method() === 'PUT'
  );
  await page.getByLabel('Weekly summary').check();
  await page.getByRole('button', { name: 'Save' }).click();
  const response = await responsePromise;
  expect(response.status()).toBe(200);
  expect(response.request().postDataJSON()).toMatchObject({ weeklySummary: true });
  await expect(page.getByRole('status')).toHaveText('Preferences saved');
});

Q: How do you test eventual consistency after a UI action?

Poll the observable business resource with a bounded timeout and meaningful interval rather than using a fixed sleep. Stop when the expected state appears, and report the last received state if time expires. Confirm that eventual consistency is part of the documented architecture, because polling can otherwise conceal a synchronous regression. Keep the timeout close to the service-level expectation instead of inheriting an oversized global test timeout.

Q: When does API setup hide a defect?

It hides risk when the bypassed UI or gateway performs essential validation, transformation, authorization, or side effects. For example, directly inserting an order may skip tax calculation and inventory reservation performed by the checkout workflow. Map the boundaries explicitly and retain end-to-end coverage for critical integrations. Focused API setup is a speed technique, not evidence that the omitted path works.

Q: How would you test a multi-user workflow?

Create separate browser contexts and API clients for each identity, then give every user an explicitly owned resource. Perform the initiating action as one user and observe the authorized result as the other. Add a negative assertion for an unrelated user to cover information boundaries. Capture resource IDs and correlation IDs so failures across sessions can be reconstructed.

7. Mocking, Routing, and Dependency Control

Q: How does page.route() help API-related UI tests?

page.route() can fulfill, continue, or abort matching browser requests, which makes rare dependency states deterministic. It is useful for a 503, malformed payload, slow response, or unavailable third party when the goal is UI resilience. Assert the outgoing request before fulfilling it so the test also checks the browser contract. Clearly label the test as mocked because the real service is not being validated.

Q: What is the difference between route.fulfill() and route.continue()?

route.fulfill() completes the request with a supplied or fetched response, allowing full control of status, headers, and body. route.continue() sends the request onward, optionally overriding details such as headers or method. Fulfill is appropriate for deterministic stubs; continue suits observation or narrow request modification. Excessive modification can create traffic no real client would send, so keep overrides intentional.

Q: When would you use route.fetch()?

Use route.fetch() when most of the real upstream response is valuable but one field or header must be adjusted for a focused browser scenario. Fetch the response, parse it carefully, and fulfill using the original response plus the controlled change. This creates a hybrid test that still depends on upstream availability, so it is not a pure mock. I document that dependency because failure triage differs from a fully stubbed response.

Q: What are the risks of over-mocking?

Mocks can drift from production schemas, status behavior, authentication rules, and latency patterns. A suite may become fast and green while the deployed services no longer integrate. Balance mocked edge cases with direct API contract checks and a small number of real end-to-end journeys. Treat mock payloads as maintained test assets with owners, not convenient anonymous objects copied into many specs.

Q: How do you test a third-party API safely?

Test your adapter against a sandbox or contract fixture, not a vendor's production endpoint during every pull request. Stub deterministic browser scenarios and run a smaller scheduled integration check where vendor terms permit it. Avoid asserting undocumented fields and never use real customer credentials or personal data. Model timeouts, throttling, and malformed responses because resilient behavior matters as much as the happy path.

8. Reliability, Debugging, and CI

Q: An API test passes locally but fails in CI. What do you inspect?

Match the environment, configuration, runtime, worker count, identity, and seeded data before changing code. Capture sanitized status, headers, bounded body content, timing, and a service correlation ID. Check DNS, proxy, certificates, clock skew, rate limits, shared-account collisions, and deployment version. A retry can reveal intermittency, but it should not replace classification of the original failure.

Q: How do retries affect API tests?

Retries may reduce interruption from transient infrastructure faults and collect a second set of evidence. They are dangerous for non-idempotent writes because the first attempt may have succeeded even if its response was lost. Use idempotency keys, unique data, and post-failure state checks before retrying mutations. Report flaky passes separately so first-run reliability remains visible.

Q: What artifacts should an API suite retain?

Retain test metadata, durations, endpoint templates, status codes, correlation IDs, and sanitized request and response excerpts for failures. Attach schema-validation errors and created resource IDs where they help reproduce the issue. Redact tokens, cookies, personal data, and confidential payload fields at the source. Browser traces can complement combined tests, but a trace is not a substitute for service-side logs.

Q: How would you organize API tests in CI?

Run fast, deterministic contract and critical-path checks on pull requests, then broader integration matrices after merge or on schedule. Separate destructive, rate-limit, and environment-mutating cases so they cannot collide with normal workers. Shard only independent tests and provision isolated namespaces per shard. Publish clean-pass rate, flaky-pass rate, duration percentiles, and owned failure trends rather than one aggregate pass percentage.

Q: How do you distinguish a product defect from a test defect?

Reproduce the exact request independently with sanitized evidence, then compare the response with the documented contract and deployed version. A consistent contract violation across clients points toward the product; malformed setup, leaked state, or an incorrect expectation points toward the test. Environmental faults deserve their own category rather than being mislabeled as either. The classification should follow evidence and ownership, not which team notices the failure first.

9. Scenario-Based Playwright API Testing Interview Questions

Q: A DELETE endpoint returns 204, but the record still appears. How do you investigate?

First confirm whether deletion is synchronous, soft, or eventually consistent according to the contract. Query by ID with the same and a privileged identity, inspect cache behavior, and check whether the collection response is stale. Capture the deletion correlation ID and audit event for the service team. The correct assertion may be immediate 404, a deleted status, or disappearance within a defined service-level window.

Q: Two parallel tests occasionally update the wrong account. What is your fix?

Trace account allocation and request authorization to prove whether the collision comes from shared credentials, mutable globals, or reused data. Give each worker or test a unique account and make the client fixture immutable after construction. Include the expected account ID in setup assertions and verify it again after writes. A serial mode may confirm the diagnosis, but it is not the permanent solution when isolation is feasible.

Q: An endpoint sometimes returns HTML instead of JSON. How should the test report it?

Check status and content type before calling response.json(). On mismatch, attach a small redacted text excerpt, response headers, and proxy or correlation identifiers. This produces a useful gateway or authentication diagnosis instead of a generic JSON parse error. Cap the excerpt size so an error page cannot flood logs or expose sensitive content.

Q: How would you test file upload and download APIs?

For upload, send a controlled fixture through multipart, then verify media type, size, checksum, and associated metadata through the service. For download, assert status and content type, read body() as bytes, and compare a checksum or parse the actual format. Keep test files small and non-sensitive. Validate rejection of unsupported type and excessive size through a safe lower environment rather than attempting huge payloads in shared CI.

Q: A GraphQL endpoint always returns 200, even on errors. What do you assert?

Parse the GraphQL envelope and inspect errors separately from HTTP status. For a successful operation, assert the required data path and absence of unexpected errors; for negative scenarios, assert stable error codes or extensions. Validate authorization at the field level when the schema exposes mixed-access data. A transport-level 200 is not application success in GraphQL.

10. Senior Design and Strategy Questions

Q: How would you design a Playwright API testing framework?

Start with typed domain clients over small APIRequestContext calls, fixtures that own identity and lifecycle, builders for valid data, and focused assertions close to tests. Keep transport details visible enough for diagnosis and avoid one giant client containing every service. Add environment validation, secret redaction, schema helpers, run-scoped cleanup, and reporters that attach correlation IDs. Evolve abstractions from repeated domain behavior rather than drawing a framework diagram before tests exist.

Q: How do you choose between API, component, and browser tests?

Place a test at the lowest boundary that can expose the target risk with confidence. Validation and service rules usually fit unit or API checks, component rendering fits component tests, and navigation or cross-system customer journeys require a browser. Preserve a thin end-to-end layer for critical integrations even when lower layers cover most combinations. The goal is fast diagnosis and adequate risk coverage, not maximizing one test category.

Q: How would you migrate a Postman collection to Playwright?

Inventory requests, environments, scripts, data dependencies, and actual failure value before translating syntax. Move common authentication and clients into fixtures, convert assertions into typed tests, and replace collection ordering with explicit independent setup. Run both suites briefly against the same stable environment and compare coverage and outcomes. The Postman API testing tutorial is useful for explaining concepts, but migration should remove hidden collection state rather than reproduce it.

Q: What metrics indicate a healthy API suite?

Track clean first-run pass rate, flaky-pass rate, duration percentiles, queue time, failure ownership age, and defects detected by risk area. Monitor endpoints or contracts covered, but do not confuse request count with useful coverage. Measure how quickly a failure can be classified and reproduced because diagnostic quality affects delivery time. Review metrics as trends by suite and environment rather than using one target to reward superficial green builds.

Q: How do you review an API test pull request?

Check whether the test names a business behavior, owns its data, and remains independent under parallel execution. Review exact status and contract assertions, negative coverage, credential handling, cleanup, and failure output. Challenge fixed sleeps, broad retries, shared mutable accounts, and assertions tied to irrelevant payload details. Ask what defect the test would catch and whether a lower test layer would provide faster, clearer feedback.

How Interviewers Grade Your Answers

Interviewers listen for boundary awareness. A junior answer often lists methods; a stronger answer explains whether the code tests a real service, a browser integration, or a mock, then connects that boundary to a specific risk. Accurate vocabulary matters: APIRequestContext, browser context, request fixture, routing, and storage state are related but not interchangeable.

They also evaluate test design. Your example should be deterministic, parallel-safe, secure, and diagnostic. Mention exact assertions, data ownership, teardown, and the evidence retained on failure. If you propose retries or worker scope, explain the mutation and isolation risks.

For senior roles, expect follow-ups about scale and tradeoffs. Describe why you selected an API test over a browser test, what remains uncovered, and which metric would show improvement. Practice the scenario-based API testing interview questions and the five-year Playwright interview guide to strengthen those judgment answers. You can also upload your resume to the QAJobFit resume workspace and align your examples with projects you can defend in detail.

Common Mistakes

  • Calling page.route() API testing without explaining that the backend may be mocked.
  • Asserting only response.ok() and ignoring contract or business correctness.
  • Reusing one mutable account across parallel workers.
  • Parsing every response as JSON before checking status and content type.
  • Printing bearer tokens, cookies, or full confidential payloads into CI logs.
  • Retrying POST requests without idempotency or a state check.
  • Using fixed sleeps for eventual consistency instead of bounded polling.
  • Letting cleanup failures erase the original assertion failure.
  • Building a generic client abstraction that hides endpoint, method, and useful diagnostics.
  • Claiming that API setup provides coverage for the UI path it bypasses.
  • Memorizing Playwright syntax without discussing authorization, data boundaries, or failure evidence.

Conclusion

The best way to prepare for Playwright API testing interview questions is to practice precise boundary decisions. Know how to create and scope request contexts, send and validate requests, manage identity and data, combine API setup with browser checks, and control dependencies without overstating coverage.

Run the examples against a small service, deliberately seed authorization and consistency failures, and explain the evidence you would preserve in CI. Interviewers remember candidates who can turn a failed status or malformed payload into a trustworthy diagnosis and a sensible testing decision.

Interview Questions and Answers

What is APIRequestContext in Playwright?

It is an HTTP client context with its own configuration and cookie storage. I use the managed request fixture for normal test scope or create a context manually when lifecycle must be explicit. Manually created contexts are disposed during teardown.

How does direct API testing differ from page.route()?

Direct testing sends a real HTTP request through APIRequestContext and validates the service. `page.route()` controls traffic initiated by a browser page and may replace the backend response. I name mocked UI tests clearly so they are not counted as real service coverage.

What do you assert beyond HTTP status?

I check media type, required headers, schema or shape, and scenario-specific business invariants. For a mutation, I also verify persisted state or side effects. Assertions avoid volatile implementation details unless the contract requires them.

How do you test role-based authorization?

I create separate contexts for each role and exercise allowed plus forbidden operations against owned and unowned resources. I distinguish unauthenticated `401` from the documented forbidden response. For rejected writes, I verify that server state did not change.

How do you make API tests parallel-safe?

Each test or worker gets a unique namespace, identity, and owned records. Fixture state tracks created IDs for idempotent cleanup. I avoid shared mutable accounts and process-global data.

How do you test an eventually consistent API?

I poll the business resource with a bounded timeout aligned to the service expectation. The failure includes the last observed state, not just a generic timeout. I use this only when eventual behavior is documented so polling does not hide a regression.

When should API setup be used for a browser test?

I use it when state creation is a prerequisite rather than the behavior under test. It makes focused browser scenarios faster and more diagnostic. I retain separate end-to-end coverage where the bypassed UI or gateway performs critical work.

How do you handle retries for POST requests?

I do not retry a mutation blindly because the first request may have committed before its response was lost. I use an idempotency key, unique payload identity, and a state lookup before retrying. Flaky passes remain visible in reporting.

How would you debug an HTML response from a JSON endpoint?

I inspect status and content type before parsing JSON. On mismatch, I retain a small redacted body excerpt, headers, and correlation identifiers. That evidence usually distinguishes a proxy, authentication, routing, or application failure.

How would you structure a Playwright API framework?

I use small typed domain clients, lifecycle-owning fixtures, data builders, schema helpers, and run-scoped cleanup. Environment validation and secret redaction belong near the infrastructure boundary. Tests keep business intent and meaningful assertions visible.

What metrics show API suite health?

I track clean first-run pass rate, flaky-pass rate, duration percentiles, queue time, and failure ownership age. I also review defects detected by risk area and time to classify failures. Raw test count or request count is not a quality outcome.

Frequently Asked Questions

Can Playwright be used for API testing without a browser?

Yes. APIRequestContext sends HTTP requests directly, so API-only tests do not need a page or visible browser. Playwright Test still supplies runner features such as fixtures, parallelism, assertions, and reporting.

What is the request fixture in Playwright?

The request fixture is a Playwright-managed APIRequestContext available to a test. It provides an isolated HTTP client that can use base URL, headers, credentials, and cookies.

How do you assert an API response in Playwright?

Assert the documented status, relevant headers, response shape, and business invariants. Use `toBeOK()` only when any 2xx response is acceptable, and prefer an exact status when the status code is contractual.

Can Playwright validate JSON Schema?

Playwright can parse the response, but full JSON Schema validation normally uses a library such as Ajv. Keep separate focused assertions for business rules that a structural schema cannot express.

Should API tests and UI tests be in the same Playwright project?

They can share a repository and runner, but separate projects or tags often provide clearer commands, timeouts, and CI policies. Combined scenarios are useful when API calls prepare state for a focused browser check.

How do you avoid flaky Playwright API tests?

Own unique data, isolate identities, avoid fixed delays, and poll only documented eventual states with a bound. Capture sanitized response evidence and do not use retries to conceal nondeterministic writes.

Is Playwright suitable for API load testing?

Playwright can send concurrent requests, but it is not a specialized load-generation and performance-analysis platform. Use a purpose-built load tool when you need controlled arrival rates, large virtual-user counts, or detailed performance models.

Related Guides