k6 v0.44.0 is here! 🎉 This release includes:

- A new `k6/experimental/webcrypto` module implementing (partially) the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) specification.
- A sampling option for the experimental tracing module.
- Memory usage improvements.
- Bug fixes and UX improvements.

Some highlights from the `k6/experimental/browser` module are:

- `locator.click` is now asynchronous, which is a breaking change.
- `browserContext.addCookies` has now been implemented.
- `browserType.Connect` has been implemented so k6 can now connect to an already running Chrome/Chromium browser instance.
- Web vitals are natively supported when working with the browser module.

## Breaking changes

The browser module is still in an `experimental` stage, and therefore breaking changes are expected as we are improving the APIs to make them more user-friendly.

- [browser#790](https://github.com/grafana/xk6-browser/pull/790) Converted `locator.click` to async to have feature parity with `page.click` and `elementHandle.click`. Users must remember to work with `promise.All` and `page.waitForNavigation()` when a click action results in navigation.

    A `locator.click` action that doesn't result in navigation can be used like so:
    ```javascript
    const tails = page.locator("input[value='Bet on tails!']");
    await tails.click(),
    ```

    A `locator.click` action that does result in a navigation can be used like so:
    ```javascript
    const tails = page.locator("input[value='Bet on tails!']");
    await Promise.all([
      page.waitForNavigation(),
      tails.click(),
    ]);
    ```

- [browser#817](https://github.com/grafana/xk6-browser/pull/817) We've removed `--no-sandbox` from the default Chrome launch arguments. Now Chrome will launch with a sandbox, which is a more secure way of running the browser. If you are running tests under a `root` user, the browser will no longer launch unless the `--no-sandbox` argument is supplied. You can still pass this flag when launching a new Chrome instance using the `args` parameter on `chromium.launch`:

    ```javascript
    const browser = chromium.launch({
      args: ['no-sandbox'],
    });
    ```

- [browser#844](https://github.com/grafana/xk6-browser/pull/844) Removed the exported `version` param from the root module. Users should from now on reference the k6 version instead of the browser module version.
- [browser#838](https://github.com/grafana/xk6-browser/pull/838) Removed the first meaningful paint metric. This metric is being deprecated across all the browsers, because the metric's definition relies on browser-specific implementation details, and we've now introduced web vitals in the browser module which is a reliable industry standard way to measure frontend performance. You can find more details [here](https://developer.chrome.com/en/docs/lighthouse/performance/first-meaningful-paint/).
- [browser#843](https://github.com/grafana/xk6-browser/pull/843) Removed the build step from Github Actions. From this release onwards, no new standalone browser binaries will be built and available from the [releases](https://github.com/grafana/xk6-browser/releases) section. The latest version of the browser module will be available in the k6 binary which can be found in the [k6 releases](https://github.com/grafana/k6/releases) page.

## New features

### A new `k6/experimental/webcrypto` module implementing the Web Crypto API specification [#3007](https://github.com/grafana/k6/pull/3007)

This release includes a new `k6/experimental/webcrypto` module partially implementing the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) specification in k6.

<details>
<summary> Expand to see an example of the new functionality.</summary>

This example shows encrypting and decrypting of a "Hello, World!" string using AES-CBC algorithm.

```javascript
import { crypto } from 'k6/experimental/webcrypto';

export default async function () {
  const key = await crypto.subtle.generateKey(
    {
      name: 'AES-CBC',
      length: 256,
    },
    true,
    ['encrypt', 'decrypt']
  );

  const encoded = stringToArrayBuffer('Hello, World!');
  const iv = crypto.getRandomValues(new Uint8Array(16));

  const ciphertext = await crypto.subtle.encrypt(
    {
      name: 'AES-CBC',
      iv: iv,
    },
    key,
    encoded
  );

  const plaintext = await crypto.subtle.decrypt(
    {
      name: 'AES-CBC',
      iv: iv,
    },
    key,
    ciphertext
  );

  console.log(
    'deciphered text == original text: ',
    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)
  );
}

function arrayBufferToHex(buffer) {
  return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('');
}

function stringToArrayBuffer(str) {
  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
```
</details>

You can see the list of currently supported APIs and algorithms in the project's [README](https://github.com/grafana/xk6-webcrypto/blob/v0.1.0/README.md#current-state). Documentation for the module is available [here](https://k6.io/docs/javascript-api/k6-experimental/webcrypto/).

### Add sampling capabilities to the experimental tracing module [#2886](https://github.com/grafana/k6/pull/2886)

This release adds sampling capabilities to the tracing module. You can now specify a sampling rate with the `sampling` option when initializing a Client, or in the `tracing.InstrumentHTTP` function.

### `browserContext.addCookies` [browser#760](https://github.com/grafana/xk6-browser/pull/760)

Cookies can now be added to a `BrowserContext` and all new `Page`s created from this context will have the cookie assigned to them. Thanks @zucchinho for implementing this feature!

```javascript
const context = browser.newContext()
context.addCookies([{name: 'myCookie', value: 'hello world', url: 'https://test.k6.io'}])
const page = context.newPage()
```

### `browserType.Connect` [browser#800](https://github.com/grafana/xk6-browser/pull/800)

There are cases where the user may want to connect to a remote browser instance where they have more control over the browser lifecycle, such as when working in a resource bound environment. This feature enables users to connect to a manually started Chrome/Chromium browser instance. It's a simple case of replacing `browser.launch` with `browser.connect` and supplying the CDP url as the first argument. Not all `launch` options will work with `connect` since the browser instance should already have started prior to working with `connect`. Since we assume that the user had decided to take ownership of starting the browser, we have made `browser.close` a NOOP when working with `browser.connect`, so the user will need to close the browser themselves.

```javascript
const browser = chromium.connect('ws://127.0.0.1:1234/devtools/browser/e3bb7e53-ad0f-46f3-ae89-a8416868f4ce')
const page = browser.newPage();
```

### Web Vitals are now natively supported by the browser module [browser#836](https://github.com/grafana/xk6-browser/pull/836) [browser#847](https://github.com/grafana/xk6-browser/pull/847)

Web vitals are the defacto way for developers to measure their frontend performance using the core metrics:

- Largest contentful paint ([LCP](https://web.dev/lcp/))
- First input delay ([FID](https://web.dev/fid/))
- Cumulative layout shift ([CLS](https://web.dev/cls/))

These measurements are now calculated for all tests without any additional work from your side. Simply run your test as you have been doing and you will be presented with the new metrics in the output. This is the output after running the [examples/fillform.js](https://github.com/grafana/xk6-browser/blob/main/examples/fillform.js) script:

```bash
webvital_cumulative_layout_shift..........: avg=0        min=0        med=0        max=0        p(90)=0        p(95)=0
webvital_cumulative_layout_shift_good.....: 1       0.323332/s
webvital_first_contentful_paint...........: avg=278.86ms min=141.1ms  med=229.39ms max=466.1ms  p(90)=418.76ms p(95)=442.43ms
webvital_first_contentful_paint_good......: 3       0.969995/s
webvital_first_input_delay................: avg=300µs    min=200µs    med=300µs    max=399.99µs p(90)=379.99µs p(95)=389.99µs
webvital_first_input_delay_good...........: 2       0.646663/s
webvital_interaction_to_next_paint........: avg=16ms     min=16ms     med=16ms     max=16ms     p(90)=16ms     p(95)=16ms
webvital_interaction_to_next_paint_good...: 1       0.323332/s
webvital_largest_content_paint............: avg=303.6ms  min=141.1ms  med=303.6ms  max=466.1ms  p(90)=433.6ms  p(95)=449.85ms
webvital_largest_content_paint_good.......: 2       0.646663/s
webvital_time_to_first_byte...............: avg=205.23ms min=104.79ms med=188.39ms max=322.5ms  p(90)=295.67ms p(95)=309.08ms
webvital_time_to_first_byte_good..........: 3       0.969995/s
```

You may have noticed other metrics in there too. We rely on the [web-vitals](https://github.com/GoogleChrome/web-vitals) JS library which exposes a few more metrics, so we've left them in for you to experiment with. You can find more details on all the browser module metrics in our [documentation](https://k6.io/docs/using-k6-browser/browser-metrics/).

You will no longer see `browser_first_contentful_paint` in the summary, and instead you can work with `webvital_first_contentful_paint`.

### UX improvements and enhancements

- [#2906](https://github.com/grafana/k6/pull/2906) Added multiple date-time formats for CSV output. Thanks, @Azanul!
- [#2916](https://github.com/grafana/k6/pull/2916) k6 started to show the actual binary's name in the usage help. Thanks, @ariasmn!
- [#2942](https://github.com/grafana/k6/pull/2942) Reference 'k6 cloud' instead of 'Load Impact' in docs and errors.
- [#2985](https://github.com/grafana/k6/pull/2985) Added support of async functions for `setup` and `handleSummary`.
- [#2901](https://github.com/grafana/k6/pull/2901) Added a warning when the number of time series exceeds 100 000, which could lead to potential out-of-memory issues.
- [#2997](https://github.com/grafana/k6/pull/2997) Added a new exit code (`109`), used on a go panic.
- [browser#788](https://github.com/grafana/xk6-browser/pull/788) Updated the browser readme to highlight that it is now a module in k6.
- [browser#803](https://github.com/grafana/xk6-browser/pull/803) Users are now warned if the `browser.close` method is called more than once.
- [browser#820](https://github.com/grafana/xk6-browser/pull/820) Added error handling to wildcard selectors, which cleans up the error output in the terminal.
- [browser#848](https://github.com/grafana/xk6-browser/pull/848) Multiple k6 instances can now connect to one browser to run concurrent tests. This update empowers high-concurrency browser testing with multiple VUs and instances. Using the new `browserType.Connect` API, users can now connect to an existing browser instance and execute concurrent tests, which was not possible previously.

## Bug fixes

- [#2984](https://github.com/grafana/k6/pull/2984) Fixed wrongly assigned HTTP `POST` and `PUT` methods for the `tracing.instrumentHTTP`. Thanks, @marcin-maciej-seweryn!
- [#2928](https://github.com/grafana/k6/pull/2928) Handled a new behavior of `filepath.Join` on windows with go1.20, which could cause issues for the `k6 archive` and `k6 cloud` commands.
- [#2915](https://github.com/grafana/k6/pull/2915) Fixed `check` that could return incorrect values for some cases with many preallocated VUs.
- [#2953](https://github.com/grafana/k6/pull/2953) Fixed active VU reporting by arrival-rate executors.
- [#3006](https://github.com/grafana/k6/pull/3006) `xk6-websockets` updated to v0.2.0 which fixes a lock up of the whole k6.
- [#3023](https://github.com/grafana/k6/pull/3023) Fixed Trend.Max's support of negative values.
- [browser#781](https://github.com/grafana/xk6-browser/pull/781) Fixed mapping of `response` object's function from `jSON` to `json`.
- [browser#779](https://github.com/grafana/xk6-browser/pull/779) Cleared Zombie processes on panic.
- [browser#834](https://github.com/grafana/xk6-browser/pull/834) Fixed `page.close` so that it closes the current page and not the whole browser context.

## Maintenance and internal improvements

### Improved the per-VU buffer pool [#2879](https://github.com/grafana/k6/pull/2879)

Improved the per-VU buffer pool which should greatly reduce memory usage, at a minor expense of higher CPU usage and lower request throughput. In some cases, this change can [reduce memory usage up to 50%](https://github.com/grafana/k6/issues/794#issuecomment-1406522459).

Thanks to @davidpst for the contribution!

Other minor changes in this release:

- [#3004](https://github.com/grafana/k6/pull/3004) Changed `eventloop.WaitOnRegistered` to execute all scheduled callbacks.
- [#2881](https://github.com/grafana/k6/pull/2881) Refactored how modules are loaded. This is a preparation for the upcoming ESM support.
- [#2920](https://github.com/grafana/k6/pull/2920) Updated Go version that we use for k6 compilation to 1.20.x. The docker image is also updated to use alpine:3.17.
- [#2986](https://github.com/grafana/k6/pull/2986) Refactored goja's `isNullish` to be a part of `js/common`.
- [#2960](https://github.com/grafana/k6/pull/2960) Refactored `sirupsen/logrus` usage.
- [#2999](https://github.com/grafana/k6/pull/2999) Directly embed `lib.TestPreInitState` in `js/common.InitEnvironment`.
- [#2892](https://github.com/grafana/k6/pull/2892) Added z/OS build flags for IBM z/OS compatibility. Thanks, @msradam!
- [#2833](https://github.com/grafana/k6/pull/2833) Fixed detected memory leaks.
- [#2931](https://github.com/grafana/k6/pull/2931), [#2940](https://github.com/grafana/k6/pull/2940), [#2895](https://github.com/grafana/k6/pull/2895), [#3002](https://github.com/grafana/k6/pull/3002) Updated k6's dependencies. Added `goja`'s generator support.
- [#2947](https://github.com/grafana/k6/pull/2947), [#2943](https://github.com/grafana/k6/pull/2943), [#2946](https://github.com/grafana/k6/pull/2946), [#3009](https://github.com/grafana/k6/pull/3009), [#3012](https://github.com/grafana/k6/pull/3012), [#2894](https://github.com/grafana/k6/pull/2894) Tests' fixes, refactoring, and improvements.
- [#2891](https://github.com/grafana/k6/pull/2891), [#2921](https://github.com/grafana/k6/pull/2921), [#2923](https://github.com/grafana/k6/pull/2923), [#2990](https://github.com/grafana/k6/pull/2990), [#2995](https://github.com/grafana/k6/pull/2995), [#3016](https://github.com/grafana/k6/pull/3016), [#2989](https://github.com/grafana/k6/pull/2989) Linters and formatting fixes.
- [#3005](https://github.com/grafana/k6/pull/3005) The samples catalog was renamed to examples.
- [browser#776](https://github.com/grafana/xk6-browser/pull/776) Fixed a test for preset flags for Chrome on macOS.
- [browser#782](https://github.com/grafana/xk6-browser/pull/782), [browser#783](https://github.com/grafana/xk6-browser/pull/783), [browser#826](https://github.com/grafana/xk6-browser/pull/826) Fixed and refactored the Go-JS mapping.
- [browser#797](https://github.com/grafana/xk6-browser/pull/797), [browser#832](https://github.com/grafana/xk6-browser/pull/832) Fixed multi browser close.
- [browser#796](https://github.com/grafana/xk6-browser/pull/796), [browser#810](https://github.com/grafana/xk6-browser/pull/810) Refactored `browserContext.SetExtraHTTPHeaders` to work with errors and ErrFatal.
- [browser#798](https://github.com/grafana/xk6-browser/pull/798), [browser#799](https://github.com/grafana/xk6-browser/pull/799) Added more tests for the Go-JS mapping layer.
- [browser#802](https://github.com/grafana/xk6-browser/pull/802) Added a helper to assert on the logs and dump the logs for easier debugging.
- [browser#807](https://github.com/grafana/xk6-browser/pull/807) Fixed incorrect keyboard key code on up/down key presses.
- [browser#819](https://github.com/grafana/xk6-browser/pull/819) `Browser.Launch` now transitions to `Browser.Connect` when a CDP URL is provided in an environment variable.
- [browser#821](https://github.com/grafana/xk6-browser/pull/821), [browser#824](https://github.com/grafana/xk6-browser/pull/824), [browser#830](https://github.com/grafana/xk6-browser/pull/830) Upgraded dependencies and fixed breaking changes.
