Skip to content

Releases: grafana/k6

v1.2.3

27 Aug 07:42
Compare
Choose a tag to compare

k6 1.2.3 is a small patch with a couple of bug fixes

Bug fixes

  • #5099 Fixes auto extension resolution only working if binary is called k6 after a fix in v1.2.2.
  • #5098 Fixes gRPC calls not using loaded types and erroring out, especially around the usage of Any.

v1.2.2

19 Aug 11:21
Compare
Choose a tag to compare

k6 1.2.2 is a small patch release fixing a panic and two other smaller bugfixes.

Bug fixes

  • #5067 fixes a panic on the deprecated k6 login cloud command. Thanks @indygriffiths for reporting it!
  • #5069 Fixes group order in end of test summary when scenarios are used.
  • #5070 Adds nullish check to the new getByRole and add tests for other getBy* APIs nullish checks.

v1.2.1

13 Aug 10:59
Compare
Choose a tag to compare

k6 v1.2.1 is here 🎉! This release includes:

  • Automatic extension resolution (previously Binary Provisioning) enabled for everyone
  • gRPC gets better handling of NaN and Infinity float values and easier health check
  • Browser module gets page.route, all the page.getBy* APIs, locator.all(), and page.waitForURL

Note: An old xk6-browser repo v1.2.0 tag was pushed by mistake. It was left over on the machine since the merging of the two repos. As such it can not be used as a go module or installed with go install. For this reason v1.2.1 is released.

Breaking changes

As per our stability guarantees,
breaking changes across minor releases are allowed only for experimental features.

Breaking changes for experimental modules

  • The experimental Open Telemetry and Prometheus outputs now default to TLSv1.3. This should've been the default to begin with. It is not expected that anyone should be affected, apart from making it more secure for the metrics output to send messages.

New features

Automatic extension resolution

k6 extensions allow you to add custom functionality to your tests, such as connecting to databases, message queues, or specialized networking protocols. Previously, using extensions required manual building of a custom k6 binary with the extensions compiled in. This new version introduces the Automatic Extension Resolution functionality, previously named Binary Provisioning, which is enabled by default and automatically detects when your script imports extensions and handles the complexity of provisioning the right k6 binary for you.

import faker from "k6/x/faker";

export default function () {
  console.log(faker.person.firstName());
}

The previous experimental versions only supported official extensions. #4922 added the support to use any extension listed in the community list by setting the K6_ENABLE_COMMUNITY_EXTENSIONS environment variable.

K6_ENABLE_COMMUNITY_EXTENSIONS=true k6 run script.js

Note, Community extensions are only supported for local test executions (using k6 run or k6 cloud run --local-execution). When running tests on Grafana Cloud k6, only official extensions are allowed.

Check out the new extensions documentation for additional details.

Handling of NaN and Infinity float values in gRPC #4631

Previously, float values of NaN or Infinity were marshalled as null. This has now changed to use their string representation, aligning with other gRPC APIs.

There are no changes required in the scripts.

This is also the first contribution by @ariasmn. Thank you @ariasmn for taking the time to make the PR and answer all our questions.

Health check for gRPC APIs #4853

The k6 gRPC module now has a client.healthCheck() method that simplifies checking the status of a gRPC service. This method eliminates the need for manual invoke calls, making it particularly useful for readiness checks and service discovery.

Before, you had to write boilerplate code to perform a health check:

import grpc from 'k6/grpc';

const client = new grpc.Client();
// ...
const response = client.invoke('grpc.health.v1.Health/Check', { service: 'my-service' });

Now, you can simplify this with the healthCheck() method:

import grpc from 'k6/grpc';

const client = new grpc.Client();
client.connect('grpc.test.k6.io:443');

// Check the health of a specific service
const response = client.healthCheck('my-service');

// Check the health of the overall gRPC server
const overallResponse = client.healthCheck();

client.close();

Check out the client.healthCheck documentation for additional details.
Thank you, @tbourrely, for contributing this feature.

Assertions Library (Preview) #4067

k6 now provides an assertions library to help you verify your application behaves as expected during testing.

The library introduces the expect function with a set of expressive matchers. Pass a value to expect() and chain it with a matcher that defines the expected outcome. The library caters to both protocol testing HTTP/API and browser testing scenarios.

The API is inspired by Playwright's assertion syntax, offering a fluent interface for more readable and reliable tests.

