Skip to content

mocha-chain ​

Chain Mocha hooks so each one passes typed context to the next, instead of sharing nullable variables between them.

ts
import { 
expect
} from 'chai';
import {
beforeEach
,
suite
} from 'mocha-chain';
suite
('Counter', () => {
const
withCounter
=
beforeEach
(() => ({
counter
: new
Counter
() }));
withCounter
.
test
('starts at zero', ({
counter
}) => {
counter: Counter
expect
(
counter
.
increment
()).
to
.
equal
(1);
}); });

counter is a Counter in every test, never Counter | undefined, and each test gets a new one.

Get started →

Features ​

  • Typed context: a hook returns an object, and the hooks and tests chained to it receive it as their first parameter, merged with what earlier hooks returned.
  • Isolated tests: each test gets a shallow copy of the context, from hooks that ran for it.
  • Just Mocha: every function calls Mocha's own, so this.timeout(), .only(), .skip(), retries and reporters all work, and native Mocha calls can be mixed in.
  • Catches misplaced tests: a test or hook declared inside another test or hook throws, where Mocha would silently ignore it.
  • Teardown with the same context: afterEach and after receive what setup returned, so cleanup is typed too.
  • For Vitest too: vitest-chain is the same API for Vitest.

Compared to ​

  • Plain Mocha: a let variable assigned in beforeEach must be typed T | undefined, and asserted non-null in every test. See Why mocha-chain.
  • mocha-typescript and similar class-based wrappers give tests typed fields through decorators and class instances. mocha-chain keeps Mocha's functional style, and needs no decorators.
  • Vitest's test context (test.extend) types fixtures for Vitest. vitest-chain brings the hook-based style to Vitest instead.