Migrating browser scripts to k6 v0.52
This guide outlines the key changes you will need to make when moving your existing k6 experimental browser test scripts to the latest k6 browser module version bundled with k6 0.52.
Key changes
In the latest release of k6, we have graduated k6 browser module out of experimental and is now under the import k6/browser
. Migrating to this is a breaking change that will affect all scripts that use the experimental k6 browser module. The breaking changes are:
- Converted most of the k6 browser module APIs to asynchronous (async) APIs. That means they will return a
promise
that willresolve
to a value when the API call succeeds orreject
when an error occurs. - A side effect of making this async changes is that you will need to use the
check
utility function from jslib.k6.io instead of working with the k6 check API. - Finally, it’s also worth reiterating that the group API still doesn’t work with async APIs.
If you are interested in the rationale behind this change, refer to the v0.51 release notes.
Note
The experimental import (k6/experimental/browser
) and the corresponding synchronous APIs will be supported up until the 23rd of September 2024.
Migrating to async
To ensure your scripts work with the latest release of the k6 browser module, you must:
- Change the import from
k6/experimental/browser
tok6/browser
. - Ensure that all the synchronous (sync) APIs that have been migrated over to async are handled appropriately. In most cases, you will only need to add
await
in front of the API call.
For example, before:
import { browser } from 'k6/experimental/browser';
...
export default async function () {
const page = browser.newPage();
...
}
And now:
import { browser } from 'k6/browser';
...
export default async function () {
const page = await browser.newPage();
...
}
You might have already encountered async APIs when working with the browser module, such as page.click, so the use of async
and await
keywords might be familiar to you.
Below is a screenshot of a comparison between a generic browser test in v0.51
and v0.52
to help visualize the change:
The affected APIs
Class | Method |
---|---|
Browser | closeContext |
Browser | context |
Browser | newContext |
Browser | newPage |
Browser | userAgent |
BrowserContext | addCookies |
BrowserContext | addInitScript |
BrowserContext | browser |
BrowserContext | clearCookies |
BrowserContext | clearPermissions |
BrowserContext | close |
BrowserContext | cookies |
BrowserContext | grantPermissions |
BrowserContext | newPage |
BrowserContext | setGeolocation |
BrowserContext | setOffline |
ElementHandle | $ |
ElementHandle | $$ |
ElementHandle | boundingBox |
ElementHandle | check |
ElementHandle | contentFrame |
ElementHandle | dblclick |
ElementHandle | dispatchEvent |
ElementHandle | fill |
ElementHandle | focus |
ElementHandle | getAttribute |
ElementHandle | hover |
ElementHandle | innerHTML |
ElementHandle | innerText |
ElementHandle | inputValue |
ElementHandle | isChecked |
ElementHandle | isDisabled |
ElementHandle | isEditable |
ElementHandle | isEnabled |
ElementHandle | isHidden |
ElementHandle | isVisible |
ElementHandle | ownerFrame |
ElementHandle | press |
ElementHandle | screenshot |
ElementHandle | scrollIntoViewIfNeeded |
ElementHandle | selectOption |
ElementHandle | selectText |
ElementHandle | setInputFiles |
ElementHandle | tap |
ElementHandle | textContent |
ElementHandle | type |
ElementHandle | uncheck |
ElementHandle | waitForElementState |
ElementHandle | waitForSelector |
Frame | $ |
Frame | $$ |
Frame | check |
Frame | content |
Frame | dblclick |
Frame | dispatchEvent |
Frame | evaluate<R, Arg> |
Frame | evaluateHandle<R, Arg> |
Frame | fill |
Frame | focus |
Frame | frameElement |
Frame | getAttribute |
Frame | hover |
Frame | innerHTML |
Frame | innerText |
Frame | inputValue |
Frame | isChecked |
Frame | isDisabled |
Frame | isEditable |
Frame | isEnabled |
Frame | isHidden |
Frame | isVisible |
Frame | press |
Frame | selectOption |
Frame | setContent |
Frame | setInputFiles |
Frame | tap |
Frame | textContent |
Frame | title |
Frame | type |
Frame | uncheck |
Frame | waitForLoadState |
Frame | waitForSelector |
Frame | waitForTimeout |
JSHandle | asElement |
JSHandle | dispose |
JSHandle | evaluate<R, Arg> |
JSHandle | evaluateHandle<R, Arg> |
JSHandle | getProperties |
JSHandle | jsonValue |
Keyboard | down |
Keyboard | insertText |
Keyboard | press |
Keyboard | type |
Keyboard | up |
Locator | check |
Locator | clear |
Locator | dblclick |
Locator | dispatchEvent |
Locator | fill |
Locator | focus |
Locator | getAttribute |
Locator | hover |
Locator | innerHTML |
Locator | innerText |
Locator | inputValue |
Locator | isChecked |
Locator | isDisabled |
Locator | isEditable |
Locator | isEnabled |
Locator | isHidden |
Locator | isVisible |
Locator | press |
Locator | selectOption |
Locator | tap |
Locator | textContent |
Locator | type |
Locator | uncheck |
Locator | waitFor |
Mouse | click |
Mouse | dblclick |
Mouse | down |
Mouse | move |
Mouse | up |
Page | $ |
Page | $$ |
Page | bringToFront |
Page | check |
Page | close |
Page | content |
Page | dblclick |
Page | dispatchEvent |
Page | emulateMedia |
Page | emulateVisionDeficiency |
Page | evaluate<R, Arg> |
Page | evaluateHandle<R, Arg> |
Page | fill |
Page | focus |
Page | getAttribute |
Page | hover |
Page | innerHTML |
Page | innerText |
Page | inputValue |
Page | isChecked |
Page | isDisabled |
Page | isEditable |
Page | isEnabled |
Page | isHidden |
Page | isVisible |
Page | on |
Page | opener |
Page | press |
Page | reload |
Page | screenshot |
Page | selectOption |
Page | setContent |
Page | setExtraHTTPHeaders |
Page | setInputFiles |
Page | setViewportSize |
Page | tap |
Page | textContent |
Page | throttleCPU |
Page | throttleNetwork |
Page | title |
Page | type |
Page | uncheck |
Page | viewportSize |
Page | waitForLoadState |
Page | waitForSelector |
Page | waitForTimeout |
Request | allHeaders |
Request | headerValue |
Request | headersArray |
Request | postData |
Request | resourceType |
Request | response |
Request | size |
Request | timing |
Response | allHeaders |
Response | body |
Response | headerValue |
Response | headerValues |
Response | headersArray |
Response | json |
Response | securityDetails |
Response | serverAddr |
Response | size |
Touchscreen | tap |
Working with k6 check
The k6 check
API will not await
promises, so calling a function that returns a Promise
, for example locator.textContent()
, inside one of the predicates will not work. Instead, you can work with the jslib.k6.io’s check
utility function.
For example, before:
check(page.locator('h2'), {
header: lo => lo.textContent() == 'Welcome, admin!',
});
And now:
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';
// ...
await check(page.locator('h2'), {
'header': async lo => await lo.textContent() === 'Welcome, admin!'
});
Groups
A note on groups, they don’t work with async APIs either, there is no workaround as of yet. Here’s the GitHub issue that you can follow to keep up-to-date with relevant news on a group API that works with async APIs.
Migrating from k6 v0.45 or below
If you use k6 v0.45 or below, first review how to migrate to v0.46. This guide details the breaking changes introduced in v0.46 for the browser
APIs and provides instructions on how to migrate to them.
Where to get extra help
With the release of k6 v0.52
, you’ll also be able to find the latest type definitions and updates to the k6 browser documentation. Refer to Configure k6 IntelliSense for details on how to work with the type definition file in your project.
For all the details, review the CHANGELOG for k6 version 0.52. You can also ask questions in the community forum if you need help.