import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import { browser } from 'k6/browser';
import http from 'k6/http';

export function protocolTest() {
  // Get the home page of k6's Quick Pizza app
  const response = http.get('https://quickpizza.grafana.com/');

  // Simple assertions
  expect(response.status).toBe(200);
  expect(response.error).toEqual('');
  expect(response.body).toBeDefined();
}

export async function browserTest() {
  const page = await browser.newPage();

  try {
    await page.goto('https://quickpizza.grafana.com/');

    // Assert the "Pizza Please" button is visible
    await expect(page.locator('button[name=pizza-please]')).toBeVisible();
  } finally {
    await page.close();
  }
}

export const options = {
  scenarios: {
    // Protocol tests
    protocol: {
      executor: 'shared-iterations',
      vus: 1,
      iterations: 1,
      exec: 'protocolTest',
    },

    // Browser tests
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
      exec: 'browserTest',
    },
  },
};

Preview feature

This feature is ready to use, but still in preview:

  • No breaking changes are neither planned, nor expected.
  • Some functionality may be missing or rough around the edges.
  • We expect to keep adding matchers and improving coverage.

We welcome your feedback, and invite you to share your suggestions and contributions on GitHub.

Add page.getByRole API #4843

The browser module now supports page.getByRole(), which allows you to locate elements based on their ARIA roles. This provides a more semantic and accessible way to find elements, making your tests more robust and aligned with how users actually interact with web applications.

ARIA roles represent the purpose or function of an element (like button, link, textbox, etc.), making them excellent selectors for testing since they're less likely to change when the UI is refactored compared to CSS classes or IDs.

Example usage:

// Find elements by role
await page.getByRole('button').click();

// Find elements by role and accessible name
await page.getByRole('button', { name: 'Submit' }).click();

// `name` works with regex too
await page.getByRole('textbox', { name: /^Username$/ }).fill('admin');

// Work with specific states
await page.getByRole('checkbox', { name: 'Accept terms', checked: true }).click();

// Find headings by level
await page.getByRole('heading', { level: 2, name: 'Section Title' }).textContent();

### Add `page.getByAltText` [#4881](https://github.com/grafana/k6/pull/4881)

The browser module now includes `page.getByAltText()`, which provides a convenient way to select elements that have an `alt` text attribute. This is particularly useful for locating images or other elements that rely on alternative text for accessibility.

