The next-gen flux-based test runner for Jest that provides test framework globals and event-driven test execution
npx @tessl/cli install tessl/npm-jest-circus@29.7.0Jest Circus is a flux-based test runner for Jest that provides test framework globals and event-driven test execution. It serves as the default test execution engine for Jest, offering a highly maintainable and extensible architecture with comprehensive test orchestration capabilities.
npm install jest-circus (included with Jest 27+)import { describe, it, test, beforeAll, afterAll, beforeEach, afterEach } from "jest-circus";For state management and execution:
import { getState, setState, resetState, run } from "jest-circus";For type definitions:
import { type Event, type State } from "jest-circus";For Jest integration (runner):
// Used in Jest configuration
import runner from "jest-circus/runner";
// or
const runner = require("jest-circus/runner");import { describe, it, test, beforeAll, afterAll, beforeEach, afterEach } from "jest-circus";
describe("Calculator", () => {
let calculator;
beforeAll(() => {
// Setup before all tests
calculator = new Calculator();
});
beforeEach(() => {
// Setup before each test
calculator.reset();
});
afterEach(() => {
// Cleanup after each test
calculator.clearMemory();
});
afterAll(() => {
// Cleanup after all tests
calculator = null;
});
it("should add numbers correctly", () => {
expect(calculator.add(2, 3)).toBe(5);
});
test("should multiply numbers correctly", () => {
expect(calculator.multiply(4, 5)).toBe(20);
});
test.concurrent("should handle concurrent tests", async () => {
const result = await calculator.asyncCalculation(10);
expect(result).toBe(100);
});
});Jest Circus is built around several key components:
describe, it, test) with support for lifecycle hooksCore testing functions for organizing and defining tests. Provides the standard Jest API with support for skipping, focusing, concurrent execution, and parameterized tests.
function describe(blockName: BlockNameLike, blockFn: BlockFn): void;
function it(testName: TestNameLike, fn: TestFn, timeout?: number): void;
function test(testName: TestNameLike, fn: TestFn, timeout?: number): void;
function beforeAll(fn: HookFn, timeout?: number): void;
function afterAll(fn: HookFn, timeout?: number): void;
function beforeEach(fn: HookFn, timeout?: number): void;
function afterEach(fn: HookFn, timeout?: number): void;Low-level state management for controlling test execution state and accessing runtime information.
function getState(): State;
function setState(state: State): State;
function resetState(): void;
interface State {
currentDescribeBlock: DescribeBlock;
currentlyRunningTest?: TestEntry | null;
rootDescribeBlock: DescribeBlock;
hasStarted: boolean;
hasFocusedTests: boolean;
testTimeout: number;
maxConcurrency: number;
unhandledErrors: Array<Exception>;
includeTestLocationInResult: boolean;
parentProcess: NodeJS.Process | null;
seed: number;
testNamePattern?: RegExp | null;
expand?: boolean;
randomize?: boolean;
}Core test execution engine that runs tests and produces results.
function run(): Promise<RunResult>;
interface RunResult {
unhandledErrors: Array<FormattedError>;
testResults: TestResults;
}Jest test runner adapter for integrating circus with Jest's infrastructure.
// Export from jest-circus/runner
function jestAdapter(
globalConfig: any,
config: any,
environment: any,
runtime: any,
testPath: string,
sendMessageToJest?: any
): Promise<any>;The runner is automatically used when jest-circus is configured as the test runner.
type BlockNameLike = string | Function;
type TestNameLike = string | Function;
type BlockName = string;
type TestName = string;
type BlockFn = () => void;
type TestFn = (done?: DoneFn) => void | Promise<void>;
type HookFn = (done?: DoneFn) => void | Promise<void>;
type DoneFn = (reason?: string | Error) => void;
type Exception = any;
type FormattedError = string;
type BlockMode = void | 'skip' | 'only' | 'todo';
type TestMode = BlockMode;
type HookType = 'beforeAll' | 'afterAll' | 'beforeEach' | 'afterEach';
interface DescribeBlock {
type: 'describeBlock';
children: Array<DescribeBlock | TestEntry>;
name: BlockName;
parent?: DescribeBlock;
mode: BlockMode;
hooks: Array<Hook>;
/** @deprecated Please get from children array instead */
tests: Array<TestEntry>;
}
interface TestEntry {
type: 'test';
asyncError: Exception;
concurrent: boolean;
errors: Array<Exception>;
retryReasons: Array<Exception>;
fn: TestFn;
mode: TestMode;
name: TestName;
parent: DescribeBlock;
seenDone: boolean;
timeout?: number;
failing: boolean;
invocations: number;
numPassingAsserts: number;
startedAt?: number | null;
duration?: number | null;
status?: 'skip' | 'done' | 'todo' | null;
}
interface Hook {
asyncError: Error;
fn: HookFn;
type: HookType;
parent: DescribeBlock;
seenDone: boolean;
timeout: number | undefined | null;
}
interface RunResult {
unhandledErrors: Array<FormattedError>;
testResults: Array<TestResult>;
}
interface TestResult {
duration?: number | null;
errors: Array<FormattedError>;
errorsDetailed: Array<unknown>;
invocations: number;
status: 'skip' | 'done' | 'todo';
location?: {column: number; line: number} | null;
numPassingAsserts: number;
retryReasons: Array<FormattedError>;
testPath: Array<TestName | BlockName>;
}
// Event types (re-exported from @jest/types)
type Event = SyncEvent | AsyncEvent;
type SyncEvent = {name: string; [key: string]: any};
type AsyncEvent = {name: string; [key: string]: any};