Note
This is a preview feature.
While we’re committed to supporting and maintaining this feature in the future (we do not anticipate breaking changes) some functionality might be missing; it might be a bit rough around the edges; and there might be use-cases we haven’t covered yet. The feature is considered ready to use, but it is in a preview state as we expect to keep iterating on it by adding new functionalities and improvements.
Users are encouraged to participate in its roadmap and implementation on GitHub. Feel free to open an issue if you have any feedback or suggestions.
Assertions
k6 provides test assertions in the form of the
expect
function. Assertions validate that your application behaves as expected during testing.
Define assertions by passing a value to
expect()
and chaining it with a matcher that defines your expected outcome. The library provides expressive matchers that work with both protocol testing
HTTP/API and
browser testing scenarios.
The assertions API is inspired by Playwright’s assertion syntax, providing a fluent interface that improves test readability and reliability.
Getting started
Assertions are provided by the k6-testing library. Import the library to start using assertions:
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',
},
},
};
Types of assertions
The k6-testing library provides two types of assertions, each designed for different testing scenarios:
Non-retrying assertions
Non-retrying assertions evaluate conditions immediately at a single point in time without retrying. They’re ideal for validating static data such as HTTP response content, data structures, or configuration values.
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
export default function () {
const pizzaRequestPayload = { maxCaloriesPerSlice: 1000, mustBeVegetarian: true };
const pizzaRequestHeader = {
'Content-Type': 'application/json',
'Authorization': 'Token ' + 'abcdef0123456789',
};
const response = http.post(
`https://quickpizza.grafana.com/api/pizza`,
JSON.stringify(pizzaRequestPayload),
{ headers: pizzaRequestHeader }
);
const data = response.json();
// These assertions evaluate immediately
expect(response.status).toEqual(200);
expect(response.headers['Content-Type']).toBeDefined();
expect(response.headers['Content-Type']).toEqual('application/json');
expect(data.pizza).toBeDefined();
expect(data.pizza.name).toBeDefined();
expect(data.pizza.name).not.toHaveLength(0);
}
Auto-retrying assertions
Auto-retrying assertions automatically retry until conditions become true or a timeout is reached. They’re designed for browser testing scenarios where elements may take time to load, update, or become interactable.
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import { browser } from 'k6/browser';
export default async function () {
// Open a new browser page
const page = await browser.newPage();
try {
// Navigate to the quickpizza website
await page.goto('https://quickpizza.grafana.com/');
// Click the 'Pizza please' button
await page.locator('button[name="pizza-please"]').click();
// Take a screenshot of the homepage, and save it to the local filesystem
// so we can inspect it later if needed.
await page.screenshot({ path: 'homepage.png' });
// Check if the pizza recipe is displayed
const textContent = await pizzaRecipeIsDisplayed(page);
expect(textContent).toEqual('Our recommendation:');
} finally {
await page.close();
}
}
// Browsers are asynchronous, so we need to wait for the content we want to check
// to be visible.
async function pizzaRecipeIsDisplayed(page) {
const label = await page.locator('h2[id="pizza-name"]');
await label.isVisible();
const textContent = (await label.textContent()).trim();
return textContent;
}
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};
Assertions vs. checks
Unlike k6 checks, which continue execution when they fail and register metrics for threshold evaluation, assertions immediately fail and interrupt the test when expectations are not met. Assertions are designed for validating critical conditions that determine whether a test should continueโwhen these conditions aren’t met, they invalidate the entire testing scenario.
Assertions do not register metrics because they halt execution rather than collect data points. This design provides fast feedback and detailed error messages to help you identify issues quickly, ensuring your tests only proceed when fundamental assumptions are satisfied.
Available assertion methods
Non-retrying assertions
Use these for immediate evaluation of static values:
Method | Description |
---|---|
toBe() | Exact equality using Object.is() |
toEqual() | Deep equality comparison |
toBeTruthy() | Value is truthy |
toBeFalsy() | Value is falsy |
toBeDefined() | Value is not undefined |
toBeUndefined() | Value is undefined |
toBeNull() | Value is null |
toBeGreaterThan() | Numeric greater than |
toBeGreaterThanOrEqual() | Numeric greater than or equal |
toBeLessThan() | Numeric less than |
toBeLessThanOrEqual() | Numeric less than or equal |
toBeCloseTo() | Floating point comparison |
toContain() | Array/string contains value |
toContainEqual() | Array contains object with matching content |
toHaveLength() | Array/string has specific length |
toHaveProperty() | Object has specific property |
toBeInstanceOf() | Value is instance of class |
See all non-retrying assertions โ
Auto-retrying assertions
Essential for browser testing with dynamic content:
Method | Description |
---|---|
toBeVisible() | Element is visible on the page |
toBeHidden() | Element is hidden or not visible |
toBeEnabled() | Element is enabled and interactive |
toBeDisabled() | Element is disabled |
toBeChecked() | Checkbox or radio button is checked |
toBeEditable() | Element is editable |
toHaveText() | Element has specific text content |
toContainText() | Element contains specific text |
toHaveValue() | Input element has specific value |
toHaveAttribute() | Element has specific attribute value |
See all retrying assertions โ
Assertion features
Negation
All assertions can be negated using .not
:
import { browser } from 'k6/browser';
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
export default async function () {
const response = http.get('https://quickpizza.grafana.com/');
// Negated assertions
expect(response.status).not.toBe(404);
expect(response.body).not.toHaveLength(0);
expect(response.headers).not.toHaveProperty('error');
// Browser negation (with await)
const page = await browser.newPage();
await page.goto('https://quickpizza.grafana.com/');
await expect(page.locator('.error-message')).not.toBeVisible();
}
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
};
Soft assertions
Soft assertions continue test execution even when they fail, marking the test as failed but allowing subsequent assertions to run. Unlike checks, soft assertions do not measure failures or emit dedicated metrics. If you need failure-related metrics, consider using checks instead:
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
export default function () {
const response = http.get('https://quickpizza.grafana.com/');
// These will all run even if some fail
expect.soft(response.status).toBe(200);
expect.soft(response.headers['Content-Type']).toContain('text/html');
expect.soft(response.body).toHaveLength(response.body.length);
// Test continues and performs additional checks
console.log('Test completed, checking results...');
}
Custom error messages
Provide descriptive error messages for better debugging:
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
export default function () {
const response = http.get('https://quickpizza.grafana.com/api/pizza', {
headers: { 'Content-Type': 'application/json' },
});
const pizza = response.json();
expect(response.status, 'API should return successful response').toBe(200);
expect(pizza.name, 'Pizza should have a valid name').toBeDefined();
expect(pizza.name, 'Pizza name should not be empty').not.toHaveLength(0);
}
Configuration and customization
Global configuration
Configure assertion behavior globally for all tests:
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
// Configure global settings
const configuredExpect = expect.configure({
timeout: 10000, // 10 seconds for retrying assertions
interval: 500, // Retry check every 500ms (on retriable assertions)
colorize: true, // Enable colored output
// Setting `softMode` to 'throw', will make soft assertions fail the current iteration instead of the whole test.
softMode: 'fail',
});
export default function () {
const response = http.get('https://quickpizza.grafana.com');
// All assertions use these settings
configuredExpect(response.status).toBe(200);
}
Per-scenario configuration
Create different configurations for different test scenarios:
import { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';
import http from 'k6/http';
import { browser } from 'k6/browser';
// Fast assertions for API testing
const fastExpect = expect.configure({
timeout: 2000,
interval: 100,
});
// Slow assertions for complex browser interactions
const slowExpect = expect.configure({
timeout: 30000,
interval: 1000,
softMode: 'continue',
});
export default async function () {
// Use appropriate expectation based on test type
const response = http.get('https://quickpizza.grafana.com/');
fastExpect(response.status).toBe(200);
if (__ENV.BROWSER_TEST) {
const page = await browser.newPage();
await page.goto('https://quickpizza.grafana.com/');
await slowExpect(page.locator('h1')).toBeVisible();
}
}
Best practices
For tests that primarily use assertions to validate system state, such as tests verifying a successful deployment in CI pipelines, run k6 tests with assertions in quiet mode:
k6 run --quiet --no-summary script.ts
This approach eliminates unnecessary output and focuses on the assertion results, making it ideal for automated testing environments.
See also
- expect() API reference - Complete assertion documentation
- Auto-retrying assertions
- Non-retrying assertions
- Browser testing - Browser automation with k6
- Checks - Alternative validation approach