Previously, you would have to use CSS or XPath selectors to find these elements:
```javascript
// Using CSS selector
const locator = page.locator('img[alt="World Map"]');

// Using XPath selector
const locator = page.locator('//img[@alt="World Map"]');

Now, you can simplify this by using getByAltText():

const locator = page.getByAltText('World Map');

// Find an image with alt text that starts with 'World'
const locator = page.getByAltText(/^World/);

Add page.getByLabel #4890

The browser module now includes page.getByLabel(), which provides a convenient way to locate form elements and other interactive components by their associated label text. This method works with both explicit <label> elements and elements that have an aria-label attribute, making it particularly useful for finding form inputs, buttons, and other interactive elements.

Previously, you would need to use XPath selectors to find elements by their label text, since CSS selectors cannot easily handle the relationship between labels and form elements:

// Using XPath to find input by label text  
const locator = page.locator('//label[text()="Password"]');

// Or using aria-label with CSS
const locator = page.locator('[aria-label="Username"]');

Now, you can simplify this with getByLabel():

// Works with both <label> elements and aria-label attributes
const passwordInput = page.getByLabel('Password');

// Works with regex too
const usernameInput = page.getByLabel(/^Username$/);

A...

Read more

v1.2.0

13 Aug 09:51
Compare
Choose a tag to compare

k6 v1.2.0 is here 🎉! This release includes:

  • Automatic extension resolution (previously Binary Provisioning) enabled for everyone
  • gRPC gets better handling of NaN and Infinity float values and easier health check
  • Browser module gets page.route, all the page.getBy* APIs, locator.all(), and page.waitForURL

Breaking changes

As per our stability guarantees,
breaking changes across minor releases are allowed only for experimental features.

Breaking changes for experimental modules

  • The experimental Open Telemetry and Prometheus outputs now default to TLSv1.3. This should've been the default to begin with. It is not expected that anyone should be affected, apart from making it more secure for the metrics output to send messages.

New features

Automatic extension resolution

k6 extensions allow you to add custom functionality to your tests, such as connecting to databases, message queues, or specialized networking protocols. Previously, using extensions required manual building of a custom k6 binary with the extensions compiled in. This new version introduces the Automatic Extension Resolution functionality, previously named Binary Provisioning, which is enabled by default and automatically detects when your script imports extensions and handles the complexity of provisioning the right k6 binary for you.

import faker from "k6/x/faker";

export default function () {
  console.log(faker.person.firstName());
}

The previous experimental versions only supported official extensions. #4922 added the support to use any extension listed in the community list by setting the K6_ENABLE_COMMUNITY_EXTENSIONS environment variable.

K6_ENABLE_COMMUNITY_EXTENSIONS=true k6 run script.js

Note, Community extensions are only supported for local test executions (using k6 run or k6 cloud run --local-execution). When running tests on Grafana Cloud k6, only official extensions are allowed.

Check out the new extensions documentation for additional details.

Handling of NaN and Infinity float values in gRPC #4631

Previously, float values of NaN or Infinity were marshalled as null. This has now changed to use their string representation, aligning with other gRPC APIs.

There are no changes required in the scripts.

This is also the first contribution by @ariasmn. Thank you @ariasmn for taking the time to make the PR and answer all our questions.

Health check for gRPC APIs #4853

The k6 gRPC module now has a client.healthCheck() method that simplifies checking the status of a gRPC service. This method eliminates the need for manual invoke calls, making it particularly useful for readiness checks and service discovery.

Before, you had to write boilerplate code to perform a health check:

import grpc from 'k6/grpc';

const client = new grpc.Client();
// ...
const response = client.invoke('grpc.health.v1.Health/Check', { service: 'my-service' });

Now, you can simplify this with the healthCheck() method:

import grpc from 'k6/grpc';

const client = new grpc.Client();
client.connect('grpc.test.k6.io:443');

// Check the health of a specific service
const response = client.healthCheck('my-service');

// Check the health of the overall gRPC server
const overallResponse = client.healthCheck();

client.close();

Check out the client.healthCheck documentation for additional details.
Thank you, @tbourrely, for contributing this feature.

Assertions Library (Preview) #4067

k6 now provides an assertions library to help you verify your application behaves as expected during testing.

The library introduces the expect function with a set of expressive matchers. Pass a value to expect() and chain it with a matcher that defines the expected outcome. The library caters to both protocol testing HTTP/API and browser testing scenarios.

The API is inspired by Playwright's assertion syntax, offering a fluent interface for more readable and reliable tests.

import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import { browser } from 'k6/browser';
import http from 'k6/http';

export function protocolTest() {
  // Get the home page of k6's Quick Pizza app
  const response = http.get('https://quickpizza.grafana.com/');

  // Simple assertions
  expect(response.status).toBe(200);
  expect(response.error).toEqual('');
  expect(response.body).toBeDefined();
}

export async function browserTest() {
  const page = await browser.newPage();

  try {
    await page.goto('https://quickpizza.grafana.com/');

    // Assert the "Pizza Please" button is visible
    await expect(page.locator('button[name=pizza-please]')).toBeVisible();
  } finally {
    await page.close();
  }
}

export const options = {
  scenarios: {
    // Protocol tests
    protocol: {
      executor: 'shared-iterations',
      vus: 1,
      iterations: 1,
      exec: 'protocolTest',
    },

    // Browser tests
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
      exec: 'browserTest',
    },
  },
};

Preview feature

This feature is ready to use, but still in preview:

  • No breaking changes are neither planned, nor expected.
  • Some functionality may be missing or rough around the edges.
  • We expect to keep adding matchers and improving coverage.

We welcome your feedback, and invite you to share your suggestions and contributions on GitHub.

Add page.getByRole API #4843

The browser module now supports page.getByRole(), which allows you to locate elements based on their ARIA roles. This provides a more semantic and accessible way to find elements, making your tests more robust and aligned with how users actually interact with web applications.

ARIA roles represent the purpose or function of an element (like button, link, textbox, etc.), making them excellent selectors for testing since they're less likely to change when the UI is refactored compared to CSS classes or IDs.

Example usage:

// Find elements by role
await page.getByRole('button').click();

// Find elements by role and accessible name
await page.getByRole('button', { name: 'Submit' }).click();

// `name` works with regex too
await page.getByRole('textbox', { name: /^Username$/ }).fill('admin');

// Work with specific states
await page.getByRole('checkbox', { name: 'Accept terms', checked: true }).click();

// Find headings by level
await page.getByRole('heading', { level: 2, name: 'Section Title' }).textContent();

### Add `page.getByAltText` [#4881](https://github.com/grafana/k6/pull/4881)

The browser module now includes `page.getByAltText()`, which provides a convenient way to select elements that have an `alt` text attribute. This is particularly useful for locating images or other elements that rely on alternative text for accessibility.

Previously, you would have to use CSS or XPath selectors to find these elements:
```javascript
// Using CSS selector
const locator = page.locator('img[alt="World Map"]');

