Skip to content

Add network request mocking keyword family: Mock Response, Abort Requests, Modify Requests, Remove Route, Remove All Routes #5120

Description

@Snooz82

Use case

Network mocking is the single biggest Playwright capability that Browser library does not expose at all today: there is no keyword, no wrapper code, and no proto RPC for page.route/context.route. Users cannot:

  • Stub an API endpoint to test the frontend in isolation from the backend (return fixture JSON for /api/**).
  • Test error paths deterministically (make /api/orders return a 500 without breaking the real backend).
  • Block unwanted requests (abort analytics beacons, ads, or all images to speed up suites).
  • Modify outgoing requests (inject/override headers, redirect a request to a different URL, change method or post data).

There is currently no workaround inside the library — users who need mocking must run an external proxy or a separate mock server, which defeats the point of an integrated browser automation library. Nearly every real-world suite eventually needs at least one of these capabilities, which makes this the flagship feature of the network milestone.

Playwright's route API is callback-based, which does not fit the keyword model. The design decision (see docs/plan/playwright-feature-gap-plan.md) is to reshape it into declarative rules stored node-side, exposed as separate verb keywords (not a single Route keyword with an action enum). The library already uses this reshaping pattern in Add Locator Handler Custom.

Proposed keyword / arguments

All keywords take a matcher (URL glob pattern or regex) with the same semantics as Wait For Request / Wait For Response (reusing deserializeUrlOrPredicate). All rule-creating keywords default to scope=Context so mocks survive navigations and apply to popups/new pages; pass named-only scope=Page to narrow to the current page.

Mock Response       matcher    *, status=200    body=None    json=None    path=None    content_type=None    headers=None    times=None    scope=Context
Abort Requests      matcher    *, error_code=failed    times=None    scope=Context
Modify Requests     matcher    *, headers=None    url=None    method=None    post_data=None    scope=Context
Remove Route        matcher
Remove All Routes
  • Mock Response fulfills matching requests. Exactly one of body, json, path (file with response body) provides the payload; json sets content-type: application/json automatically.
  • Abort Requests aborts matching requests with the given Playwright error code (failed, aborted, accessdenied, connectionrefused, internetdisconnected, ...).
  • Modify Requests continues matching requests with overrides (extra/overridden headers, rewritten URL, method, or post data).
  • times= limits how many times a rule fires before it is removed automatically (maps to the route option times).
  • Optional stretch goal: named-only base_on_server_response=True on Mock Response — fetch the real response first (route.fetch) and fulfill with the given fields merged on top, so users can mutate real responses (e.g. patch one JSON field).
*** Test Cases ***
Frontend Renders Empty User List
    Mock Response    **/api/users    json={"users": []}
    Go To    ${APP_URL}
    Get Text    id=user-list-empty    ==    No users found

Error Banner On Server Failure
    Mock Response    **/api/orders    status=500    json={"error": "boom"}    times=1
    Click    id=load-orders
    Get Text    css=.error-banner    contains    Something went wrong

Block Analytics For Whole Suite
    Abort Requests    /.*google-analytics.*/

Inject Auth Header Only On Current Page
    Modify Requests    **/api/**    headers={"Authorization": "Bearer ${token}"}    scope=Page

Cleanup
    Remove Route    **/api/users
    Remove All Routes

Playwright API

Implementation notes

  • New RPCs in protobuf/playwright.proto for registering/removing route rules (rule spec message: matcher, action, action payload, times, scope).
  • Node-side rule store in node/playwright-wrapper: one real route() handler per registered matcher that executes the stored declarative action; matcher parsing reuses the existing deserializeUrlOrPredicate from the Wait For Request/Response path. Rule ordering semantics (last registered wins, Playwright-style) must be defined and documented.
  • New Python keywords in Browser/keywords/network.py, docs, inv build stub regen.
  • New atest suite against the dynamic test app (fixture endpoints for fulfill/abort/continue, times=, scope behavior across New Page/navigation).
  • This is a full milestone on its own (see plan: Wave 2, "Network mocking").

Backwards compatibility

Purely additive: five new keywords, no changes to any existing keyword or return value. Existing suites are unaffected unless they call the new keywords.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions