A simple yet powerful testing framework for Node.js backend applications and libraries
npx @tessl/cli install tessl/npm-japa--runner@4.4.0Japa is a simple yet powerful testing framework specifically designed for Node.js backend applications and libraries. It offers a complete testing solution with a focus on simplicity, performance, and minimal bloat compared to frontend-oriented testing frameworks.
npm install @japa/runnerimport { test, configure, run } from "@japa/runner";For additional functionality:
import { Test, Suite, Runner, Group, Emitter } from "@japa/runner/core";
import { spec, dot, ndjson, github } from "@japa/runner/reporters";
import { disallowPinnedTests } from "@japa/runner/plugins";
import { runner } from "@japa/runner/factories";
import type { Config, CLIArgs, PluginFn } from "@japa/runner/types";For CommonJS:
const { test, configure, run } = require("@japa/runner");import { test, configure, run } from "@japa/runner";
import { assert } from "chai"; // or your preferred assertion library
// Configure the test runner
configure({
files: ["tests/**/*.spec.ts"],
forceExit: false,
});
// Define tests
test("should add two numbers", async (ctx) => {
const result = 2 + 3;
assert.equal(result, 5);
});
test.group("Math operations", (group) => {
test("should subtract numbers", async (ctx) => {
const result = 5 - 3;
assert.equal(result, 2);
});
});
// Run the tests
await run();Japa Runner is built around several key components:
Primary API for creating and running tests with configuration, CLI processing, and execution management.
function test(title: string, callback?: TestExecutor<TestContext, undefined>): Test<undefined>;
function configure(options: Config): void;
async function run(): Promise<void>;
function processCLIArgs(argv: string[]): void;Advanced test creation, grouping, and macro functionality for organizing complex test suites.
interface TestGroup {
(title: string, callback: (group: Group) => void): Group;
}
interface TestMacro {
<T extends (test: Test, ...args: any[]) => any>(callback: T): (...args: OmitFirstArg<Parameters<T>>) => ReturnType<T>;
}
function getActiveTest(): Test<any> | undefined;
function getActiveTestOrFail(): Test<any>;Comprehensive configuration options for test execution, filtering, and environment setup.
interface Config {
cwd?: string;
timeout?: number;
retries?: number;
filters?: Filters;
configureSuite?: (suite: Suite) => void;
reporters?: {
activated: string[];
list?: NamedReporterContract[];
};
plugins?: PluginFn[];
forceExit?: boolean;
setup?: SetupHookHandler[];
teardown?: TeardownHookHandler[];
}
interface Filters {
files?: string[];
suites?: string[];
tests?: string | string[];
groups?: string | string[];
tags?: string | string[];
}Built-in reporters and reporter creation for test output formatting and result reporting.
function spec(options?: BaseReporterOptions): NamedReporterContract;
function dot(options?: BaseReporterOptions): NamedReporterContract;
function ndjson(options?: BaseReporterOptions): NamedReporterContract;
function github(options?: BaseReporterOptions): NamedReporterContract;
interface BaseReporterOptions {
framesMaxLimit?: number;
}Plugin architecture for extending functionality with built-in and custom plugins.
interface PluginFn {
(japa: {
config: NormalizedConfig;
cliArgs: CLIArgs;
runner: Runner;
emitter: Emitter;
}): void | Promise<void>;
}
function disallowPinnedTests(options?: {
disallow?: boolean;
errorMessage?: string;
}): PluginFn;Low-level classes for advanced usage, testing frameworks, and plugin development.
class Runner {
bail(toggle?: boolean): this;
registerReporter(reporter: ReporterContract): void;
getSummary(): RunnerSummary;
}
class Test<TestData = undefined> {
throws(message: string | RegExp, errorConstructor?: any): this;
timeout(duration: number): this;
retry(count: number): this;
}
class TestContext {
cleanup(cleanupCallback: TestHooksCleanupHandler<TestContext>): void;
}Test runner factory for testing reporters, plugins, and creating isolated test environments.
function runner(): RunnerFactory;
class RunnerFactory {
configure(config: Config, argv?: string[]): this;
useEmitter(emitter: Emitter): this;
async runTest(title: string, callback: TestExecutor<TestContext, undefined>): Promise<RunnerSummary>;
bail(toggle?: boolean): this;
async runSuites(suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[]): Promise<RunnerSummary>;
}interface CLIArgs {
_?: string[];
tags?: string | string[];
files?: string | string[];
tests?: string | string[];
groups?: string | string[];
timeout?: string;
retries?: string;
reporters?: string | string[];
forceExit?: boolean;
failed?: boolean;
help?: boolean;
matchAll?: boolean;
listPinned?: boolean;
bail?: boolean;
bailLayer?: string;
}
type TestFiles = string | string[] | (() => URL[] | Promise<URL[]>);
interface TestSuite {
name: string;
files: TestFiles;
configure?: (suite: Suite) => void;
timeout?: number;
retries?: number;
}type SetupHookHandler = HookHandler<[runner: Runner], [error: Error | null, runner: Runner]>;
type TeardownHookHandler = HookHandler<[runner: Runner], [error: Error | null, runner: Runner]>;
interface HooksEvents {
setup: [[runner: Runner], [error: Error | null, runner: Runner]];
teardown: [[runner: Runner], [error: Error | null, runner: Runner]];
}