// Using XPath selector
const locator = page.locator('//img[@alt="World Map"]');

Now, you can simplify this by using getByAltText():

const locator = page.getByAltText('World Map');

// Find an image with alt text that starts with 'World'
const locator = page.getByAltText(/^World/);

Add page.getByLabel #4890

The browser module now includes page.getByLabel(), which provides a convenient way to locate form elements and other interactive components by their associated label text. This method works with both explicit <label> elements and elements that have an aria-label attribute, making it particularly useful for finding form inputs, buttons, and other interactive elements.

Previously, you would need to use XPath selectors to find elements by their label text, since CSS selectors cannot easily handle the relationship between labels and form elements:

// Using XPath to find input by label text  
const locator = page.locator('//label[text()="Password"]');

// Or using aria-label with CSS
const locator = page.locator('[aria-label="Username"]');

Now, you can simplify this with getByLabel():

// Works with both <label> elements and aria-label attributes
const passwordInput = page.getByLabel('Password');

// Works with regex too
const usernameInput = page.getByLabel(/^Username$/);

Add page.getByPlaceholder #4904

The browser module now includes page.getByPlaceholder(), which provides a convenient way to locate form elements by their placeholder text. This is particularly useful for finding input fields, textareas, and other form controls that use placeholder text to guide user input.

Previously, you would need to use CSS or XPath selectors to find elements by their placeholder attribute...

Read more

v1.1.0

25 Jun 14:10
0e3fb95
Compare
Choose a tag to compare

k6 v1.1.0 is here 🎉! This release includes:

  • New count, nth, first, and last methods for the browser module's Locator API #4797, #4825
  • The k6/experimental/webcrypto module has been removed as its functionality is available globally.
  • Group results in the full end-of-test summary are now sorted as in code and properly indented.

Breaking changes

As per our stability guarantees,
breaking changes across minor releases are allowed only for experimental features.

Breaking changes for experimental modules

Remove experimental k6/experimental/webcrypto module #4851

The WebCrypto API has been available globally since v1.0.0-rc1 (or v0.58.0), and now the experimental import (k6/experimental/webcrypto) is no longer available.

The required change for users is to remove the import; the rest of the code should work.

New features

New count method for the browser module's Locator API #4797

The new locator.Count method returns the number of elements matching the locator. Unlike other Locator API methods, locator.Count returns the result immediately and doesn't wait for the elements to be visible.

import { expect } from "https://jslib.k6.io/k6-testing/0.4.0/index.js";
import { browser } from 'k6/browser'

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
}

export default async function () {
  const page = await browser.newPage()
  await page.goto('https://quickpizza.grafana.com/login')

  expect(await page.locator('input').count()).toEqual(3);

  await page.close();
}

New nth, first and last methods for the browser module's Locator API #4825

The new Locator API methods, nth, first, and last, can select a single element from multiple elements matched by a locator. For example, selecting a single item from a catalogue of items on an e-commerce website. Because items in this catalogue generally change often and selecting an exact element may fail in future test runs, the new methods help to prevent flaky tests, leading to more reliable tests.

import { expect } from "https://jslib.k6.io/k6-testing/0.4.0/index.js";
import { browser } from 'k6/browser'

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
}

export default async function () {
  const page = await browser.newPage()
  await page.goto('https://quickpizza.grafana.com')

  await expect(await page.locator('p').first()).toContainText('QuickPizza');
  await expect(await page.locator('p').nth(4)).toContainText('QuickPizza Labs.');
  await expect(await page.locator('p').last()).toContainText('Contribute to QuickPizza');

  await page.close();
}

