SuperAPI AI Directory

chai

Coding & development

View repository

Updated 10-16 05:48

About this skill

Chai

Chai is an assertion library. It pairs naturally with Mocha. It supports TDD (assert) and BDD (expect, should) styles.

When to Use

  • BDD/TDD Assertion Library: Pairing with test runners like Mocha to write expressive, human-readable assertions in JavaScript/TypeScript.
  • Expect / Should / Assert Syntax: Choosing between chainable BDD assertions (expect(foo).to.be.a('string')) and classical TDD assert.
  • Deep Object & Array Equality: Comparing nested objects, array sets, and property structures effortlessly.
  • Plugin Ecosystem (chai-as-promised, chai-http): Extending assertion vocabularies with async promises and HTTP response assertions.

Quick Start

import { expect } from "chai";

const foo = "bar";
const beverages = { tea: ["chai", "matcha", "oolong"] };

expect(foo).to.be.a("string"); expect(foo).to.equal("bar"); expect(foo).to.have.lengthOf(3); expect(beverages).to.have.property("tea").with.lengthOf(3);


## Core Concepts

### Chainable Language Chains (BDD Style)

Chai uses natural English chaining words (`to`, `be`, `have`, `and`, `with`, `at`, `of`):

```typescript
import { expect } from "chai";

expect(user).to.be.an("object").that.has.property("email");
expect(user.roles).to.be.an("array").that.includes("admin");
expect(user.score).to.be.at.least(0).and.below(100);

Deep Equality vs Strict Identity

Distinguishes between memory reference equality and structural value equality:

const actual = { id: 1, tags: ["web", "api"] };
const expected = { id: 1, tags: ["web", "api"] };

// Strict reference identity (FAILS)
// expect(actual).to.equal(expected);

// Deep structural equality (PASSES)
expect(actual).to.deep.equal(expected);

Asynchronous Promise Assertions (chai-as-promised)

Asserts on resolved and rejected promise outcomes cleanly:

import chai, { expect } from "chai";
import chaiAsPromised from "chai-as-promised";
chai.use(chaiAsPromised);

await expect(fetchUserData("invalid_id")).to.be.rejectedWith(
  Error,
  "User not found",
);

Common Patterns

Deep Object and Schema Verification

Problem: Standard shallow equality fails to detect deeply nested object mismatches or unexpected keys.

Solution: Combine to.deep.include and type assertions:

import { expect } from "chai";

it("validates nested user response", () => {
  const user = {
    id: 1,
    profile: { name: "Alice", roles: ["admin", "editor"] },
  };
  expect(user).to.be.an("object");
  expect(user).to.have.nested.property("profile.name", "Alice");
  expect(user.profile.roles).to.include("admin").and.have.lengthOf(2);
});

Best Practices

Do:

  • Prefer expect over should: expect works cleanly with null and undefined without extending Object.prototype.
  • Use deep.equal for Objects and Arrays: Prevent false negatives caused by comparing distinct object references.
  • Provide Custom Assertion Failure Messages: Pass custom descriptions as the second argument (expect(val, 'User balance must match ledger').to.equal(100)).
  • Always Await chai-as-promised: Forgetting await on promise assertions results in unhandled promise rejections.

Don't:

  • Write orphan chains: Writing expect(val).to.be.true; in environments without function call getters can lead to silent passes if mistyped.
  • Use assert and expect interchangeably in the same suite: Standardize on one assertion style across the team.
  • Forget to install @types/chai: Ensure strict TypeScript typings are active in TS projects.

Troubleshooting

Error Cause Solution
AssertionError: expected { ... } to equal { ... } Using equal (strict equality) instead of deep.equal. Replace .to.equal() with .to.deep.equal().
TypeError: expect(...).to.be.true is not a function Calling Chai properties as functions. Use .to.be.true as a property getter, or install dirty-chai.
UnhandledPromiseRejection in chai-as-promised Missing await before asynchronous expectation. Prefix assertion with await expect(promise).to.eventually....

References