> Markdown version of [Load Testing Response Checks](https://vaadin.com/docs/latest/flow/testing/load-testing/response-checks). Section index: [llms.txt](https://vaadin.com/docs/latest/flow/llms.txt)

# Load Testing Response Checks (since V25.2)

## <a id="overview"></a>Overview

By default, every generated k6 script validates responses with built-in Vaadin checks (status codes, session validity, CSRF tokens, error detection). **Custom response checks** let you add your own `check()` assertions on top of these defaults — for example verifying that a specific element appears in the page, that no application-level warning is returned, or that response times stay within an acceptable range.

Custom checks are injected into the same `check(response, { …​ })` blocks as the built-in checks. They participate in the k6 `checks` threshold, meaning a failing custom check can abort the test (when `checksAbortOnFail` is enabled) and is reported in k6 output alongside the standard checks.

## <a id="quick-start"></a>Quick Start

Command line

```bash
mvn loadtest:record \
  -Dk6.testClass=MyScenarioIT \
  -Dk6.checks.custom="INIT|has page title|(r) => r.body.includes('<title>')"
```

POM configuration

```xml
<configuration>
    <testClass>MyScenarioIT</testClass>
    <customChecks>INIT|has page title|(r) => r.body.includes('&lt;title&gt;')</customChecks>
</configuration>
```

The generated k6 script will contain:

```javascript
if (!check(response, {
    'init request succeeded': (r) => r.status === 200,
    'session is valid': (r) => !r.body.includes('Your session needs to be refreshed'),
    'valid init response': (r) => r.body.includes('"v-uiId"') && r.body.includes('"Vaadin-Security-Key"'),
    'has page title': (r) => r.body.includes('<title>'),  // <-- custom check
})) {
    fail(`Request 2 (GET ...): init failed ...`)
}
```

## <a id="scopes"></a>Scopes

Each check has a **scope** that controls where it is injected in the generated script.

| Scope  | Description                                                                                       |
| ------ | ------------------------------------------------------------------------------------------------- |
| `INIT` | Injected after **init requests** only (the initial page load that returns Vaadin bootstrap JSON). |
| `UIDL` | Injected after **UIDL requests** only (Vaadin client-server RPC calls).                           |
| `ALL`  | Injected after **both** init and UIDL requests.                                                   |

## <a id="string-format"></a>String Format

The `k6.checks.custom` Maven property accepts checks in a delimited string format:

```
scope|name|expression
```

- **scope** — `INIT`, `UIDL`, or `ALL` (case-insensitive). Optional; defaults to `ALL` when omitted.

- **name** — the check description displayed in k6 output.

- **expression** — a JavaScript function that receives the k6 response object `r` and returns a boolean.

Multiple checks are separated by semicolons (`;`).

Format examples

```
# Scope + name + expression (3 parts)
INIT|has page title|(r) => r.body.includes('<title>')

# Name + expression only, scope defaults to ALL (2 parts)
fast response|(r) => r.timings.duration < 3000

# Multiple checks separated by semicolons
INIT|has title|(r) => r.body.includes('<title>');UIDL|no warning|(r) => !r.body.includes('warning')
```

> **Note:** Semicolons (`;`) separate entries and pipes (`|`) separate fields within an entry. Avoid using literal `|` or `;` inside check names or expressions.

## <a id="maven-configuration"></a>Maven Configuration

### <a id="command-line"></a>Command Line

```bash
# Single check
mvn loadtest:record \
  -Dk6.testClass=MyScenarioIT \
  -Dk6.checks.custom="INIT|has title|(r) => r.body.includes('<title>')"

# Multiple checks
mvn loadtest:record \
  -Dk6.testClass=MyScenarioIT \
  -Dk6.checks.custom="INIT|has title|(r) => r.body.includes('<title>');UIDL|no timeout|(r) => !r.body.includes('timeout');ALL|fast|(r) => r.timings.duration < 3000"
```

### <a id="pom-plugin-configuration"></a>POM Plugin Configuration

```xml
<plugin>
    <groupId>com.vaadin</groupId>
    <artifactId>testbench-converter-plugin</artifactId>
    <configuration>
        <testClass>MyScenarioIT</testClass>
        <customChecks>
            INIT|has page title|(r) =&gt; r.body.includes('&lt;title&gt;');
            UIDL|no application warning|(r) =&gt; !r.body.includes('warning');
            ALL|response under 3s|(r) =&gt; r.timings.duration &lt; 3000
        </customChecks>
    </configuration>
</plugin>
```

> **Note:** In XML, escape `<` as `&lt;` and `>` as `&gt;`.

### <a id="parameter-reference"></a>Parameter Reference

| Parameter          | Default  | Description                                                                              |
| ------------------ | -------- | ---------------------------------------------------------------------------------------- |
| `k6.checks.custom` | *(none)* | Custom response validation checks in `scope\|name\|expression` format, separated by `;`. |

## <a id="java-api"></a>Java API

For programmatic use (e.g., in custom Maven plugins or test harnesses), `ResponseCheckConfig` provides a fluent builder API.

```java
import com.vaadin.testbench.loadtest.util.ResponseCheckConfig;
import com.vaadin.testbench.loadtest.util.ResponseCheckConfig.Scope;

ResponseCheckConfig checks = ResponseCheckConfig.EMPTY
        .withCheck(Scope.INIT, "has page title",
                "(r) => r.body.includes('<title>')")
        .withCheck(Scope.UIDL, "no application warning",
                "(r) => !r.body.includes('warning')")
        .withCheck(Scope.ALL, "response under 3s",
                "(r) => r.timings.duration < 3000");
```

Parse from string format:

```java
ResponseCheckConfig checks = ResponseCheckConfig.EMPTY.withChecks(
        "INIT|has title|(r) => r.body.includes('<title>');"
        + "UIDL|no warning|(r) => !r.body.includes('warning')");
```

Pass to the converter:

```java
HarToK6Converter converter = new HarToK6Converter();
converter.convert(harFile, outputFile, thresholdConfig, checks);
```

## <a id="examples"></a>Examples

### <a id="validate-page-content-after-init"></a>Validate page content after init

Ensure the init response contains a specific page marker:

```bash
-Dk6.checks.custom="INIT|has navigation menu|(r) => r.body.includes('side-nav')"
```

### <a id="detect-application-errors-in-uidl-responses"></a>Detect application errors in UIDL responses

Catch domain-specific error patterns that the built-in checks don’t cover:

```bash
-Dk6.checks.custom="UIDL|no validation error|(r) => !r.body.includes('ValidationException')"
```

### <a id="enforce-response-time-limits"></a>Enforce response time limits

Add a per-request response time check (complementing the aggregate p95/p99 thresholds):

```bash
-Dk6.checks.custom="ALL|response under 5s|(r) => r.timings.duration < 5000"
```

## <a id="how-it-works"></a>How It Works

1. The user configures custom checks via the `k6.checks.custom` Maven parameter (or `ResponseCheckConfig` Java API).

2. During HAR-to-k6 conversion, `HarToK6Converter` injects the custom check expressions into the `check(response, { …​ })` blocks:

   - Checks with scope `INIT` (or `ALL`) are appended to the init request check block.

   - Checks with scope `UIDL` (or `ALL`) are appended to each UIDL request check block.

3. The generated k6 script includes custom checks alongside the built-in Vaadin checks.

4. When k6 runs, custom checks are evaluated per-request and contribute to the `checks` pass rate metric.

5. If [`checksAbortOnFail`](https://vaadin.com/docs/latest/flow/testing/load-testing/thresholds.md#default-threshold-parameters) is enabled (default: `true`), any failing check — built-in or custom — aborts the test.

### <a id="built-in-checks-reference"></a>Built-in Checks Reference

These checks are always present in generated scripts. Custom checks are appended after them.

Table 1. Init request checks

| Check Name               | Assertion                                                                 |
| ------------------------ | ------------------------------------------------------------------------- |
| `init request succeeded` | `r.status === 200`                                                        |
| `session is valid`       | `!r.body.includes('Your session needs to be refreshed')`                  |
| `valid init response`    | `r.body.includes('"v-uiId"') && r.body.includes('"Vaadin-Security-Key"')` |

Table 2. UIDL request checks

| Check Name               | Assertion                                                |
| ------------------------ | -------------------------------------------------------- |
| `UIDL request succeeded` | `r.status === 200`                                       |
| `no server error`        | `!r.body.includes('"appError"')`                         |
| `no exception`           | `!r.body.includes('Exception')`                          |
| `session is valid`       | `!r.body.includes('Your session needs to be refreshed')` |
| `security key valid`     | `!r.body.includes('Invalid security key')`               |
| `valid UIDL response`    | `syncIdMatch !== null`                                   |

## <a id="related"></a>Related

- [k6 Checks documentation](https://grafana.com/docs/k6/latest/using-k6/checks/) — Full reference for the k6 `check()` API

- [k6 Thresholds documentation](https://grafana.com/docs/k6/latest/using-k6/thresholds/) — How thresholds interact with check pass rates