UX improvements and enhancements

  • #4807 Sorts full end-of-test summary group results as in code and fixes the indentation. Thanks, @the-it, for the contribution!
  • #4832 Uses consistent error messages in the execution config options.

Bug fixes

  • #4794 Fixes race conditions from stringifying types in k6/browser.
  • #4809 Fixes the locator.fill method when used on react based websites.
  • #4831 Fixes the Dockerfile for k8s use by setting the user to 12345 instead of k6 to avoid having to work with runAsUser in the pod manifest file.
  • #4845 Fixes an infrequent panic when click is called.

Maintenance and internal improvements

  • #4608 Enables the 'copyloopvar' linter.
  • #4744 Updates the 'golangci-lint' linter to v2.
  • #4746 Adds a collection of small k6/browser performance improvements.
  • #4750 Fixes the lint GHA.
  • #4775 Updates the version of the golangci-lint GHA.
  • #4784 Fixes the golangci-lint version detection and execution. Thanks, @tbourrely, for the contribution!
  • #4785 Updates the chromedp/cdproto dependency and adjusts the Browser module accordingly.
  • #4800 Allows un/marshaling of invalid UTF-8 when using JSONv2 within the Browser module.
  • #4802 Fixes the examples/grpc_server and updates its dependencies.
  • #4822 Uses the CODECOV_TOKEN variable for GH Workflows from Vault.
  • #4831 Fixes the default user defined in the Dockerfile.
  • #4833 Retrieves secrets from Vault and adjusts the 'k6packager' deployment process.
  • #4837, #4847 Prevent Codecov from running on forks.
  • #4848 Enables CI pipelines to be executed also on ARM (ubuntu-24.04-arm). Thanks, @nadiamoe, for the contribution!
  • #4855 Adds some changes to make Browser tests more stable.
  • #4780, #4781, #4782, #4786, #4798, #4816, #4821, #4835, #4840 Update direct dependencies.
  • #4864 Updates the logging to debug and adds more context to it when waiting for an element to be detached.

Roadmap

Official Testing/Assertions Module

We're working to integrate a built-in testing and assertions module that's compatible with Playwright's in k6. You can try the current implementation using the k6 testing jslib, which serves as our work-in-progress implementation for what will become the official k6/test module (final name TBD). We'd love your feedback on issue #4805.

Enhanced Machine-Readable Test Results

We're developing the next version of k6's end-of-test summary to make it easier to integrate test results into CI/CD pipelines and automated workflows. This new format will be officially supported, versioned, and designed specifically for programmatic use. Follow our progress, and provide us with feedback on issue #4803.

v1.0.0

06 May 10:53
41b4984
Compare
Choose a tag to compare

Grafana k6 v1.0 is here! 🎉

After 9 years of iteration and countless community contributions, we're thrilled to announce Grafana k6 v1.0.

While many features and capabilities in this release were introduced gradually in previous versions, k6 v1.0 marks a turning point: a commitment to stability, formal support guarantees, and transparency in how we evolve and develop the project from here. This milestone is more than a version number; it's about trust, reliability, and empowering you to test confidently.

Thank you, k6 community! 🌍

This release wouldn't be possible without you:

  • ⭐️ 27000+ GitHub stars.
  • 🧠 9000+ git commits.
  • 🤝 200+ contributors.
  • 🔁 Countless test runs of any scale, in every timezone.

It's been amazing to watch k6 grow from a simple load testing command-line tool into a comprehensive reliability tool, used by teams worldwide and supported by a passionate and dedicated community.

To everyone who filed bugs, built extensions and libraries, or championed k6:️
Thank you! You've shaped what k6 is today. 🙇‍♂️

What's New in k6 1.0?

1. Stability You Can Build On

  • Semantic Versioning: k6 now follows Semantic Versioning 2.0. Breaking changes will only happen in major releases, with prior deprecation warnings.
  • 🔒 2-Year Support Guarantees: Every major version will be supported with critical fixes for at least two years; upgrade on your schedule.
  • 📦 Public API Surface: We've established a clearly delineated and supported API surface for the k6 codebase. Extensions, integrations, and projects building on top of the k6 code now have a stable foundation to rely on.

🔎 Read more in our versioning and stability guarantees guide.

2. First-Class TypeScript Support

Write type-safe and maintainable tests—no transpilation needed. Simply save your file with a .ts extension and run it directly using k6 run script.ts.

import http from 'k6/http';  

