release notes/v0.51.0.md
k6 v0.51.0 is here π! Some special mentions included in this release:
In the last release notes we mentioned this breaking change, and we wanted to remind and update you on the plan. In the next release (v0.52.0), most of the synchronous browser APIs will be migrated to be asynchronous (promisifying them). We expect this will affect most if not all of our users.
This breaking change will require you to add await in front of most of the browser module APIs. Without this await you will witness undocumented and unknown behavior during the runtime. To make the migration simpler we advise that you work with the latest k6 type definitions.
You can find a list of all the APIs that we expect to convert to async in a comment in issue browser#428.
Awaiting on something thatβs not a thenable just returns that value, which means you can add the await keyword today on the APIs that will become async to future proof your test scripts.
Here are the reasons for making this large breaking change:
As a starting point, we have migrated a single API (the tap method), which you can find the details below that will help visualize the upcoming breaking changes.
Tap is now an async method grafana/xk6-browser#1268This release converts the Tap method in the browser module into an asynchronous method. This change is necessary to ensure that the method can be used in async contexts and to align with the rest of the browser module's planned asynchronous API. To use the Tap method, you must now add the await keyword before the method call.
Affected components:
See the following example for how to use the Tap method after this change:
Before:
import browser from 'k6/experimental/browser'
// ...
export default function () {
// ...
page.tap(selector, { modifiers: ["Alt", "Control", "Meta", "Shift"] });
// ...
}
After:
import browser from 'k6/experimental/browser'
// ...
export default function () {
// ...
await page.tap(selector, { modifiers: ["Alt", "Control", "Meta", "Shift"] });
// ...
}
k6/experimental/websockets will not default binaryType to `"arraybuffer"'As part of the stabilization of the API it needs to become as close to the specification.
Early in the development the idea of adding Blob support as part was deemed feature creep and was dropped in favor of going with only "arraybuffer". But the specification defaults to returning binary responses as Blob - which was another thing that was changed.
While adding Blob is still on our radar, moving the default is always going to be a breaking change that we need to do to align with the specification.
For this release there is now a warning that will be printed if binaryType is not set to "arraybuffer" and a binary response is received. The warning will go away when binaryType is set to "arraybuffer".
In the next release the warning will become an error.
More info and place for discussion can be found in an this issue.
k6/experimental/grpc is no longer available #3530As the last step of the graduation process for the experimental gRPC module, we completely removed the module. It is now fully integrated into the stable k6/net/grpc module. So, if you haven't done this yet, replace your imports from k6/experimental/grpc to k6/net/grpc.
The following pull requests start the process to introduce breaking changes. They are currently starting to emit warning if their condition is hit, but they will turn to return errors in the future release. It is recommended to use the suggested alternative, or to fix the script if you see the warning message.
require expressions.k6/experimental/streams module #3696This release of k6 introduces the new k6/experimental/streams module, which partially supports the JavaScript
Streams API, focusing initially on the ReadableStream construct.
With the ReadableStream, users can define and consume data streams within k6 scripts. This is particularly useful for
efficiently handling large datasets or for processing data sequentially in a controlled flow.
The following example demonstrates creating and consuming a simple stream that emits numbers until it reaches a predefined limit:
import { ReadableStream } from 'k6/experimental/streams'
function numbersStream() {
let currentNumber = 0
return new ReadableStream({
start(controller) {
const fn = () => {
if (currentNumber < 5) {
controller.enqueue(++currentNumber)
setTimeout(fn, 1000)
return;
}
controller.close()
}
setTimeout(fn, 1000)
},
})
}
export default async function () {
const stream = numbersStream()
const reader = stream.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
console.log(`received number ${value} from stream`)
}
console.log('we are done')
}
For more advanced examples, please head to the MDN Web Docs on the Streams API.
Currently, users can define and consume readable streams. However, this release does not include support for byte readers
and controllers, nor does it include support the tee, pipeTo, and
pipeThrough methods of the ReadableStream object.
This release brings support for asymmetric cryptography to the k6/experimental/webcrypto module. We added support of the elliptic curves algorithms ECDH (xk6-webcrypto#67) and ECDSA (xk6-webcrypto#69) algorithms along with new import/export key formats like spki and pkcs8.
One of the newly added operations is deriveBits, which allows parties to generate a unique shared secret by using shared public and non-shared private keys.
import { crypto } from 'k6/experimental/webcrypto';
export default async function () {
// Generate a key pair for Alice
const aliceKeyPair = await crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: 'P-256',
},
true,
['deriveKey', 'deriveBits']
);
// Generate a key pair for Bob
const bobKeyPair = await crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: 'P-256',
},
true,
['deriveKey', 'deriveBits']
);
// Derive shared secret for Alice
const aliceSharedSecret = await deriveSharedSecret(aliceKeyPair.privateKey, bobKeyPair.publicKey);
// Derive shared secret for Bob
const bobSharedSecret = await deriveSharedSecret(bobKeyPair.privateKey, aliceKeyPair.publicKey);
// alice shared secret and bob shared secret should be the same
console.log('alice shared secret: ' + printArrayBuffer(aliceSharedSecret));
console.log('bob shared secret: ' + printArrayBuffer(bobSharedSecret));
}
async function deriveSharedSecret(privateKey, publicKey) {
return crypto.subtle.deriveBits(
{
name: 'ECDH',
public: publicKey,
},
privateKey,
256
);
}
const printArrayBuffer = (buffer) => {
const view = new Uint8Array(buffer);
return Array.from(view);
};
The sign and verify operations got support for ECDSA algorithm. The sign operation allows you to sign a message with a private key, while the verify operation allows you to verify the signature with a public key.
Other notable updates and fixes:
See webcrypto's module documentation for more details.
setTimeout, setInterval and related clear functions have been part of the JavaScript ecosystem, probably for as long as it has existed.
In the previous releases we stabilized and made them available through k6/timers module. While the module isn't going anywhere and might get more identifiers, setTimeout is usually used without importing it. For this reason it is now globally available along clearTimeout, setInterval and clearInterval.
No code needs to be changed, but you no longer need to import k6/timers to use this functionality.
asyncInvoke method to the k6/net/grpc module. It's a non-blocking version of the invoke method.execution.test.options from Init context.k6_SYSTEM_TAGS environment variable.mappings field is empty in the provided SourceMap.golangci-lint in the contribution guide. Thanks @yomek33 for your contribution!As the changes in documentation mention, binaryType was by default set to arraybuffer, now instead it is "" (empty string).
In a not so remote future, instead, we expect to introduce and use Blob object.
WebCrypto got more features in the current release, and we expect to continue its expansion in the next iterations. Reaching a wider coverage will push WebCrypto module to being graduated as a stable module.
In the not so distant future, we have plans to start using the Streams API in existing modules. Our first iteration being adding a .readable property to the already existing fs.File object.
In the near future, we intend to reiterate on k6 cloud and related commands to create a simplified and more ergonomic user experience.
The k6/experimental/timers module is now part of the stable k6 API as k6/timers and via the globally available functions. The next release will make the experimental import no longer available.