new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Playwright · all subjects

api testing

83 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Dispose APIRequestContext

Call dispose() method on an APIRequestContext instance to clean up and release resources after use.

Example: Setup and teardown with beforeAll and afterAll

```js test.beforeAll(async ({ request }) => { const response = await request.post('/user/repos', { data: { name: REPO } }); expect(response.ok()).toBeTruthy(); }); test.afterAll(async ({ request }) => { const response = await request.delete(`/repos/${USER}/${REPO}`); expect(response.ok()).toBeTruthy(); }); ``` This shows how to create a repository before tests run and delete it afterwards.

APIRequestContext methods for HTTP requests

APIRequestContext can send all kinds of HTTP(S) requests over network. It provides methods like post(), get(), delete(), and fetch() for making API requests from Node.js without loading a page.

Built-in request fixture respects configuration

Playwright Test comes with a built-in request fixture that respects configuration options like baseURL and extraHTTPHeaders specified in the configuration file.

Create APIRequestContext manually with request.newContext()

Use request.newContext() to create an APIRequestContext instance manually for more control. This method accepts options like baseURL and headers. The context can be used to make HTTP requests independently.

Use beforeAll and afterAll for setup and teardown

Use test.beforeAll() hook to set up resources like creating a repository before running tests, and test.afterAll() hook to clean up resources like deleting the repository after tests complete.

Example: API test using request fixture

```js const REPO = 'test-repo-1'; const USER = 'github-username'; test('should create a bug report', async ({ request }) => { const newIssue = await request.post(`/repos/${USER}/${REPO}/issues`, { data: { title: '[Bug] report 1', body: 'Bug description', } }); expect(newIssue.ok()).toBeTruthy(); const issues = await request.get(`/repos/${USER}/${REPO}/issues`); expect(issues.ok()).toBeTruthy(); expect(await issues.json()).toContainEqual(expect.objectContaining({ title: '[Bug] report 1', body: 'Bug description' })); }); ``` This demonstrates using the request fixture to post data to an API and then get and verify the response.

Example: Create issue via UI and verify via API

```js import { test, expect } from '@playwright/test'; const REPO = 'test-repo-1'; const USER = 'github-username'; let apiContext; test.beforeAll(async ({ playwright }) => { apiContext = await playwright.request.newContext({ baseURL: 'https://api.github.com', extraHTTPHeaders: { 'Accept': 'application/vnd.github.v3+json', 'Authorization': `token ${process.env.API_TOKEN}`, }, }); }); test.afterAll(async ({ }) => { await apiContext.dispose(); }); test('last created issue should be on the server', async ({ page }) => { await page.goto(`https://github.com/${USER}/${REPO}/issues`); await page.getByText('New Issue').click(); await page.getByRole('textbox', { name: 'Title' }).fill('Bug report 1'); await page.getByRole('textbox', { name: 'Comment body' }).fill('Bug description'); await page.getByText('Submit new issue').click(); const issueId = new URL(page.url()).pathname.split('/').pop(); const newIssue = await apiContext.get( `https://api.github.com/repos/${USER}/${REPO}/issues/${issueId}` ); expect(newIssue.ok()).toBeTruthy(); expect(newIssue.json()).toEqual(expect.objectContaining({ title: 'Bug report 1' })); }); ``` This example shows validating postconditions by creating an issue through the UI, then verifying it exists via API.

APIResponse ok() method

Call ok() method on an APIResponse to check if the response status code is within the 200-299 range. Returns a boolean.

APIResponse json() method

Call json() method on an APIResponse to parse the response body as JSON and return the parsed object.

Context request shares cookies with browser

APIRequestContext accessible via context.request or page.request will populate the request's Cookie header from the browser context cookies and automatically update browser cookies if the APIResponse has a Set-Cookie header.

Create isolated APIRequestContext with separate cookies

Use playwright.request.newContext() to create an APIRequestContext instance with isolated cookie storage that does not share cookies with the browser context. This is useful when you want API requests to have their own independent cookie storage.

Handling download event without knowing the trigger

If you do not know what action initiates the download, you can handle the event using `page.on('download', download => download.path().then(console.log))` in JavaScript. However, this pattern forks the control flow and makes the script harder to follow, and the scenario might end while a file is downloading since the main control flow does not await the operation.

Downloaded files deleted when context closes

Downloaded files are deleted when the browser context that produced them is closed.

Download object properties and methods

The Download object obtained from the `Page.download` event provides access to the download URL, file name via `suggestedFilename()`, and payload stream. It has a `saveAs()` method to save the file to a specified path, and a `path()` method to get the download path.

Waiting for download with waitForEvent

To handle file downloads, start waiting for the download event before performing the action that initiates the download. In JavaScript, use `page.waitForEvent('download')` without awaiting it initially, then perform the action that triggers the download, then await the returned promise. This pattern ensures the download listener is registered before the download begins.

