In short
Plenty of Node codebases don't use Jest. They use Mocha to run tests and Chai to check results. You'll meet this pair in real jobs, so it helps to read it comfortably.
A flexible, unopinionated test runner (Mocha) commonly paired with an assertion library (Chai) — an older but still widely used alternative to Jest in many Node.js codebases.

Think of it like this
The contest host and the judge
At a college cooking contest, the host runs the show: starts each round, keeps time, announces results. The judge just tastes and says pass or fail. Mocha is the host, organising and running the tests. Chai is the judge, making an assertion about each result.
Watch it happen
Two ways to set up a Node test suite
Jest
- Runner, assertions and mocks in one
- Little setup to get started
- A common default in many projects
Mocha + Chai
- Mocha runs tests; Chai asserts
- Pick your own mocks, like Sinon
- Common in older Node codebases
Both test the same things well. Use whatever the project already uses; for a fresh project, Jest, Vitest or node:test need the least setup.
The big ideas
What you need to know
Mocha runs, that's all
Mocha gives you describe, it, hooks and reporters. It doesn't mind which assertion library you use.
Chai asserts
Chai offers expect, should and assert styles. expect(total).to.equal(60) is the most common.
Mix and match
Add Sinon for spies and stubs, and c8 for coverage. More setup, but more control.
Config in .mocharc
A .mocharc.json file sets the spec pattern, timeout and any loader, such as one for TypeScript.
See it in code
Walk through the code
1import { expect } from "chai";2import { Cart } from "../src/cart.js";3 4describe("Cart", function () {5 let cart: Cart;6 beforeEach(function () { cart = new Cart(); });7 8 it("totals items", function () {9 cart.add({ name: "samosa", price: 20 }, 3);10 expect(cart.total()).to.equal(60);11 });12 13 it("rejects negative quantities", function () {14 expect(() => cart.add({ name: "chai", price: 15 }, -1)).to.throw("Invalid quantity");15 });16});1/4Chai provides expect. Mocha supplies the describe and it functions.
Run it with npx mocha. describe, it and beforeEach are globals that Mocha provides while running.
Save yourself the pain
Common mistakes
Oops
Using arrow functions everywhere, then calling this.timeout().
Do this instead
Arrow functions don't get Mocha's this. Use function () {} when you need this.timeout or this.retries.
Oops
Passing a promise to expect without awaiting it.
Do this instead
Await the result first, or use chai-as-promised with await expect(p).to.be.rejected, or you're checking a pending promise.
Your mission
Read and run a Mocha suite
Quick check
In a Mocha and Chai suite, which library decides whether expect(total).to.equal(60) passes?
Go deeper
- 1Set up Mocha + Chai and write a test equivalent to one you wrote in Jest.
- 2Compare Chai's `expect`/`should` assertion styles to Jest's built-in `expect`.
- 3Understand why some existing codebases still use Mocha+Chai over Jest.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.