No results for

Powered byAlgolia

Running xk6-browser

Follow along to learn how to:

  1. Run a test
  2. Interact with elements on your webpage
  3. Wait for page navigation
  4. Run both browser-level and protocol-level tests in a single script
  5. Run xk6-browser tests in a Docker container

With these example snippets, you'll run the test locally with your machine's resources. xk6-browser is not available within k6 cloud as of yet.

Run a test

To run a simple local script:

  1. Follow the Installation Guidelines and make sure there is a binary named xk6-browser in your current working directory.

  2. Copy the following code, paste it into your favorite editor, and save it as script.js:

    1import { chromium } from 'k6/x/browser';
    3export default function () {
    4 const browser = chromium.launch({ headless: false });
    5 const page = browser.newPage();
    7 page
    8 .goto('', { waitUntil: 'networkidle' })
    9 .then(() => {
    10 page.screenshot({ path: 'screenshot.png' });
    11 })
    12 .finally(() => {
    13 page.close();
    14 browser.close();
    15 });

    The preceding code imports the chromium BrowserType (currently the only available BrowserType implementation), and uses its launch method to start up a Chromium Browser process. After it starts, you can interact with it using the browser-level APIs. This example visits a test URL, waits until the network is idle and takes a screenshot of the page. Afterwards, it closes the page and the browser.


    To provide rough compatibility with the Playwright API, the xk6-browser API is also being converted from synchronous to asynchronous. page.goto() is now asynchronous so .then() is used to deal with the asynchronous nature of the operation.

  3. Then, run xk6-browser on your terminal with this command:

    $ ./xk6-browser run script.js

    The ./ prefix tells your shell to run the binary located in the current working directory. This is required on macOS and Linux, but not on the Windows cmd.exe shell. On PowerShell, specify .\xk6-browser instead.

    If you installed xk6-browser with a system package, or placed the binary in a directory that's part of your $PATH environment variable, you can omit the ./ or .\ prefixes.

Interact with elements on your webpage

You can use page.locator() and pass in the element's selector you want to find on the page. page.locator() will create and return a Locator object, which you can later use to interact with the element.

To find out which selectors xk6-browser supports, check out Selecting Elements.


You can also use page.$() instead of page.locator(). You can find the differences between page.locator() and page.$ in the Locator API documentation.

1import { chromium } from 'k6/x/browser';
3export default function () {
4 const browser = chromium.launch({ headless: false });
5 const page = browser.newPage();
7 page
8 .goto('', { waitUntil: 'networkidle' })
9 .then(() => {
10 // Enter login credentials
11 page.locator('input[name="login"]').type('admin');
12 page.locator('input[name="password"]').type('123');
14 page.screenshot({ path: 'screenshot.png' });
15 })
16 .finally(() => {
17 page.close();
18 browser.close();
19 });

The preceding code creates and returns a Locator object with the selectors for both login and password passed as arguments.

Within the Locator API, various methods such as type() can be used to interact with the elements. The type() method types a text to an input field.

Asynchronous operations

As explained previously, the k6 API is synchronous. However, since many browser operations happen asynchronously, and in order to follow the Playwright API more closely, we are working on migrating most xk6-browser methods to be asynchronous as well.

At the moment, methods such as page.goto(), page.waitForNavigation() and return JavaScript promises, and scripts must be written to handle this properly.

To avoid timing errors or other race conditions in your script, if you have actions that load up a different page, you need to make sure that you wait for that action to finish before continuing.

1import { check } from 'k6';
2import { chromium } from 'k6/x/browser';
4export default function () {
5 const browser = chromium.launch({ headless: false });
6 const page = browser.newPage();
8 page
9 .goto('', { waitUntil: 'networkidle' })
10 .then(() => {
11 // Enter login credentials and login
12 page.locator('input[name="login"]').type('admin');
13 page.locator('input[name="password"]').type('123');
15 // Wait for asynchronous operations to complete
16 return Promise.all([
17 page.waitForNavigation(),
18 page.locator('input[type="submit"]').click(),
19 ]).then(() => {
20 check(page, {
21 'header': page.locator('h2').textContent() == 'Welcome, admin!',
22 });
23 });
24 }).finally(() => {
25 page.close();
26 browser.close();
27 });

The preceding code uses Promise.all([]) to wait for the two promises to be resolved before continuing. Since clicking the submit button causes page navigation, page.waitForNavigation() is needed because the page won't be ready until the navigation completes. This is required because there can be a race condition if these two actions don't happen simultaneously.

Then, you can use check from the k6 API to assert the text content of a specific element. Finally, you close the page and the browser.

Run both browser-level and protocol-level tests in a single script

The real power of xk6-browser shines when it’s combined with the existing features of k6. A common scenario that you can try is to mix a smaller subset of browser-level tests with a larger protocol-level test which can simulate how your website responds to various performance events.

To run a browser-level and protocol-level test concurrently, you can use scenarios.


Keep in mind that there is an additional performance overhead when it comes to spinning up a browser VU and that the resource usage will depend on the system under test.

1import { chromium } from 'k6/x/browser';
2import { check } from 'k6';
3import http from 'k6/http';
5export const options = {
6 scenarios: {
7 messages: {
8 executor: 'constant-vus',
9 exec: 'browser',
10 vus: 1,
11 duration: '10s',
12 },
13 news: {
14 executor: 'constant-vus',
15 exec: 'news',
16 vus: 20,
17 duration: '1m',
18 },
19 },
22export function browser() {
23 const browser = chromium.launch({ headless: false });
24 const page = browser.newPage();
26 page
27 .goto('', { waitUntil: 'networkidle' })
28 .then(() => {
29 page.locator('#checkbox1').check();
31 check(page, {
32 'checkbox is checked': (p) =>
33 p.locator('#checkbox-info-display').textContent() === 'Thanks for checking the box',
34 });
35 })
36 .finally(() => {
37 page.close();
38 browser.close();
39 });
42export function news() {
43 const res = http.get('');
45 check(res, {
46 'status is 200': (r) => r.status === 200,
47 });

The preceding code contains two scenarios. One for the browser-level test called browser and one for the protocol-level test called news. Both scenarios are using the constant-vus executor which introduces a constant number of virtual users to execute as many iterations as possible for a specified amount of time.

Since it's all in one script, this allows for greater collaboration amongst teams.

Run xk6-browser tests in a Docker container

If you prefer working with Docker, you can run your xk6-browser test scripts in a Docker container using Docker Compose by creating a Dockerfile and docker-compose file.

To run the test, use the following command and replace script.js with your file.

docker-compose run -T xk6-browser run - <script.js