JavaScript download handling example

// Start waiting for download before clicking. Note no await. const downloadPromise = page.waitForEvent('download'); await page.getByText('Download file').click(); const download = await downloadPromise; // Wait for the download process to complete and save the downloaded file somewhere. await download.saveAs('/path/to/save/at/' + download.suggestedFilename());

Download event emitted for page attachments

For every attachment downloaded by the page, a `Page.download` event is emitted. All attachments are downloaded into a temporary folder.

Pitfall: using test variable directly in evaluate

Do not reference test variables directly in the evaluated function without passing them as parameters. The variable name will not be available in the browser context, causing a ReferenceError.

Example: evaluate passing data as parameter

const data = 'some data'; const result = await page.evaluate(data => { window.myApp.use(data); }, data);

Example: evaluate with object destructuring

await page.evaluate( ({ button1, button2 }) => button1.textContent + button2.textContent, { button1, button2 });

Example: addInitScript replacing Math.random

test.beforeEach(async ({ page }) => { const value = 42; await page.addInitScript(value => { Math.random = () => value; }, value); });

Page.evaluate runs JavaScript in browser context

The Page.evaluate API runs a JavaScript function in the context of the web page and brings results back to the Playwright environment. Browser globals like window and document can be used in evaluate.

evaluate automatically waits for Promise resolution

If the result is a Promise or if the function is asynchronous, evaluate will automatically wait until it is resolved before returning.

Cannot access test variables directly in evaluated scripts

Evaluated scripts run in the browser environment while tests run in a testing environment. Variables from the test cannot be used directly in the page script and vice versa. Variables must be passed explicitly as arguments.

Pass test data to evaluate as function arguments

To use values from your test in an evaluated script, pass them explicitly as arguments to the evaluate function. The evaluated function can then accept these parameters normally.

evaluate accepts mix of serializable values and JSHandle instances

Playwright evaluation methods like Page.evaluate take a single optional argument that can be a mix of Serializable values and JSHandle instances. Handles are automatically converted to the value they represent.

Object destructuring in evaluate requires parentheses

When destructuring objects in evaluate, the destructuring pattern must be wrapped in parentheses. Property names in the destructured object must match between the destructured object and the argument passed to evaluate.

Array destructuring in evaluate requires parentheses

When destructuring arrays in evaluate, the destructuring pattern must be wrapped in parentheses. Arbitrary names can be used for destructuring array elements.

evaluate can accept handles alongside serializable values

The evaluate function can accept a single argument that contains any mix of serializable values (primitives, arrays, objects) and JSHandle instances in the same object or array.

Page.addInitScript runs script before page loading

Page.addInitScript and BrowserContext.addInitScript evaluate a script in the page context before the page starts loading. This is useful for setting up mocks or test data before page navigation begins.

addInitScript accepts path or inline function

addInitScript can be passed either a path to a script file or a function. When passing a function, you can also pass arguments to it.

Example: evaluate getting document location

const href = await page.evaluate(() => document.location.href);

Example: evaluate with async function and fetch

const status = await page.evaluate(async () => { const response = await fetch(location.href); return response.status; });

Listen to events using page.on and page.off

Subscribe to events using page.on(eventName, callback) where the callback receives the event object. Unsubscribe using page.off(eventName, callback) with the same callback reference. Each on* method has a corresponding off* method. Example: page.on('request', request => console.log(`Request sent: ${request.url()}`)); const listener = request => console.log(`Request finished: ${request.url()}`); page.on('requestfinished', listener); await page.goto('https://wikipedia.org'); page.off('requestfinished', listener);

Event types Playwright supports

Playwright allows listening to various event types including network requests, creation of child pages, dedicated workers, popups, dialogs, and requestfinished events.

Wait for request with URL pattern using waitForRequest

Use page.waitForRequest(urlPattern) to wait for a network request matching a URL pattern. Start the wait before the action that triggers the request. The method returns a promise that resolves to the Request object. Example: const requestPromise = page.waitForRequest('**/*logo*.png'); await page.goto('https://wikipedia.org'); const request = await requestPromise; console.log(request.url());

HAR file recording with Browser.newContext recordHar option