// PizzaRequest defines the request body format the quickpizza API expects
export interface PizzaRequest {
    maxCaloriesPerSlice: number;
    mustBeVegetarian: boolean;
}

export default function () {  
    const payload: PizzaRequest = {
        maxCaloriesPerSlice: 500, // Type-checked!  
        mustBeVegetarian: true,
    }

  http.post(
    'https://quickpizza.grafana.com/api/pizza',
    JSON.stringify(payload),
    { 
        headers: { 
          "Content-Type": "application/json",
          "Authorization": "Token " + "abcdef0123456789"
        } as Record<string, string>
    });  
}  

3. Extensions Made Simple

With k6 v1.0, extensions now work out of the box in k6 cloud run and k6 cloud run --local-execution. Support for k6 run is coming soon.

✅ No more xk6 toolchain.
✅ No manual builds.
✅ Import an extension's module and go.

import faker from 'k6/x/faker';

export default function () {
  console.log(faker.person.firstName());
}

To try the experimental feature, first enable its feature flag, then run it on Grafana Cloud with the following command:

K6_BINARY_PROVISIONING=true k6 cloud run script.js,

or if you want to run it locally and stream the results to Grafana Cloud then use:

K6_BINARY_PROVISIONING=true k6 cloud run --local-execution script.js

4. Revamped test summary

The new end-of-test summary makes it easier to understand results and spot issues:

  • 📊 Hierarchical output: Metrics are grouped by scenario, group, and category.
  • Improved thresholds & checks: Clearer layout for faster debugging.
  • 🔍 Multiple summary modes:
    • compact (default): big picture results, focusing on essentials.
    • full: full picture results, providing granularity.
k6 run --summary-mode=full script.ts

end-of-test-summary

5. Quality of Life Upgrades

  • Stable modules: k6/browser, k6/net/grpc, and k6/crypto are now production-ready.
  • Improved Grafana Cloud integration: Stream local test results to Grafana Cloud with k6 cloud run --local-execution.

v1.0.0-rc2

05 May 10:03
fbe82ca
Compare
Choose a tag to compare

k6 v1.0.0-rc2 is here 🎉!

Continuing our commitment beyond the v1.0.0 release, we are pleased to announce a new release candidate that includes several significant changes:

  • Native support for extensions in the Cloud
  • New test failure control with execution.test.fail

New features

Native support for extensions in the Cloud #4671

The new Binary Provisioning feature automatically requests and uses custom k6 binaries with the required extensions for your tests. This allows you to run scripts that use extensions without manually rebuilding k6 as it was in the past by depending on tools like xk6. The system caches binaries locally for efficiency, and any additional runs with the same dependencies will use the same binary and will run faster.

Binary Provisioning is available for all k6 Cloud users (free and paid plans). It is an experimental feature, it's enabled by opt-in with the feature flag K6_BINARY_PROVISIONING=true.

Binary provisioning is a limited set of extensions that are supported, and it's not available for the k6 run command that might be added in the future. However, local development is supported with the k6 cloud run --local-execution command if a cloud token is provided by the canonical login methods.
Check out the documentation for additional details.

Test failure control with execution.test.fail #4672

The new execution.test.fail function allows you to explicitly fail a test while letting it continue execution until completion. This gives you more control over test outcomes while still collecting all metrics and completing necessary cleanup tasks.

UX improvements and enhancements

  • #4698 Displays threshold values even when are not configured in summaryTrendStats option.
  • #4699 Drops the link of the legacy k6 website from the user agent.

Bug fixes

  • #4717 Safeguards against pressedKeys being updated concurrently in the browser module.
  • #4665 Prevents race condition between Ended & Interrupted execution states.
  • #4677 Makes secretsource also redact float32 and float64 values.

Maintenance and internal improvements

  • #4675, #4676, #4678 Move several packages to internal as preparations for v1.0.0 stabilization
  • #4686 Drops the redundant NO_COLOR detection.
  • #4709 Fixes JS native objects override to avoid a page under the test from overwriting native JavaScript objects, like Set and Map.
  • #4726 Unifies the internal/cmd.Execute methods.
  • #4703 Makes wptTests run without tags or skip if repos not checkout.
  • #4701 Fixes WebCrypto errors not propagating from the tests.
  • #4691, #4674, #4673, #4663 Bumps the versions for OpenTelemetry, grpc, golang/x and esbuild dependencies.
  • #4691 Bumps x509roots/fallback dependency for fallback certificates.
  • #4739 Removes deprecated GetLayoutMetrics.VisualViewport CDP usage.

