---
title: TestCafe reference
description: Reference documentation for the Allure TestCafe integration | How to add steps and additional metadata | Create attachments | Organise tests
---

# Allure TestCafe reference

These are the functions and conventions you can use to integrate your TestCafe tests with Allure. For an introduction to the three API styles (Runtime API, Meta API, and title annotations), see [Getting started](/docs/testcafe/).

For labels and links, **test-level meta overrides fixture-level meta** for the same key. This lets you set defaults on a fixture and override them on individual tests.

## Metadata

Assign a test's [description, links, and other metadata](/docs/v3/readability/#description-links-and-other-metadata).

### Description

- `allure.description(markdown: string): Promise<void>`

Set the test's [description](/docs/v3/readability/#description). Markdown formatting is allowed.

```js
const { description } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await description("This test verifies that a user can sign in with valid credentials.");
  // ...
});
```

To set an HTML description instead, use `allure.descriptionHtml(html: string)`.

### Display name

- `allure.displayName(name: string): Promise<void>`

Override the test name as it appears in the report. This does not affect the test's identity or history tracking — only the displayed label.

```js
const { displayName } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await displayName("Sign in with username and password");
  // ...
});
```

### Owner

- `allure.owner(name: string): Promise<void>`
- Meta: `"allure.label.owner": "<value>"`
- Title: `@allure.label.owner=<value>`

Set the test's [owner](/docs/v3/readability/#owner).

**Runtime API:**
```js
const { owner } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await owner("alice");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ "allure.label.owner": "alice" })("sign in", async (t) => {
  // ...
});
```

**Title annotation:**
```js
fixture`Authentication`.page`https://example.com/login`;

test("sign in @allure.label.owner=alice", async () => {
  // ...
});
```

### Tag

- `allure.tag(name: string): Promise<void>`
- `allure.tags(...names: string[]): Promise<void>`
- Meta: `"allure.label.tag": "<value>"` or `"allure.label.tag": ["<value1>", "<value2>"]`
- Title: `@allure.label.tag=<value>` (repeat for multiple tags)

Set the test's [tags](/docs/v3/readability/#tags).

**Runtime API:**
```js
const { tag, tags } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await tag("smoke");
  await tags("authentication", "web");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ "allure.label.tag": ["smoke", "authentication", "web"] })("sign in", async (t) => {
  // ...
});
```

**Title annotation:**
```js
fixture`Authentication`.page`https://example.com/login`;

test(
  "sign in" +
    " @allure.label.tag=smoke" +
    " @allure.label.tag=authentication" +
    " @allure.label.tag=web",
  async () => {
    // ...
  },
);
```

### Severity

- `allure.severity(level: string): Promise<void>`
- Meta: `"allure.label.severity": "<value>"`
- Title: `@allure.label.severity=<value>`

Set the test's [severity](/docs/v3/readability/#other-labels).

Allowed values are: `"trivial"`, `"minor"`, `"normal"`, `"critical"`, and `"blocker"`.

**Runtime API:**
```js
const { severity, Severity } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await severity(Severity.CRITICAL);
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ "allure.label.severity": "critical" })("sign in", async (t) => {
  // ...
});
```

### Label

- `allure.label(name: string, value: string): Promise<void>`
- `allure.labels(...labels: Label[]): Promise<void>`
- Meta: `"allure.label.<name>": "<value>"`
- Title: `@allure.label.<name>=<value>`

Set an arbitrary [label](/docs/v3/readability/#other-labels) for the test. This is the underlying function used by most other Allure label helpers.

You can call `label()` multiple times with the same name to assign multiple values.

**Runtime API:**
```js
const { label } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await label("microservice", "auth-service");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ "allure.label.microservice": "auth-service" })("sign in", async (t) => {
  // ...
});
```

### ID

- `allure.allureId(id: string): Promise<void>`
- Meta: `"allure.id": "<value>"`
- Title: `@allure.id=<value>`

Set the test's [Allure ID](/docs/v3/readability/#id). Used by [test plan filtering](#test-plan) to select tests by ID. Test plan filtering runs before the test body executes, so only the meta key and title annotation forms are effective for plan-based selection — the runtime `allureId()` function runs too late to influence filtering.

**Runtime API:**
```js
const { allureId } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await allureId("42");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ "allure.id": "42" })("sign in", async (t) => {
  // ...
});
```

**Title annotation:**
```js
fixture`Authentication`.page`https://example.com/login`;

test("sign in @allure.id=42", async () => {
  // ...
});
```

### Link

- `allure.link(url: string, name?: string, type?: string): Promise<void>`
- `allure.links(...links: Link[]): Promise<void>`
- `allure.issue(url: string, name?: string): Promise<void>`
- `allure.tms(url: string, name?: string): Promise<void>`
- Meta: `"allure.link.<type>": "<url-or-id>"` or `"allure.link.<type>": ["<url1>", "<url2>"]`
- Title: `@allure.link.<type>=<url-or-id>`

Add a [link](/docs/v3/readability/#links) related to the test.

Based on the `type` (which can be any string, defaults to `"link"`), Allure will try to load a corresponding **link template** as defined by the [`links`](/docs/testcafe-configuration/#links) configuration option. If no template is found or if the value is already a full URL, it is left unmodified.

For convenience, Allure provides two shorthand functions with pre-selected link types: `issue` and `tms`.

**Runtime API:**
```js
const { issue, tms, link } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await issue("AUTH-123", "Related issue");
  await tms("TMS-456", "Related TMS ticket");
  await link("https://example.com/docs/auth", "Auth documentation");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`.meta({
  "allure.link.issue": "AUTH-123",
});

test.meta({
  "allure.link.tms": ["TMS-456", "TMS-789"],
})("sign in", async (t) => {
  // ...
});
```

