Skip to content

Conversation

elastic-renovate-prod[bot]
Copy link
Contributor

@elastic-renovate-prod elastic-renovate-prod bot commented May 7, 2025

This PR contains the following updates:

Package Type Update Change
go.k6.io/k6 require major v0.56.0 -> v1.2.3

Release Notes

grafana/k6 (go.k6.io/k6)

v1.2.3

Compare Source

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

Compare Source

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

Compare Source

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://redirect.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:

// Using CSS selector
const locator = page.locator('input[placeholder="Enter your name"]');

// Using XPath selector  
const locator = page.locator('//input[@&#8203;placeholder="Enter your name"]');

Now, you can simplify this with getByPlaceholder():

const nameInput = page.getByPlaceholder('Enter your name');

// Works with regex too
const emailInput = page.getByPlaceholder(/^Email/);
Add page.getByTitle #​4910

The browser module now includes page.getByTitle(), which provides a convenient way to locate elements by their title attribute. This is particularly useful for finding tooltips, buttons, or any other elements that use the title attribute to provide extra information.

Previously, you would need to use CSS or XPath selectors to find these elements:

// Using CSS selector
const locator = page.locator('div[title="Information box"]');

// Using XPath selector
const locator = page.locator('//div[@&#8203;title="Information box"]');

Now, you can simplify this with getByTitle():

const infoBox = page.getByTitle('Information box');

// Works with regex too
const saveButton = page.getByTitle(/^Save/);
Add page.getByTestId #​4911

The browser module now includes page.getByTestId(), which provides a convenient way to locate elements by their data-testid attribute. This is particularly useful for creating resilient tests that are not affected by changes to the UI, since data-testid attributes are specifically added for testing purposes and are not expected to change.

Previously, you would need to use CSS or XPath selectors to find these elements:

// Using CSS selector
const locator = page.locator('button[data-testid="submit-button"]');

// Using XPath selector
const locator = page.locator('//button[@&#8203;data-testid="submit-button"]');

Now, you can simplify this with getByTestId():

const submitButton = page.getByTestId('submit-button');

// Works with regex too
const usernameInput = page.getByTestId(/^username/);
Add page.getByText #​4912

The browser module now includes page.getByText(), which allows you to locate elements by their text content. This provides a convenient way to find elements like buttons, links, and other interactive components that are identified by their visible text.

Previously, you would need to use XPath selectors to find elements by their text content, since CSS selectors cannot directly query the text of an element:

// Using XPath selector
const locator = page.locator('//div[text()="Hello World"]');

Now, you can simplify this with getByText():

const helloWorldElement = page.getByText('Hello World');

// Works with regex too
const submitButton = page.getByText(/^Submit/);
Add page.route #​4953 #​4961, #​4971, #​4985

The browser module now supports page.route(), which allows you to intercept and handle network requests before they are sent. This is particularly useful for testing scenarios where you need to mock API responses, block certain resources, or modify request behavior.

The route handler receives a route object that provides methods to abort(), continue(), or fulfill() the request.

You can use page.route() to:

  • Block requests: Prevent certain resources from loading (e.g., images, ads, analytics) with abort().
    // Block all image requests
    await page.route(/(\.png$)|(\.jpg$)|(\.jpeg$)/, async (route) => {
        await route.abort();
    });
  • Mock responses: Return custom responses without hitting real endpoints with fulfill().
    // Mock API responses
    await page.route('**/api/users', async (route) => {
        await route.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify([{ id: 1, name: 'Mock User' }])
        });
    });
  • Modify requests: Change headers, URL, or request body before they're sent with continue().
    // Continue with modified headers
    await page.route('**/api/**', async (route) => {
        await route.continue({
            headers: {
            ...route.request().headers(),
            'Authorization': 'Bearer mock-token'
            }
        });
    });
Add locator.all() #​4899

The browser module now supports the locator.all() method, which returns an array of locators for all elements matching the selector. This is particularly useful when you need to interact with multiple similar elements on a page, such as items in a list or multiple buttons with the same styling.

Example usage:

// Get all list items and iterate through them
const items = await page.locator('li').all();
for (const item of items) {
  console.log(await item.textContent());
}
Add waitForURL in frame and page #​4917, #​4920

The browser module now includes the waitForURL method for both page and frame objects.

As a prerequiste to this enhancement, waitForNavigation now accepts a url option. This also allows you to wait for a specific URL during navigation. It is advised that you work with waitForURL instead.

The waitForURL method first checks if the current page URL already matches the expected pattern. If it does, it waits for the load state to complete. Otherwise, it waits for a navigation to the specified URL. This approach prevents race conditions where a page might complete navigation before the wait condition is set up, which is particularly useful when dealing with pages that perform multiple redirects. It supports both string patterns and regular expressions:

// Wait for navigation to a specific URL
await Promise.all([
  page.waitForURL('https://quickpizza.grafana.com/my_messages.php'),
  page.locator('a[href="/my_messages.php"]').click(),
]);

