Skip to content

Browser: add route-related doc #2018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Page provides methods to interact with a single tab in a running web browser. A
| [opener()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/opener) | Returns the `page` that opened the current `page`. |
| [press(selector, key[, options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/press/) | Focuses the element, and then presses the given `key` on the [Keyboard](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/keyboard). |
| [reload([options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/reload/) | Reloads the current page. |
| [route(url, handler)](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/route/) | Adds a route to the page to modify network requests made by that page. |
| [screenshot([options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/screenshot/) | Returns a buffer with the captured screenshot from the web browser. |
| [selectOption(selector, values[, options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/selectoption/) | Selects one or more options which match the values from a `<select>` element. |
| [setContent(html[, options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/setcontent/) | Sets the supplied HTML string to the current page. |
Expand Down
91 changes: 91 additions & 0 deletions docs/sources/k6/next/javascript-api/k6-browser/page/route.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: 'route(url, handler)'
description: 'Browser module: page.route(url, handler) method'
---

# route(url, handler)

The method adds a route that allows modifying network requests matching the provided url. The handler is a function taking a [Route](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/) input that provides functions to [continue](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/continue), [fulfill](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/fulfill) or [abort](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/abort) the request. Once routing is enabled, every request matching the url pattern will stall unless one of these functions is called.

When several routes match the given pattern, only the last registered route handler will run, and all others will be skipped.

| Parameter | Type | Default | Description |
| --------- | -------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------- |
| url | string or Regexp | `''` | URL to match during routing. |
| handler | function([Route](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/)) | null | Handler function executed when routing the request. |

## Returns

| Type | Description |
| --------------- | ------------------------------------------------------------ |
| `Promise<void>` | A Promise that fulfills when the route is added to the page. |

## Example

{{< code >}}

<!-- md-k6:skip -->

```javascript
import { browser } from 'k6/browser';

export const options = {
scenarios: {
browser: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};

export default async function () {
const page = await browser.newPage();

// Abort all images requests
await page.route(/(\.png$)|(\.jpg$)/, async function (route) {
await route.abort();
});

// Fulfill request with the following response which
// changes the quotes displayed on the page
await page.route(/.*\/quotes$/, async function (route) {
await route.fulfill({
body: JSON.stringify({
quotes: ['"We ❤️ pizza" - k6 team'],
}),
});
});

// Change the pizza request when the button is clicked
await page.route(/.*\/pizza$/, async function (route) {
await route.continue({
headers: {
...route.request().headers(),
foo: 'bar',
},
method: 'POST',
postData: JSON.stringify({
maxCaloriesPerSlice: 500,
mustBeVegetarian: true,
excludedIngredients: ['Pineapple'],
excludedTools: ['Knife', 'Scissors'],
maxNumberOfToppings: 1,
minNumberOfToppings: 1,
customName: 'Classic Pizza',
}),
});
});

await page.goto('https://quickpizza.grafana.com/');

await page.getByRole('button', { name: 'Pizza, Please!' }).click();

await page.close();
}
```

{{< /code >}}
90 changes: 90 additions & 0 deletions docs/sources/k6/next/javascript-api/k6-browser/route/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
title: 'Route'
description: 'Browser module: Route Class'
weight: 12
---

# Route

Route represents a network request intercepted by the [`page.route()`](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/page/route) function and allows to modify its behavior. Once routing is enabled, every request intercepted by a route will stall unless it's continued, fulfilled or aborted.

When several routes match the given pattern, only the last registered route handler will run, and all others will be skipped.

## Supported APIs

| Method | Description |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| [abort([errorCode])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/abort) | Aborts the route's request. |
| [continue([options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/continue) | Continues the request with optional overrides. |
| [fulfill([options])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/fulfill) | Fulfills the request with the given response |
| [request()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/route/request) | Returns the matching [Request](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-browser/request) object. |

### Example

{{< code >}}

<!-- md-k6:skip -->

```javascript
import { browser } from 'k6/browser';

export const options = {
scenarios: {
browser: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};

export default async function () {
const page = await browser.newPage();

// Abort all images requests
await page.route(/(\.png$)|(\.jpg$)/, async function (route) {
await route.abort();
});

// Fulfill request with the following response which
// changes the quotes displayed on the page
await page.route(/.*\/quotes$/, async function (route) {
await route.fulfill({
body: JSON.stringify({
quotes: ['"We ❤️ pizza" - k6 team'],
}),
});
});

// Change the pizza request when the button is clicked
await page.route(/.*\/pizza$/, async function (route) {
await route.continue({
headers: {
...route.request().headers(),
foo: 'bar',
},
method: 'POST',
postData: JSON.stringify({
maxCaloriesPerSlice: 500,
mustBeVegetarian: true,
excludedIngredients: ['Pineapple'],
excludedTools: ['Knife', 'Scissors'],
maxNumberOfToppings: 1,
minNumberOfToppings: 1,
customName: 'Classic Pizza',
}),
});
});

await page.goto('https://quickpizza.grafana.com/');

await page.getByRole('button', { name: 'Pizza, Please!' }).click();

await page.close();
}
```

{{< /code >}}
56 changes: 56 additions & 0 deletions docs/sources/k6/next/javascript-api/k6-browser/route/abort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
title: 'abort([errorCode])'
description: 'Browser module: Route.abort method'
---

# abort([errorCode])

Aborts the request with the given error code.

| Parameter | Type | Default | Description |
| --------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| errorCode | string | `'failed'` | Error code when aborting the request. Can be one of the following: `'aborted'`, `'accessdenied'`, `'addressunreachable'`, `'blockedbyclient'`, `'blockedbyresponse'`, `'connectionaborted'`,`'connectionclosed'`, `'connectionfailed'`, `'connectionrefused'`, `'connectionreset'`, `'internetdisconnected'`, `'namenotresolved'`, `'timedout'`, `'failed'`. |

## Returns

| Type | Description |
| --------------- | ---------------------------------------------------- |
| `Promise<void>` | A Promise that fulfills when the request is aborted. |

## Example

{{< code >}}

<!-- md-k6:skip -->

```javascript
import { browser } from 'k6/browser';

export const options = {
scenarios: {
browser: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};

export default async function () {
const page = await browser.newPage();

// Abort all images requests
await page.route(/(\.png$)|(\.jpg$)/, async function (route) {
await route.abort('blockedbyclient');
});

await page.goto('https://quickpizza.grafana.com/');

await page.close();
}
```

{{< /code >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
title: 'continue([options])'
description: 'Browser module: Route.continue method'
---

# continue([options])

{{< admonition type="caution" >}}

This method has **known issues**, but it does work as intended. For details, refer to [#5012](https://github.com/grafana/k6/issues/5012).

{{< /admonition >}}

Sends the request to the network with optional overrides.

| Parameter | Type | Default | Description |
| ---------------- | ---------------- | ------- | ---------------------------------- |
| options | object | null | |
| options.headers | object | null | Request headers. |
| options.method | string | `''` | Request method (e.g. GET or POST). |
| options.postData | string or Buffer | `''` | Post data of the request. |
| options.url | string | `''` | Request URL. |

## Returns

| Type | Description |
| --------------- | ---------------------------------------------------- |
| `Promise<void>` | A Promise that fulfills when the request is resumed. |

## Example

{{< code >}}

<!-- md-k6:skip -->

```javascript
import { browser } from 'k6/browser';

export const options = {
scenarios: {
browser: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};

export default async function () {
const page = await browser.newPage();

// Change the pizza request when the button is clicked
await page.route(/.*\/pizza$/, async function (route) {
await route.continue({
headers: {
...route.request().headers(),
foo: 'bar',
},
method: 'POST',
postData: JSON.stringify({
maxCaloriesPerSlice: 500,
mustBeVegetarian: true,
excludedIngredients: ['Pineapple'],
excludedTools: ['Knife', 'Scissors'],
maxNumberOfToppings: 1,
minNumberOfToppings: 1,
customName: 'Classic Pizza',
}),
});
});

await page.goto('https://quickpizza.grafana.com/');

await page.getByRole('button', { name: 'Pizza, Please!' }).click();

await page.close();
}
```

{{< /code >}}
Loading