k6 `v0.47.0` is here 🎉! This release includes:

## Deprecations

- [#3347](https://github.com/grafana/k6/pull/3347) The built-in `statsd` output option has been deprecated, and users should use the [xk6-output-statsd](https://github.com/LeonAdato/xk6-output-statsd) extension instead. See [#2982](https://github.com/grafana/k6/issues/2982) for future plans.
- [#3288](https://github.com/grafana/k6/pull/3288) Loading remote modules now requires users to prepend them with `https://`. Before, k6 would try to resolve importing remote modules by prepending `https://` if it was missing. This behavior has been deprecated and will be fully removed in the next release (v0.48.0).

## New features

### Add gRPC's binary metadata support [#3234](https://github.com/grafana/k6/pull/3234), [xk6-grpc#46](https://github.com/grafana/xk6-grpc/pull/46)

The k6 gRPC modules (`k6/net/grpc` and `k6/experimental/grpc`) now support handling binary metadata that uses the `-bin` postfix, according to the gRPC specification.

```js
let resp = client.invoke("grpc.testing.TestService/EmptyCall", {}, { metadata: { "X-Load-Tester-bin": new Uint8Array([2, 200]) } })
```

Thanks to @sapphire-janrain for the contribution!

### Add gRPC's reflection metadata support [#3343](https://github.com/grafana/k6/pull/3343), [xk6-grpc#46](https://github.com/grafana/xk6-grpc/pull/46)

The k6 gRPC modules (`k6/net/grpc` and `k6/experimental/grpc`) now support adding metadata to reflection requests by using a new connection parameter [`reflectMetadata`](https://k6.io/docs/javascript-api/k6-net-grpc/client/client-connect/#connectparams).

### Higher precision for Trend metrics in Grafana Cloud k6 [#3302](https://github.com/grafana/k6/pull/3302)

Grafana Cloud k6 is now able to store and visualize Trend metrics up to 3 digits of precision for decimal numbers.

### Docker support for browser-based tests [#3199](https://github.com/grafana/k6/pull/3199)

k6 is now publishig Docker images that include Chromium web browser. This allows k6 users to run tests that use [Browser API](https://k6.io/docs/javascript-api/k6-experimental/browser/) without having to install Chrome first. Check the ["A note on running browser tests" section](https://hub.docker.com/r/grafana/k6) of the Overview page on DockerHub for details.

### Docker images for ARM64 architecture [#3320](https://github.com/grafana/k6/pull/3320)

The k6's release process now builds and pushes dedicated Docker images for ARM64. Check k6's [tags page](https://hub.docker.com/r/grafana/k6/tags) on DockerHub for details.

### New authentication methods and HTTP headers API for Prometheus remote write output [xk6-output-prometheus-remote#143](https://github.com/grafana/xk6-output-prometheus-remote/pull/143), [xk6-output-prometheus-remote#145](https://github.com/grafana/xk6-output-prometheus-remote/pull/145), [xk6-output-prometheus-remote#147](https://github.com/grafana/xk6-output-prometheus-remote/pull/147)

The experimental Prometheus remote write output now supports two new authentication methods: Bearer token and TLS certificates. Check out the [documentation](https://k6.io/docs/results-output/real-time/prometheus-remote-write/#options) to learn more about how to define them using the new environment variables.
We've also added the `K6_PROMETHEUS_RW_HTTP_HEADERS` that defines a new and more convenient way to set custom HTTP headers to pass through each flush metrics' request. 

### Improved the browser module's cookie API

The browser module now provides a more complete and robust API for handling cookies. The cookie API was stabilized by defining a new [`Cookie` class](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/cookie) ([browser#1008](https://github.com/grafana/xk6-browser/pull/1008), [browser#1030](https://github.com/grafana/xk6-browser/pull/1030)) that can be used while creating and retrieving cookies. This enabled us to add a new [`browserContext.cookies([urls])`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/cookies/) method ([browser#1005](https://github.com/grafana/xk6-browser/pull/1005)) that returns all cookies from the current [browser context](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext). The new API also supports filtering cookies by URL ([browser#1016](https://github.com/grafana/xk6-browser/pull/1016)).

That led to fixing a bug where the `expires` field was not being set correctly while adding cookies using the [`context.addCookie()`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/addcookies/) method ([browser#1031](https://github.com/grafana/xk6-browser/pull/1031)). Lastly, the existing [`context.clearCookies()`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/clearcookies) method was fixed to clear all cookies from the current [browser context](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext) ([browser#1040](https://github.com/grafana/xk6-browser/pull/1040)).

```js
const context = browser.newContext();
context.addCookies([
    {name: 'foo', value: 'bar', url: 'https://test.k6.io'},
    {name: 'baz', value: 'qux', url: 'https://grafana.com'},
]);

const cookies = context.cookies('https://test.k6.io');
console.log(cookies.length);         // 1
console.log(cookies[0].name);        // foo
console.log(cookies[0].value);       // bar

context.clearCookies();
console.log(context.cookies.length); // 0
```

### Add support for browser module's `page.on('console')` [browser#1006](https://github.com/grafana/xk6-browser/pull/1006)

Allows users to register a handler to be executed every time the `console` API methods are called from within the page's JavaScript context. The arguments passed into the handler are defined by the [ConsoleMessage](https://k6.io/docs/javascript-api/k6-experimental/browser/consolemessage/) class.

```js
page.on('console', msg => {
    check(msg, {
        'assertConsoleMessageType': msg => msg.type() == 'log',
        'assertConsoleMessageText': msg => msg.text() == 'this is a console.log message 42',
        'assertConsoleMessageArgs0': msg => msg.args()[0].jsonValue() == 'this is a console.log message',
        'assertConsoleMessageArgs1': msg => msg.args()[1].jsonValue() == 42,
    });
});

page.evaluate(() => console.log('this is a console.log message', 42));
```

## UX improvements and enhancements

- [#3338](https://github.com/grafana/k6/pull/3338), [xk6-grpc#48](https://github.com/grafana/xk6-grpc/pull/48) Adds support for the gRPC reflection protocol v1.
- [#3290](https://github.com/grafana/k6/pull/3290) Adds error logging when executing `setup` and `teardown` via REST API. Thanks to @kmtym1998 for the contribution!
- [#3327](https://github.com/grafana/k6/pull/3327) Adds commit identifier for the k6 build when running `k6 version`.
- [#3340](https://github.com/grafana/k6/pull/3340) Updates k6 ``*-with-browser`` Docker images to automatically set the `no-sandbox` environment variable.
- [#3335](https://github.com/grafana/k6/pull/3335) The character limit for metric names increased from 63 to 128 after the OpenTelemetry update. k6 will return an error starting on the next release (v0.48.0) if users hit the limit.
- [browser#1007](https://github.com/grafana/xk6-browser/pull/1007) Adds a `k6` object (`window.k6 = {};`) to help identify k6 browser module tests.
- [browser#1022](https://github.com/grafana/xk6-browser/pull/1022) Refactors the `check` in `examples/fillform.js` so that it matches the type definitions and documentation for `check`.

## Bug fixes

- [xk6-grpc#47](https://github.com/grafana/xk6-grpc/pull/47) Fixes the premature closing of a gRPC stream when a stream's client has finished sending. Thanks to @thiagodpf for reporting!
- [#3344](https://github.com/grafana/k6/pull/3344), [xk6-grpc#49](https://github.com/grafana/xk6-grpc/pull/49) Adds support for Google's protobuf wrappers. Thanks to @zibul444 for reporting!
- [#3308](https://github.com/grafana/k6/pull/3308) Updates `goja` version, and fixes a compiler bug when a class is declared in a function with an argument.
- [browser#1039](https://github.com/grafana/xk6-browser/pull/1039) Fixes `goja` conversions while adding and retrieving cookies.
- [browser#1038](https://github.com/grafana/xk6-browser/pull/1038) Fixes read/write data race for edge case with remote browsers.
- [browser#1034](https://github.com/grafana/xk6-browser/pull/1034) Fixes `page.reload` & `page.setContent` to use the default navigation timeout over the default timeout.
- [browser#1033](https://github.com/grafana/xk6-browser/pull/1033) Fixes the `page` timeouts so it is actually used after being set.

## Maintenance and internal improvements

- [#3342](https://github.com/grafana/k6/pull/3342) Updates xk6-grpc to the latest version. This change brings all the latest fixes and improvements to the experimental gRPC module.
- [#3271](https://github.com/grafana/k6/pull/3271),[#3272](https://github.com/grafana/k6/pull/3272) Updates the golangci version and adds the `interfacebloat` linter.
- [#3279](https://github.com/grafana/k6/pull/3279) Fixes the CI not publishing the SBOM file on a new release.
- [#3283](https://github.com/grafana/k6/pull/3283) Updates the Go version in k6's CI used to build the binaries.
- [#3341](https://github.com/grafana/k6/pull/3341), [#3339](https://github.com/grafana/k6/pull/3339) Updates `goja`, includes runtime initialization speed-up and a fix for source indexes.
- [#3311](https://github.com/grafana/k6/pull/3311) Updates the `alpine` image version that is used as the base of the k6 Docker image.
- [browser#1043](https://github.com/grafana/xk6-browser/pull/1043), [browser#1021](https://github.com/grafana/xk6-browser/pull/1021), [browser#1019](https://github.com/grafana/xk6-browser/pull/1019), [browser#1014](https://github.com/grafana/xk6-browser/pull/1014) Fixes xk6-browser tests.
- [browser#1000](https://github.com/grafana/xk6-browser/pull/1000), [browser#1024](https://github.com/grafana/xk6-browser/pull/1024) Refines xk6-browser issue and PR templates.
- [browser#1003](https://github.com/grafana/xk6-browser/pull/1003), [browser#1009](https://github.com/grafana/xk6-browser/pull/1009), [browser#1010](https://github.com/grafana/xk6-browser/pull/1010) Internal changes to xk6-browser.
- [browser#997](https://github.com/grafana/xk6-browser/pull/997) Updates xk6-browser readme.
- [browser#962](https://github.com/grafana/xk6-browser/pull/962) CI fixes.
- [browser#1035](https://github.com/grafana/xk6-browser/pull/1035) Refactors `int64` timeout to `time.Duration`, to help avoid confusion as to whether a timeout is in milliseconds or seconds.

## Roadmap

### Native ECMAScript Modules support

Work on this [epic issue](https://github.com/grafana/k6/issues/3265) has been picked up and there is some progress in the underlying implementation.

One of the main internal changes will be dropping [Babel](https://babeljs.io), which is currently used to transpile [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) code to [CommonJS](https://en.wikipedia.org/wiki/CommonJS).

For users, it will mean better JavaScript support as this change will automatically get [object spread](https://github.com/grafana/k6/issues/824) working and likely faster startup for *big* scripts. In the future, this also means JavaScript compatibility will be easier to add, since it'll only need to be supported in the JavaScript VM we use - [goja](https://github.com/dop251/goja).

There's a risk that some k6 tests using both CommonJS and ECMAScript modules syntax will change in behavior. In practice, using both should never really be done as they're not compatible.

Because there are risks involved, we are going to do this very carefully and only once we have done a lot of tests. That means this is currently planned for v0.49.0, but with the majority of the remaining work done in the v0.48.0 cycle.

This way, we will also be able to have most of our users test these changes from our `master` branch, using Docker images, for example.

### Future breaking changes

There are several changes in the next release that are entering the final stage of their deprecation period. That means the next release will include the following breaking changes:

- [#3065](https://github.com/grafana/k6/issues/3065) Metric names will be limited to 128 characters and a set of allowed symbols. This was going to be changed to a 63 character limit to ensure compatibility with OpenTelemetry standards, but since then, the OTel limit has been updated to 255 characters. You can find more details about the changes in the linked issue.
- [#3365](https://github.com/grafana/k6/pull/3365) The `k6 converter` command will be removed.
- [#3350](https://github.com/grafana/k6/pull/3350) The `headers` param for the gRPC module will be removed. Users should use the [metadata](https://k6.io/docs/javascript-api/k6-experimental/grpc/params) property instead.
- [#3287](https://github.com/grafana/k6/issues/3287) Loading remote modules will require users to include the `https://` protocol in their URLs, otherwise it will return an error.
- CSV output no longer accepts arguments in snake case (for example, [fileName](https://k6.io/docs/results-output/real-time/csv/#csv-options) should be used instead of `file_name`).
- The `--logformat` flag for defining the Log format option will be removed. [--log-format](https://k6.io/docs/using-k6/k6-options/reference/#logformat) should be used instead.

We recommend checking this list to see if you are impacted, and updating your scripts or CI/CD processes to avoid any issues. If you have any feedback, please open an issue.
