---
title: Chai reference
description: Reference documentation for the Allure Chai integration | Step name format | Value serialization | What assertions are recorded
---

# Allure Chai reference

## allureChai

- `allureChai: ChaiPlugin`

The Chai plugin exported by `allure-chai`. Register it with Chai once before your tests run:

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

chai.use(allureChai);
```

Once registered, every Chai assertion executed during the test run will be recorded as an Allure step. The plugin instruments the `chai.Assertion` prototype, the `chai.assert` interface, and the static methods used to define custom assertions. Calling `chai.use(allureChai)` more than once has no effect — the plugin guards against double-instrumentation.

## Step name format

### expect and should style

Steps from `expect()` and `.should` assertions follow this pattern:

```
expect(⟨actual⟩).to[.⟨modifier⟩...][.have|.be].⟨assertion⟩[(⟨arguments⟩)]
```

- `⟨actual⟩` is the value passed to `expect()`, serialized as described in [Value serialization](#value-serialization).
- Modifiers (`not`, `deep`, `nested`, `own`, `ordered`, `any`, `all`) are included between `to` and the assertion name when they are active on the assertion chain. `include` also appears as a modifier when `.include` (or `.contain`, `.contains`, `.includes`) is chained before another assertion such as `.members`. When multiple modifiers are active, they always appear in this fixed order: `not`, `include`, `deep`, `nested`, `own`, `ordered`, `any`, `all`.
- Some assertions are prefixed with `have` or `be` to match their natural Chai expression. See [Assertion path prefixes](#assertion-path-prefixes) below.
- Property assertions (those that take no arguments) omit the trailing parentheses.

**Examples:**

| Code                                    | Step name                                 |
| --------------------------------------- | ----------------------------------------- |
| `expect("a").to.equal("b")`             | `expect("a").to.equal("b")`               |
| `expect(arr).to.have.lengthOf(3)`       | `expect([...]).to.have.lengthOf(3)`       |
| `expect(x).to.be.null`                  | `expect(null).to.be.null`                 |
| `expect(x).to.not.be.undefined`         | `expect("foo").to.not.be.undefined`       |
| `expect(obj).to.deep.equal({a:1})`      | `expect({...}).to.deep.equal({"a":1})`    |
| `expect(obj).to.have.own.property("x")` | `expect({...}).to.own.have.property("x")` |

The step name always follows the structural pattern `to[.⟨modifier⟩...][.have|.be].⟨assertion⟩`, regardless of the order in which language chains appear in code. For example, the `have` in `.to.have.own.property(...)` is a language chain that gets dropped, and `have` is re-added structurally after the `own` modifier, yielding `.to.own.have.property(...)`.

### assert style

Steps from `assert.*` calls follow this pattern:

```
assert.⟨name⟩(⟨arguments⟩)
```

All arguments are serialized and joined with `, `.

**Examples:**

| Code                          | Step name                     |
| ----------------------------- | ----------------------------- |
| `assert.equal("a", "b")`      | `assert.equal("a", "b")`      |
| `assert.isTrue(false)`        | `assert.isTrue(false)`        |
| `assert.lengthOf([1,2,3], 3)` | `assert.lengthOf([1,2,3], 3)` |

### Assertion name aliases

Several Chai assertion aliases are normalized to their canonical names in step output:

| Alias                             | Displayed as            |
| --------------------------------- | ----------------------- |
| `eq`, `equals`                    | `equal`                 |
| `eqls`                            | `eql`                   |
| `contain`, `contains`, `includes` | `include`               |
| `exists`                          | `exist`                 |
| `matches`                         | `match`                 |
| `throws`, `Throw`                 | `throw`                 |
| `greaterThan`, `gt`               | `above`                 |
| `greaterThanOrEqual`, `gte`       | `least`                 |
| `lessThan`, `lt`                  | `below`                 |
| `lessThanOrEqual`, `lte`          | `most`                  |
| `instanceof`                      | `instanceOf`            |
| `haveOwnProperty`                 | `ownProperty`           |
| `haveOwnPropertyDescriptor`       | `ownPropertyDescriptor` |
| `respondsTo`                      | `respondTo`             |
| `satisfies`                       | `satisfy`               |

### Assertion path prefixes

Allure Chai adds `have` or `be` before the assertion name in `expect`/`should` steps to match the natural Chai expression. The prefixes are applied as follows:

- **`.have.`** is added before: `keys`, `key`, `lengthOf`, `members`, `property`, `ownProperty`, `ownPropertyDescriptor`, `string`. The `.have.` prefix is omitted when `include` is an active modifier. For example, `expect([1,2,3]).to.include.members([2,3])` produces `expect([1,2,3]).to.include.members([2,3])`, not `expect([1,2,3]).to.include.have.members([2,3])`.
- **`.be.`** is added before: `a`, `an`, `arguments`, `Arguments`, `empty`, `exist`, `extensible`, `false`, `finite`, `frozen`, `instanceOf`, `NaN`, `null`, `ok`, `sealed`, `true`, `undefined`.
- No prefix is added for all other assertions.

## Value serialization

Values appearing in step names (both `⟨actual⟩` and assertion arguments) are serialized as follows:

- **Strings** are JSON-encoded, including surrounding quotes: `"hello"`.
- **Numbers, booleans, `null`, `undefined`** are converted to their string representations: `42`, `true`, `null`, `undefined`.
- **BigInts** are serialized as `⟨value⟩n`: `9007199254740993n`.
- **Symbols** are serialized using `Symbol.prototype.toString()`: `Symbol(foo)`.
- **Functions** are serialized as `[Function ⟨name⟩]`, or `[Function]` if the function has no name. Constructor functions that are subclasses of `Error` (i.e. where `value.prototype instanceof Error` is true) are serialized by name only: `TypeError`. Note that `Error` itself does not satisfy this check and serializes as `[Function Error]`.
- **RegExp values** are serialized using `RegExp.prototype.toString()` and then JSON-encoded as a string: `"/^foo$/i"`.
- **Error instances** are serialized as `{"name":"⟨name⟩","message":"⟨message⟩"}`, whether they appear as the top-level value or nested inside objects or arrays.
- **Arrays and objects** are JSON-serialized up to two levels of nesting. Values nested deeper than two levels are replaced with `[Array]` or `[Object]`. Circular references are replaced with `[Circular]`.
- **Serialized values longer than 160 characters** are truncated and suffixed with `... <truncated>`.

## What is and is not recorded

**Recorded as steps:**

- All method assertions on `chai.Assertion.prototype` (e.g. `equal`, `include`, `throw`, `match`).
- All property assertions on `chai.Assertion.prototype` that are not language chains or modifiers (e.g. `null`, `ok`, `empty`, `exist`).
- Chainable methods used as assertions: `a`, `an`, `include`, `contain`, `contains`, `includes`, `length`.
- All methods on `chai.assert` (e.g. `assert.equal`, `assert.isTrue`, `assert.throws`). `assert.*` methods are implemented on top of `expect` internally; those inner `expect` calls are suppressed so each `assert.*` call records exactly one step, not two.
- Custom assertions added via `chai.Assertion.addMethod()`, `chai.Assertion.addProperty()`, and `chai.Assertion.addChainableMethod()`. Assertions already on the prototype when `chai.use(allureChai)` is called are instrumented at registration time; assertions added afterward are instrumented at the point of the `addMethod`/`addProperty`/`addChainableMethod` call.
- Inner assertions called from a callback inside a custom assertion. These are recorded as nested child steps of the outer assertion's step.
- When a failed assertion carries `actual` and `expected` on its error (as Chai's `AssertionError` does), those values are captured in the step's status details.

**Not recorded:**

- Language chain properties: `to`, `be`, `been`, `is`, `and`, `has`, `have`, `with`, `that`, `which`, `at`, `of`, `same`, `but`, `does`, `still`, `also`. These are cosmetic and have no effect on the report.
- Modifier properties accessed as part of a chain: `not`, `deep`, `nested`, `own`, `ordered`, `any`, `all`, `itself`. These are not recorded as steps themselves. All except `itself` appear in the name of the assertion step that follows; `itself` is a silent chain that affects `.respondTo()` semantics but is never reflected in step names.
- Internal `Assertion.prototype` members that are not user-facing assertions: `_obj`, `__flags`, `__methods`, `callable`, `iterable`, `numeric`, `assert`, `constructor`. These are skipped during instrumentation.
- `AssertionError` on `chai.assert`. This is a constructor, not a callable assertion, and is not wrapped.
- Vitest's built-in `expect()` assertions. Allure Chai detects Vitest-owned assertion chains and skips them automatically to avoid duplicating the steps that allure-vitest already records.
- Assertions invoked through Cypress's built-in 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. A separately imported Chai instance used in the same project (e.g. for `chai-http` assertions) is not affected by the Cypress check and will still be recorded.