// Using regex pattern
await Promise.all([
  page.waitForURL(/.*\/contacts\.php.*/),
  page.locator('a[href^="/contacts.php"]').click()
]);

While waitForURL provides a convenient way to wait for specific URLs, we still recommend using element-based waiting strategies or the locator API with its built-in auto-waiting capabilities for more reliable tests.

UX improvements and enhancements

  • #​4878 Do not report NaN percentages when there are no checks in the end of test summary. Thank you @​Fernando-hub527 for the fix.
  • #​4897 Support string-labels in locator.selectOption in the browser module.
  • #​4898 Add support for authority pseudo header to the gRPC module. Thank you @​Oursin for the changes.
  • #​4916 Print errors more consistently and correctly.
  • #​4918 Surface navigation errors from navigation events in the browser module.
  • #​4919 page.url() now doesn't make a call to the browser but instead uses a cached version. Making it a lot faster and aligned with playwright.
  • #​4932 Making it more clear that the requests were aborted in the browser module.
  • #​4944 Add Prometheus metrics endpoint. Thank you @​gouthamve.
  • #​5040 Use new expect() syntax in script templates.
  • #​4976 Align metrics in end of test summary with using less dots and less horizontal space.

Bug fixes

  • #​4850 Fixes incorrect conversions between integer types in the browser module.
  • #​4973 Fixes panic when BrowserContext is requested before creating a Page in the browser module.
  • #​4975 Fixes potential race conditions in the browser module.
  • #​5015 Fixes waitForNavigation now blocking the iteration from ending if page.close is not called.
  • #​5017 Fixes potential race conditions in gRPC module, when it gets protobuf defintions from remote server.

Maintenance and internal improvements

v1.2.0