### Test identity

- `allure.historyId(id: string): Promise<void>`
- `allure.testCaseId(id: string): Promise<void>`

Override the identifiers Allure uses to match this test across runs when computing history and grouping retries.

- `historyId` replaces the computed value used to look up previous results. Use this when the same logical test runs under different names or parameters across runs.
- `testCaseId` replaces the stable identifier used to group retries. Results that share a `testCaseId` are treated as retries of the same test.

```js
const { historyId, testCaseId } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await historyId("auth-signin-v2");
  await testCaseId("TC-1001");
  // ...
});
```

## Behavior-based hierarchy

- `allure.epic(name: string): Promise<void>`
- `allure.feature(name: string): Promise<void>`
- `allure.story(name: string): Promise<void>`
- Meta: `"allure.label.epic"`, `"allure.label.feature"`, `"allure.label.story"`
- Title: `@allure.label.epic=<value>`, `@allure.label.feature=<value>`, `@allure.label.story=<value>`

Assign names of **epics**, **features**, or **user stories** for a test, as part of Allure's [behavior-based hierarchy](/docs/v3/navigation/#behavior-based-hierarchy).

**Runtime API:**
```js
const { epic, feature, story } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await epic("Web interface");
  await feature("Essential features");
  await story("Authentication");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`.meta({
  "allure.label.epic": "Web interface",
  "allure.label.feature": "Essential features",
});

test.meta({
  "allure.label.story": "Authentication",
})("sign in", async (t) => {
  // ...
});
```

A common pattern is to set epic and feature on the fixture so all tests in the file share them, and override story per test.

## Suite-based hierarchy

- `allure.parentSuite(name: string): Promise<void>`
- `allure.suite(name: string): Promise<void>`
- `allure.subSuite(name: string): Promise<void>`
- Meta: `"allure.label.parentSuite"`, `"allure.label.suite"`, `"allure.label.subSuite"`
- Title: `@allure.label.parentSuite=<value>`, etc.

Assign the names of **parent suite**, **suite**, or **sub-suite** for a test, as part of Allure's [suite-based hierarchy](/docs/v3/navigation/#suite-based-hierarchy).

**Runtime API:**
```js
const { parentSuite, suite, subSuite } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  await parentSuite("Tests for web interface");
  await suite("Tests for essential features");
  await subSuite("Tests for authentication");
  // ...
});
```

**Meta API:**
```js
fixture`Authentication`.page`https://example.com/login`.meta({
  "allure.label.parentSuite": "Tests for web interface",
  "allure.label.suite": "Tests for essential features",
  "allure.label.subSuite": "Tests for authentication",
});

test("sign in", async (t) => {
  // ...
});
```

**Title annotations:**
```js
fixture`Authentication`.page`https://example.com/login`;

test(
  "sign in" +
    " @allure.label.parentSuite=TestsForWebInterface" +
    " @allure.label.suite=TestsForEssentialFeatures" +
    " @allure.label.subSuite=TestsForAuthentication",
  async () => {
    // ...
  },
);
```

## Test steps

- `allure.step<T>(name: string, body: (context: StepContext) => T | Promise<T>): Promise<T>`
- `allure.logStep(name: string, status?: Status, error?: Error): Promise<void>`

Define a [test step](/docs/steps/) with the given `name`.

There are two ways to define a step:

- **Lambda steps**

  Pass a function to `allure.step()`. The function receives a `StepContext` object with two methods:

  - `displayName(name: string)` — override the step name while it executes.
  - `parameter(name, value, mode?)` — record a parameter for the step. `mode` can be `"default"`, `"masked"`, or `"hidden"`.

  TestCafe action steps created automatically are nested inside any enclosing lambda step.

- **No-op steps**

  `allure.logStep()` adds an instant step with no body. Useful for log-style annotations inside a test. The optional `status` argument defaults to `Status.PASSED`. Pass an `Error` object as the third argument to include its message in the step.

```js
const { step, logStep, Status } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async (t) => {
  await step("Fill in the form", async (ctx) => {
    await ctx.displayName("Fill in credentials form");
    await ctx.parameter("environment", "staging");
    await t.typeText("#login", "demo-user");
    await t.typeText("#password", "secret");
  });
  await step("Submit the form", async () => {
    await t.click("#submit");
  });
  await logStep("Verified redirect", Status.PASSED);
});
```

## Parametrized tests

- `allure.parameter(name: string, value: string, options?: ParameterOptions): Promise<void>`

Record a `name`/`value` parameter pair for the test. See [Parametrized tests](/docs/v3/readability/#parametrized-tests) for details.

The optional `options` argument is an object with two properties:

- `excluded` — if `true`, Allure excludes this parameter when comparing the test with its history. Use this for timestamps or other values that change on every run. See [Common pitfall: retries displayed as separate tests](/docs/history-and-retries/#common-pitfall-a-tests-retries-are-displayed-as-separate-tests).

- `mode` — controls how the parameter appears in the report:
  - `"default"` — shown in a table with other parameters.
  - `"masked"` — shown in the table, but the value is hidden. Use for passwords and tokens.
  - `"hidden"` — not shown in the report at all.

```js
const { parameter } = require("allure-js-commons");