v0.59.0

05 May 13:38
Compare
Choose a tag to compare

The v0.59.0 release mirrors the previous v1.0.0-rc2 release to allow automation tools to recognize it as the latest version.
For example, Homebrew's k6 formulae and pkg.go.dev do not automatically fetch unstable versions such as v1.0.0-rc2, which is legitimately the expected behavior for these tools.

However, this has been the default for all previous v0.* releases, where they were considered the latest stable version—even if they were under a version typically associated with unstable releases. To address this, we will continue releasing mirrored versions under v0.* for necessary release candidates.

This practice will end once the official stable v1.0.0 release is available, after which we will follow the standard SemVer lifecycle to simplify the workflow for everyone.

The release notes for v1.0.0-rc2 provide a detailed look at all the changes that have been implemented since v1.0.0-rc1/v0.58.0 and are now part of this version.

v0.58.0

31 Mar 09:19
02fdc80
Compare
Choose a tag to compare

The v0.58.0 release mirrors the previous v1.0.0-rc1 release to allow automation tools to recognize it as the latest version.
For example, Homebrew's k6 formulae and pkg.go.dev do not automatically fetch unstable versions such as v1.0.0-rc1, which is legitimately the expected behavior for these tools.

However, this has been the default for all previous v0.* releases, where they were considered the latest stable version—even if they were under a version typically associated with unstable releases. To address this, we will continue releasing mirrored versions under v0.* for necessary release candidates.

This practice will end once the official stable v1.0.0 release is available, after which we will follow the standard SemVer lifecycle to simplify the workflow for everyone.

The release notes for v1.0.0-rc1 provide a detailed look at all the changes that have been implemented since v0.57.0 and are now part of this version.

v1.0.0-rc1

25 Mar 14:44
a4e5ae1
Compare
Choose a tag to compare

k6 v1.0.0-rc1 is here 🎉!

This release marks a special, non-conventional milestone in the k6 software life-cycle, serving as a preview of the upcoming version 1.0.0.

The purpose of this release is to give the community a chance to test the new version, identify any potential issues, and test migrations of any parts affected by breaking changes. If you encounter any problems or have trouble with the migration, we encourage you to report them by creating an issue. Your feedback will help improve the final release. If no critical issues are reported, we plan to release the final v1.0.0 within the next month.

Here’s a glimpse of what’s new in this release:

  • k6/experimental/webcrypto promoted to stable and available globally under crypto.
  • A revamped end-of-test summary aiming to bring an easier way to understand test results.
  • k6/browser provided an API for tracking network requests and responses.
  • The new k6/secrets module for retrieving secrets with extension support.

Breaking changes

  • #4541 Commas(,) are now supported in the values of the --tag CLI flag. This is a breaking change, as previously, a comma meant the start of a new set of tag-values. As a comma is a valid symbol for the value of a tag, this is necessary to have equivalency between different ways of setting tags. This still allows multiple tags to be set on the CLI with multiple --tag key=value arguments.

A new default path for the configuration file #4301

When running the k6 cloud login or the deprecated k6 login commands, a configuration file was automatically created at {USER_CONFIG_DIR}/loadimpact/config.json. Now, the configuration file is created at {USER_CONFIG_DIR}/k6/config.json.

To migrate your configuration file to the new path:

  1. Run k6 cloud login or k6 login to automatically migrate the configuration file to the new location.
  2. Run k6 cloud run or k6 run to verify that the version is now fully functional and no related warning is emitted.

The configuration file in the old path remains available and can continue to be used with the previous k6 versions. If you're not using an old version of k6 anymore, consider deleting the files manually.

The k6 run commands search for the configuration file in the new location. If it can't find it, it tries to fall back on the old path and then logs a warning message suggesting to migrate it.

New features

A revamped end-of-test summary aiming to bring an easier way to understand test results #4089, #4649

The end-of-test-summary has been revamped to make it easier for users to understand test results. That includes:

  • A new format to summarize the results of the user-defined Checks and Thresholds.
  • Now metrics are split into different sections, making it easier to focus on what really matters.

End of test summary example