Compare Source

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` [#&#8203;4881](https://redirect.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[@&#8203;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:

// Using CSS selector
const locator = page.locator('input[placeholder="Enter your name"]');

// Using XPath selector  
const locator = page.locator('//input[@&#8203;placeholder="Enter your name"]');

Now, you can simplify this with getByPlaceholder():

const nameInput = page.getByPlaceholder('Enter your name');

// Works with regex too
const emailInput = page.getByPlaceholder(/^Email/);
Add page.getByTitle #​4910

The browser module now includes page.getByTitle(), which provides a convenient way to locate elements by their title attribute. This is particularly useful for finding tooltips, buttons, or any other elements that use the title attribute to provide extra information.

Previously, you would need to use CSS or XPath selectors to find these elements:

// Using CSS selector
const locator = page.locator('div[title="Information box"]');

// Using XPath selector
const locator = page.locator('//div[@&#8203;title="Information box"]');

Now, you can simplify this with getByTitle():

const infoBox = page.getByTitle('Information box');

// Works with regex too
const saveButton = page.getByTitle(/^Save/);
Add page.getByTestId #​4911

The browser module now includes page.getByTestId(), which provides a convenient way to locate elements by their data-testid attribute. This is particularly useful for creating resilient tests that are not affected by changes to the UI, since data-testid attributes are specifically added for testing purposes and are not expected to change.

Previously, you would need to use CSS or XPath selectors to find these elements:

// Using CSS selector
const locator = page.locator('button[data-testid="submit-button"]');

// Using XPath selector
const locator = page.locator('//button[@&#8203;data-testid="submit-button"]');

Now, you can simplify this with getByTestId():

const submitButton = page.getByTestId('submit-button');

// Works with regex too
const usernameInput = page.getByTestId(/^username/);
Add page.getByText #​4912

The browser module now includes page.getByText(), which allows you to locate elements by their text content. This provides a convenient way to find elements like buttons, links, and other interactive components that are identified by their visible text.

Previously, you would need to use XPath selectors to find elements by their text content, since CSS selectors cannot directly query the text of an element:

// Using XPath selector
const locator = page.locator('//div[text()="Hello World"]');

Now, you can simplify this with getByText():

const helloWorldElement = page.getByText('Hello World');

// Works with regex too
const submitButton = page.getByText(/^Submit/);
Add page.route #​4953 #​4961, #​4971, #​4985

The browser module now supports page.route(), which allows you to intercept and handle network requests before they are sent. This is particularly useful for testing scenarios where you need to mock API responses, block certain resources, or modify request behavior.

The route handler receives a route object that provides methods to abort(), continue(), or fulfill() the request.

You can use page.route() to:

  • Block requests: Prevent certain resources from loading (e.g., images, ads, analytics) with abort().
    // Block all image requests
    await page.route(/(\.png$)|(\.jpg$)|(\.jpeg$)/, async (route) => {
        await route.abort();
    });
  • Mock responses: Return custom responses without hitting real endpoints with fulfill().
    // Mock API responses
    await page.route('**/api/users', async (route) => {
        await route.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify([{ id: 1, name: 'Mock User' }])
        });
    });
  • Modify requests: Change headers, URL, or request body before they're sent with continue().
    // Continue with modified headers
    await page.route('**/api/**', async (route) => {
        await route.continue({
            headers: {
            ...route.request().headers(),
            'Authorization': 'Bearer mock-token'
            }
        });
    });
Add locator.all() #​4899

The browser module now supports the locator.all() method, which returns an array of locators for all elements matching the selector. This is particularly useful when you need to interact with multiple similar elements on a page, such as items in a list or multiple buttons with the same styling.

Example usage:

// Get all list items and iterate through them
const items = await page.locator('li').all();
for (const item of items) {
  console.log(await item.textContent());
}
Add waitForURL in frame and page #​4917, #​4920

The browser module now includes the waitForURL method for both page and frame objects.

As a prerequiste to this enhancement, waitForNavigation now accepts a url option. This also allows you to wait for a specific URL during navigation. It is advised that you work with waitForURL instead.

The waitForURL method first checks if the current page URL already matches the expected pattern. If it does, it waits for the load state to complete. Otherwise, it waits for a navigation to the specified URL. This approach prevents race conditions where a page might complete navigation before the wait condition is set up, which is particularly useful when dealing with pages that perform multiple redirects. It supports both string patterns and regular expressions:

// Wait for navigation to a specific URL
await Promise.all([
  page.waitForURL('https://quickpizza.grafana.com/my_messages.php'),
  page.locator('a[href="/my_messages.php"]').click(),
]);

// Using regex pattern
await Promise.all([
  page.waitForURL(/.*\/contacts\.php.*/),
  page.locator('a[href^="/contacts.php"]').click()
]);

While waitForURL provides a convenient way to wait for specific URLs, we still recommend using element-based waiting strategies or the locator API with its built-in auto-waiting capabilities for more reliable tests.

UX improvements and enhancements

  • #​4878 Do not report NaN percentages when there are no checks in the end of test summary. Thank you @​Fernando-hub527 for the fix.
  • #​4897 Support string-labels in locator.selectOption in the browser module.
  • #​4898 Add support for authority pseudo header to the gRPC module. Thank you @​Oursin for the changes.
  • #​4916 Print errors more consistently and correctly.
  • #​4918 Surface navigation errors from navigation events in the browser module.
  • #​4919 page.url() now doesn't make a call to the browser but instead uses a cached version. Making it a lot faster and aligned with playwright.
  • #​4932 Making it more clear that the requests were aborted in the browser module.
  • #​4944 Add Prometheus metrics endpoint. Thank you @​gouthamve.
  • #​5040 Use new expect() syntax in script templates.
  • #​4976 Align metrics in end of test summary with using less dots and less horizontal space.

Bug fixes

  • #​4850 Fixes incorrect conversions between integer types in the browser module.
  • #​4973 Fixes panic when BrowserContext is requested before creating a Page in the browser module.
  • #​4975 Fixes potential race conditions in the browser module.
  • #​5015 Fixes waitForNavigation now blocking the iteration from ending if page.close is not called.
  • #​5017 Fixes potential race conditions in gRPC module, when it gets protobuf defintions from remote server.

Maintenance and internal improvements

v1.1.0

Compare Source

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

Compare Source

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.


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

@elastic-renovate-prod
Copy link
Contributor Author

elastic-renovate-prod bot commented May 7, 2025

ℹ Artifact update notice

File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 20 additional dependencies were updated
  • The go directive was updated for compatibility reasons

Details:

Package Change
go 1.21.4 -> 1.23.0
golang.org/x/time v0.8.0 -> v0.12.0
github.com/go-logr/logr v1.4.2 -> v1.4.3
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 -> v2.27.1
github.com/mailru/easyjson v0.7.7 -> v0.9.0
github.com/mattn/go-colorable v0.1.13 -> v0.1.14
go.opentelemetry.io/otel v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/metric v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/sdk v1.29.0 -> v1.37.0
go.opentelemetry.io/otel/trace v1.29.0 -> v1.37.0
go.opentelemetry.io/proto/otlp v1.3.1 -> v1.7.1
golang.org/x/net v0.33.0 -> v0.43.0
golang.org/x/sys v0.28.0 -> v0.35.0
golang.org/x/text v0.21.0 -> v0.28.0
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd -> v0.0.0-20250728155136-f173205681a0
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd -> v0.0.0-20250728155136-f173205681a0
google.golang.org/grpc v1.67.1 -> v1.74.2
google.golang.org/protobuf v1.35.1 -> v1.36.7

@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/go.k6.io-k6-1.x branch from 28f7482 to 8ec237e Compare June 26, 2025 04:03
@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/go.k6.io-k6-1.x branch 2 times, most recently from 424f93e to 39fbdf6 Compare August 20, 2025 12:30
@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/go.k6.io-k6-1.x branch from 39fbdf6 to fc2bdd0 Compare August 28, 2025 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants