---
title: Chai
description: Learn how to integrate Allure with Chai assertions to record each assertion as a step in your Allure reports.
---

# Getting started with Allure Chai

[![Allure Chai npm latest version](https://img.shields.io/npm/v/allure-chai?style=flat "Allure Chai npm latest version")](https://www.npmjs.com/package/allure-chai)

Record [Chai](https://www.chaijs.com/) assertions as steps in your [Allure Report](https://allurereport.org/docs/).

## Setting up

### 1. Prepare your project

1. Make sure [Node.js](https://nodejs.org/) is installed.

   Allure Chai is tested against Node.js 20 and 22. Older versions may work, but we can't guarantee that.

1. Make sure you have Chai installed. Allure Chai supports Chai 4, 5, and 6. Chai 7 and later are not supported.

1. Make sure Allure Report is installed. If it's not, follow the [installation instructions](/docs/v2/install/). Note that Allure Report requires Java.

1. Allure Chai is a plugin for Chai — it does not run tests on its own. Install it together with an Allure test runner integration. It is compatible with [allure-mocha](/docs/mocha/), [allure-jasmine](/docs/jasmine/), [allure-jest](/docs/jest/), [allure-vitest](/docs/vitest/), [allure-playwright](/docs/playwright/), and [allure-bun](/docs/bun/).

   For example, to use it with Mocha:

   **npm:**
   ```bash
   npm install --save-dev allure-chai allure-mocha chai mocha
   ```

   **yarn:**
   ```bash
   yarn add --dev allure-chai allure-mocha chai mocha
   ```

   **pnpm:**
   ```bash
   pnpm install --dev allure-chai allure-mocha chai mocha
   ```

1. Register `allureChai` with Chai before your tests run. The best place is a setup file that your test runner loads before the test suite.

   ```js
   import { allureChai } from "allure-chai";
   import * as chai from "chai";

   chai.use(allureChai);
   ```

   How to load a setup file depends on your test runner. For example, with Mocha, add it via the `--require` flag or in `.mocharc.json`:

   ```json
   {
     "require": ["./test/setup.js"]
   }
   ```

   With Vitest, add it to `setupFiles` in `vitest.config.ts`:

   ```ts
   export default defineConfig({
     test: {
       setupFiles: ["allure-vitest/setup", "./test/setup.ts"],
     },
   });
   ```

   Warning:
   Make sure you call `chai.use(allureChai)` after the Allure runner integration is initialized. The `allure-vitest/setup` and similar setup imports must come first.

### 2. Run tests

Run your tests the same way you would normally. For example, with Mocha:

**npm:**
```bash
npm test
```

**yarn:**
```bash
yarn test
```

**pnpm:**
```bash
pnpm test
```

Each Chai assertion will be recorded as a step inside the test that made it. The test results will be saved to `allure-results` or whatever directory your runner integration is configured to use.

### 3. Generate a report

Finally, convert the test results into an HTML report. This can be done by one of two commands:

- `allure generate` processes the test results and saves an HTML report into the `allure-report` directory. To view the report, use the `allure open` command.

- `allure serve` creates the same report as `allure generate`, then automatically opens the main page of the report in a web browser.

## How assertions appear in reports

Once registered, Allure Chai automatically records every Chai assertion as a step. Each step is named after the assertion expression, so the report reads like the test code. A passing assertion produces a passed step; a failing assertion produces a failed step with the original error message, and the actual and expected values from the assertion error are captured in the step details.

All three Chai assertion styles are supported.

### expect style

```js
expect(response.status).to.equal(200);
```

Produces a step named:

```
expect(201).to.equal(200)
```

### should style

```js
import "chai/register-should";

response.status.should.equal(200);
```

Produces a step named:

```
expect(201).to.equal(200)
```

### assert style

```js
assert.equal(response.status, 200);
```

Produces a step named:

```
assert.equal(201, 200)
```

### Chained assertions

When you chain assertions, each assertion in the chain produces its own sibling step. The second step runs on the value returned by the first assertion, not on the original object:

```js
expect({ id: 1, name: "Ada" }).to.have.property("name").that.equals("Ada");
```

Produces two steps:

```
expect({"id":1,"name":"Ada"}).to.have.property("name")
expect("Ada").to.equal("Ada")
```

## Modifiers in step names

Modifiers such as `not`, `include`, `deep`, `nested`, `own`, `ordered`, `any`, and `all` appear in the step name. For example:

```js
const user = { name: "Alice" };
expect(user).to.not.have.property("password");

const body = { id: 2 };
expect(body).to.deep.equal({ id: 1, name: "Alice" });

expect([1, 2, 3]).to.include.any.members([1, 2]);
```

These produce steps named:

```
expect({"name":"Alice"}).to.not.have.property("password")
expect({"id":2}).to.deep.equal({"id":1,"name":"Alice"})
expect([1,2,3]).to.include.any.members([1,2])
```

Language chain properties like `and`, `but`, `with`, `that`, etc. have no effect on the step name. `to` always appears in `expect`/`should` step names. `be` and `have` are added automatically as prefixes where the assertion name requires them — you do not need to write them in your code for them to appear in the step name.

Tip: `length` vs `lengthOf`
`expect(arr).to.have.length(3)` produces `expect([...]).to.length(3)` — the `have` is dropped because `length` is a chainable method, not a `have`-prefixed assertion. Use `lengthOf` if you want `have` to appear: `expect(arr).to.have.lengthOf(3)` → `expect([...]).to.have.lengthOf(3)`.

## Custom assertions

Allure Chai automatically instruments assertions added via `chai.Assertion.addMethod()`, `chai.Assertion.addProperty()`, and `chai.Assertion.addChainableMethod()`. No extra configuration is needed — custom assertions are recorded as steps in the same way as built-in ones.

The `overwriteMethod`, `overwriteProperty`, and `overwriteChainableMethod` APIs are not intercepted. If a Chai plugin uses these to redefine an existing assertion after `chai.use(allureChai)`, the overwritten implementation will not be automatically wrapped, and that assertion will no longer be recorded as a step.

```js
chai.Assertion.addMethod("positiveNumber", function () {
  this.assert(
    this._obj > 0,
    "expected #{this} to be a positive number",
    "expected #{this} to not be a positive number",
  );
});

expect(42).to.be.positiveNumber();
// Step: expect(42).to.positiveNumber()
```

If a custom assertion calls inner assertions inside a callback, those inner assertions are recorded as nested child steps of the outer assertion's step:

```js
chai.Assertion.addMethod("satisfyEach", function (callback) {
  const items = chai.util.flag(this, "object");
  items.forEach(callback);
});

expect([{ enabled: true }]).to.satisfyEach((item) => {
  expect(item.enabled).to.equal(true);
});
// Step: expect([{"enabled":true}]).to.satisfyEach([Function])
//   Step: expect(true).to.equal(true)
```

## Compatibility

Allure Chai requires an Allure test runner integration to be active when tests run. It is compatible with the following integrations:

| Integration                            | Supported            |
| -------------------------------------- | -------------------- |
| [allure-mocha](/docs/mocha/)           | Yes                  |
| [allure-jasmine](/docs/jasmine/)       | Yes                  |
| [allure-jest](/docs/jest/)             | Yes                  |
| [allure-vitest](/docs/vitest/)         | Yes — see note below |
| [allure-playwright](/docs/playwright/) | Yes                  |
| [allure-bun](/docs/bun/)               | Yes                  |
| allure-cypress                         | No                   |

**Note for Vitest users**: Vitest's own `expect()` is Chai-based, but allure-vitest already records Vitest assertions as steps. To avoid duplicate steps, Allure Chai automatically skips Vitest's built-in assertions. The plugin is still useful when you bring in additional Chai assertions on top of Vitest's built-in ones — for example from a Chai plugin like `chai-http`.

**Cypress is not supported**: Cypress bundles its own Chai instance. Allure Chai detects when `globalThis.Cypress` is present and the registered Chai instance matches Cypress's own, and opts out for that instance — registering `allureChai` against Cypress's Chai will have no effect. If you import a separate copy of Chai in the same project (e.g. for a plugin like `chai-http`), that instance is not affected by the Cypress check and will still be recorded. Use [allure-cypress](/docs/cypress/) for Cypress-native assertions.