The new end-of-test summary is enabled by default for users, but you can use the summary-mode flag to choose between different modes:

  • compact (default): what you can see in the example above, with the most relevant information.
  • full: similar to compact, but also includes some more detailed metrics and results for each group and scenario defined in the test.
  • legacy: the old summary format for backward compatibility.

Note: The data structure received by the handleSummary function,
as well as the data exported using --summary-export, has not changed in this release. However, these may change in upcoming releases, which could introduce breaking changes.

Browser: Tracking network requests and responses #4290, #4296

The browser module adds support for tracking network requests and responses. This feature is especially useful for validating certain aspects of the requests and responses to determine whether the test was successful. It can also be used to debug issues with the test script or the tested application. Refer to the documentation for more details.

For example, to track all requests and responses made by a page, you can use the following script:

import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
};

export default async function () {
  const page = await browser.newPage();

  // registers a handler that logs all requests made by the page
  page.on('request', async request => console.log(request.url()));
  // registers a handler that logs all responses received by the page
  page.on('response', async response => console.log(response.url()));

  await page.goto('https://quickpizza.grafana.com/', { waitUntil: 'networkidle' });
  await page.close();
}

The output might look like this:

INFO[0000] https://quickpizza.grafana.com/                  source=console
INFO[0001] https://quickpizza.grafana.com/api/tools         source=console
INFO[0001] https://quickpizza.grafana.com/images/pizza.png  source=console
...

k6/experimental/webcrypto promoted to stable and available globally under crypto #4278

With this release, the k6/experimental/webcrypto module is promoted to stable and available globally under crypto. That means you can remove the import { crypto } from 'k6/experimental/webcrypto'; statement from your scripts and still use the module.

export default function () {
  const myUUID = crypto.randomUUID();

  console.log(myUUID);
}

k6/experimental/webcrypto is deprecated and will be removed in v1.1.0.

Support for custom templates in k6 new command #4618

The k6 new command now accepts a path to a file to use as a template for the new script. Templates use Go templates syntax and can include the following variables:

  • ScriptName: The name of the new script.
  • ProjectID: The ID of the Grafana Cloud project to use for the new script.

To generate a new script using a custom template, use the following command:

k6 new --template /path/to/my-template.js

Secret Sources #4514, #4621, #4637

We've added support for retrieving secrets from different sources. Among other things, this means that the values received from a secret source will be redacted from the logs. Refer to the documentation for more details.

The two implementations available are to read secrets from a key-value file or from CLI flags, which are meant mostly to test the feature. We've also included extension support, which can be used to implement retrieving secrets from more secure sources.

In the future, we'll likely include additional implementations that are more production-ready.

Here's an example where we log the secret directly, make a request, and then log the whole response. In both cases, the secrets are redacted from the logs.

import http from 'k6/http';
import secrets from 'k6/secrets';

export default async () => {
  const my_secret = await secrets.get('cool'); // get secret from a source with the provided identifier
  console.log(my_secret);
  const response = await http.asyncRequest("GET", "https://httpbin.org/get", null, {
    headers: {
      "Custom-Authentication": `Bearer ${await secrets.get("else")}`,
    }
  })
  console.log(response.body)
}
$ k6 run --secret-source=mock=cool="not cool secret",else="totally a secret" script.js
...
INFO[0000] ***SECRET_REDACTED***                         source=console
INFO[0031] {
  "args": {},
  "headers": {
    "Custom-Authentication": "Bearer ***SECRET_REDACTED***",
    "Host": "httpbin.org",
    "User-Agent": "k6/1.0.0-rc1 (https://k6.io/)",
    "X-Amzn-Trace-Id": "Root=1-67dd6691-18eeaf5d1782bf292da5037c"
  },
  "origin": "1.1.1.1",
  "url": "https://httpbin.org/get"
}  source=console
...

UX improvements and enhancements

  • #4547 The k6 banner now outputs with the original TrueColor (24-bit) logo only if the terminal supports it.
  • #4590 Moves the docker-compose example with InfluxDB to the examples/docker-compose directory and adds an opentelemetry example.
  • #4602, #4629 Improves the error message on options error from script. k6 now will try to print the part of the options that fails as JSON.
  • #4612 Updates the link included in the local modules' error message. Thanks, @tanurrra!

Bug fixes

  • #4544 Fixes race in ReadableStream.cancel and run WPT test with race detection for easier finding of similar pro...
Read more