When creating a browser context, use the recordHar option (JavaScript: recordHar, C#/Python/Java: recordHarPath) in Browser.newContext() to capture all network traffic for the entire context until the context is closed.

Mock API requests with page.route()

Use page.route() to intercept network requests and return custom responses without making the actual API call. The method takes a URL pattern glob and an async route handler. Inside the handler, call route.fulfill() with the desired response, such as a JSON object. For example: await page.route('*/**/api/v1/fruits', async route => { await route.fulfill({ json: [{ name: 'Strawberry', id: 21 }] }); }).

Modify API responses instead of fully mocking

When you need to make the actual API request but patch the response, use route.fetch() to get the real response, modify it, and then call route.fulfill({ response, json }) with both the original response and the modified JSON. This allows you to keep headers and other response properties while changing only the body.

Record HAR files with page.routeFromHAR()

Use page.routeFromHAR(filePath, options) or BrowserContext.routeFromHAR(filePath, options) to record or replay network requests. Set update: true to record/update the HAR file with actual network information. The options object can include url (glob pattern) to only capture matching requests. A HAR file contains request/response headers, cookies, content, and timings.

Replay requests from HAR files

Set update: false when calling page.routeFromHAR() to replay requests from a previously recorded HAR file instead of hitting the API. The method will match responses from the HAR using URL and HTTP method strictly. For POST requests, it also matches POST payloads strictly. If multiple entries match, the one with the most matching headers is picked. If no match is found, the request is aborted.

Edit HAR files manually

HAR files are stored as hashed .txt files inside the hars folder and contain JSON. You can manually open and edit the JSON to modify mock data. These edited files should be committed to source control. Running a test with update: true will update the HAR file with new requests from the API.

HAR file archive format with .zip

If a HAR file name ends with .zip, it is treated as an archive containing the HAR file along with network payloads stored as separate entries. You can extract this archive, edit payloads or the HAR log manually, and point to the extracted HAR file. All payloads will be resolved relative to the extracted HAR file on the file system.

Record HAR files with Playwright CLI

Use npx playwright open --save-har=filename.har --save-har-glob='pattern' URL to record HAR files via the CLI. The --save-har option specifies the HAR file path, and --save-har-glob filters which requests to save using a glob pattern (for example '**/api/**' to save only API requests). If the har file name ends with .zip, artifacts are written as separate files and compressed into a single zip.

Mock WebSocket connections entirely

Use page.routeWebSocket(url, handler) to intercept WebSocket connections and mock the entire communication without connecting to the server. Inside the handler, call ws.onMessage(callback) to respond to incoming messages and ws.send(message) to send responses. For example: await page.routeWebSocket('wss://example.com/ws', ws => { ws.onMessage(message => { if (message === 'request') ws.send('response'); }); }).

Intercept and modify WebSocket messages

Use ws.connectToServer() inside the WebSocket route handler to connect to the actual WebSocket server while intercepting and modifying messages. Call ws.onMessage() to receive messages from the client, optionally transform them, and send them to the server using server.send(). This allows selective modification of messages while passing others through unchanged.

WebSocketRoute API for message interception

WebSocketRoute provides ws.onMessage(callback) to register a handler for incoming messages and ws.send(message) to send messages. The connectToServer() method returns a server WebSocketRoute to forward messages to the actual server. See WebSocketRoute documentation for full details.

Context.route blocks network requests with custom route handler

You can mock network requests at the browser context level using context.route(). Define a Route handler that intercepts and handles requests. Example: await context.route(/.css$/, route => route.abort()) blocks all CSS requests for every test in that file.

Page.route mocks network for single page

Alternatively to context.route(), you can use page.route() to mock network requests for a single page only. This does not affect popup windows or opened links.

Page.route patterns apply to popup windows and opened links

Routes set up with BrowserContext.route() or Page.route() apply to popup windows and opened links, not just the initial page.

Subscribe to request and response events

Monitor network traffic by listening to 'request' and 'response' events on a page: page.on('request', request => console.log(request.method(), request.url())) and page.on('response', response => console.log(response.status(), response.url()))

Route.fulfill mocks API responses

Use route.fulfill() to mock API responses: await page.route('**/api/fetch_data', route => route.fulfill({ status: 200, body: testData }));

Page.waitForResponse waits for network response

Use page.waitForResponse() to wait for a specific response after an action. Set up the response promise before the action, then await it after: const responsePromise = page.waitForResponse('**/api/fetch_data'); await page.getByText('Update').click(); const response = await responsePromise;

Page.waitForResponse with RegExp pattern

page.waitForResponse() supports RegExp patterns to match responses: const responsePromise = page.waitForResponse(/\.jpeg$/); await action(); const response = await responsePromise;

Page.waitForResponse with predicate function

page.waitForResponse() accepts a predicate function that receives a Response object: const responsePromise = page.waitForResponse(response => response.url().includes(token)); await action(); const response = await responsePromise;

Route.continue with modified headers

Modify requests by calling route.continue() with new headers: await page.route('**/*', async route => { const headers = route.request().headers(); delete headers['X-Secret']; await route.continue({ headers }); })

Route.continue with different HTTP method

Continue requests with a different HTTP method: await page.route('**/*', route => route.continue({ method: 'POST' }));

Route.abort terminates network requests

Abort requests using route.abort(): await page.route('**/*.{png,jpg,jpeg}', route => route.abort());

Abort requests by resource type

Check the request resource type before aborting: await page.route('**/*', route => { return route.request().resourceType() === 'image' ? route.abort() : route.continue(); });

Give your agent this brain