fixture`Authentication`.page`https://example.com/login`;

for (const login of ["johndoe", "johndoe@example.com"]) {
  test(`sign in as ${login}`, async () => {
    await parameter("login", login);
    await parameter("timestamp", new Date().toISOString(), { excluded: true });
    // ...
  });
}
```

#### Plain meta as parameters

Any key in a fixture or test `meta` object that does not start with `"allure."` and whose value is a scalar (string, number, boolean, or bigint) is automatically added to the test result as a parameter. This means you can annotate test variants directly in meta without calling `parameter()` in the test body:

```js
fixture`Authentication`.page`https://example.com/login`;

test.meta({ env: "staging", shard: 1 })("sign in", async (t) => {
  // "env" and "shard" appear as parameters in the report
  // ...
});
```

## Attachments

- `allure.attachment(name: string, content: Buffer | string, options: ContentType | string | AttachmentOptions): Promise<void>`
- `allure.attachmentPath(name: string, path: string, options: ContentType | string | Omit<AttachmentOptions, "encoding">): Promise<void>`

Add an [attachment](/docs/attachments/) to the test result under the given `name`. Pass either the `content` or the `path` from which the data will be read.

The `options` argument controls the [media type](https://en.wikipedia.org/wiki/Media_type) and the filename extension used if a user downloads the attachment. You can either specify both in an object or provide just the media type and let Allure infer the extension.

```js
const { attachment, attachmentPath } = require("allure-js-commons");
const { ContentType } = require("allure-js-commons");
const path = require("node:path");

fixture`Authentication`.page`https://example.com/login`;

test("sign in", async () => {
  // ...

  await attachment("Server response", JSON.stringify({ status: "ok" }), "application/json");

  await attachmentPath("Config file", path.join(__dirname, "config.txt"), ContentType.TEXT);
});
```

#### Automatic screenshots

When TestCafe captures screenshots (e.g., on test failure or via `t.takeScreenshot()`), the reporter attaches them automatically. Screenshots are attached to the action step they belong to when TestCafe provides the association; otherwise they are attached at the test level.

#### Automatic videos

When TestCafe records videos, they are attached to the corresponding test result automatically.

## Meta API reference

The Meta API is a TestCafe-specific way to assign Allure metadata using fixture and test `.meta()` calls. It complements the Runtime API and title annotations.

| Meta key                | Effect                                                                         |
| ----------------------- | ------------------------------------------------------------------------------ |
| `"allure.id"`           | Sets the Allure ID for the test                                                |
| `"allure.label.<name>"` | Adds a label with the given name; value can be a string or an array of strings |
| `"allure.link.<type>"`  | Adds a link of the given type; value can be a URL/ID string or an array        |
| Any other scalar key    | Becomes a test parameter visible in the report                                 |

Fixture-level meta is merged with test-level meta. For the same key, test-level meta takes precedence.

Example combining fixture and test meta:

```js
fixture`Checkout`.page`https://example.com/checkout`.meta({
  "allure.label.epic": "Storefront",
  "allure.label.feature": "Checkout",
  "allure.link.issue": "SHOP-100",
});

test.meta({
  "allure.id": "42",
  "allure.label.story": "Pay with card",
  "allure.link.issue": "PAY-42", // overrides fixture-level issue link
  env: "staging", // becomes a parameter
})("pay with card", async (t) => {
  await t.expect(true).ok();
});
```

## Title annotation reference

Title annotations use `@allure.<type>=<value>` (or equivalently `@allure.<type>:<value>`) embedded in the test name. The clean test name displayed in the report has these annotations removed.

Values that contain spaces must be wrapped in `"`, `'`, or backtick quotes:

```js
test('sign in @allure.label.epic="Web interface" @allure.label.feature="Essential features"', async () => {
  // ...
});
```

| Annotation                     | Effect                           |
| ------------------------------ | -------------------------------- |
| `@allure.id=<value>`           | Sets the Allure ID               |
| `@allure.label.<name>=<value>` | Adds a label with the given name |
| `@allure.link.<type>=<value>`  | Adds a link of the given type    |

```js
fixture`Authentication`.page`https://example.com/login`;

test(
  "sign in" +
    " @allure.id=42" +
    " @allure.label.severity=critical" +
    " @allure.label.tag=smoke" +
    " @allure.link.issue=AUTH-123",
  async () => {
    // test name shown in report: "sign in"
    // ...
  },
);
```
