A simple yet powerful testing framework for Node.js backend applications and libraries
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Comprehensive configuration options for test execution, filtering, and environment setup.
Core configuration options that apply to all test execution modes.
interface BaseConfig {
/** Current working directory for searching test files */
cwd?: string;
/** Default timeout for all tests (can be overridden per test) */
timeout?: number;
/** Default retries for all tests (can be overridden per test) */
retries?: number;
/** Test filters to apply */
filters?: Filters;
/** Hook to configure suites before execution */
configureSuite?: (suite: Suite) => void;
/** Reporter configuration */
reporters?: {
activated: string[];
list?: NamedReporterContract[];
};
/** Array of plugins to register */
plugins?: PluginFn[];
/** Custom test file importer */
importer?: (filePath: URL) => void | Promise<void>;
/** Custom test refiner for filtering */
refiner?: Refiner;
/** Force exit after test completion */
forceExit?: boolean;
/** Global setup hooks */
setup?: SetupHookHandler[];
/** Global teardown hooks */
teardown?: TeardownHookHandler[];
/** Directories to exclude when searching for test files */
exclude?: string[];
}Configuration for running tests from file patterns.
interface ConfigWithFiles extends BaseConfig {
/** Test files to execute - glob patterns, arrays, or functions */
files: TestFiles;
}
type TestFiles = string | string[] | (() => URL[] | Promise<URL[]>);Usage Examples:
import { configure } from "@japa/runner";
// Simple file-based configuration
configure({
files: ["tests/**/*.spec.ts"],
timeout: 5000,
forceExit: false,
});
// Advanced file patterns
configure({
files: [
"tests/unit/**/*.spec.ts",
"tests/integration/**/*.spec.ts",
"!tests/**/*.skip.ts", // Exclude files
],
cwd: process.cwd(),
exclude: ["node_modules", "build"],
});
// Dynamic file loading
configure({
files: async () => {
const testFiles = await discoverTestFiles();
return testFiles.map(file => new URL(file, import.meta.url));
},
});Configuration for organizing tests into named suites with different settings.
interface ConfigWithSuites extends BaseConfig {
/** Array of test suites with individual configuration */
suites: TestSuite[];
}
interface TestSuite {
/** Unique name for the suite */
name: string;
/** Files associated with this suite */
files: TestFiles;
/** Function to configure the suite */
configure?: (suite: Suite) => void;
/** Suite-specific timeout */
timeout?: number;
/** Suite-specific retries */
retries?: number;
}Usage Examples:
import { configure } from "@japa/runner";
configure({
suites: [
{
name: "unit",
files: ["tests/unit/**/*.spec.ts"],
timeout: 2000,
configure: (suite) => {
suite.timeout(2000);
},
},
{
name: "integration",
files: ["tests/integration/**/*.spec.ts"],
timeout: 10000,
retries: 2,
configure: (suite) => {
suite.timeout(10000);
},
},
{
name: "e2e",
files: () => import("./e2e-file-discovery.js").then(m => m.getE2EFiles()),
timeout: 30000,
},
],
});Advanced filtering options for running specific tests, groups, or files.
interface Filters {
/** File patterns to include */
files?: string[];
/** Suite names to include */
suites?: string[];
/** Test patterns to include */
tests?: string | string[];
/** Group patterns to include */
groups?: string | string[];
/** Tags to include */
tags?: string | string[];
}Usage Examples:
import { configure } from "@japa/runner";
// Filter by patterns
configure({
files: ["tests/**/*.spec.ts"],
filters: {
tests: ["should authenticate*", "*validation*"],
groups: ["User Management", "API Tests"],
tags: ["@slow", "@integration"],
},
});
// Filter by files and suites
configure({
suites: [
{ name: "unit", files: ["tests/unit/**/*.spec.ts"] },
{ name: "integration", files: ["tests/integration/**/*.spec.ts"] },
],
filters: {
suites: ["unit"], // Only run unit tests
files: ["**/auth*.spec.ts"], // Only auth-related files
},
});Configuration for test output formatting and reporting.
interface ReporterConfig {
/** Names of activated reporters */
activated: string[];
/** Custom reporter instances */
list?: NamedReporterContract[];
}
interface NamedReporterContract {
name: string;
handler: (...args: any[]) => ReporterContract;
}
interface BaseReporterOptions {
framesMaxLimit?: number;
}Usage Examples:
import { configure } from "@japa/runner";
import { spec, dot, ndjson } from "@japa/runner/reporters";
configure({
files: ["tests/**/*.spec.ts"],
reporters: {
activated: ["spec", "custom"],
list: [
spec({ framesMaxLimit: 10 }),
dot(),
{
name: "custom",
handler: (runner, emitter) => ({
// Custom reporter implementation
}),
},
],
},
});Global setup and teardown hooks for test environment management.
type SetupHookHandler = (runner: Runner) => void | Promise<void>;
type TeardownHookHandler = (error: Error | null, runner: Runner) => void | Promise<void>;Usage Examples:
import { configure } from "@japa/runner";
configure({
files: ["tests/**/*.spec.ts"],
setup: [
async (runner) => {
// Initialize database
await connectToDatabase();
console.log("Database connected");
},
async (runner) => {
// Start test server
await startTestServer();
console.log("Test server started");
},
],
teardown: [
async (error, runner) => {
// Cleanup database
await disconnectFromDatabase();
console.log("Database disconnected");
},
async (error, runner) => {
// Stop test server
await stopTestServer();
console.log("Test server stopped");
},
],
});Plugin system for extending test runner functionality.
interface PluginFn {
(japa: {
config: NormalizedConfig;
cliArgs: CLIArgs;
runner: Runner;
emitter: Emitter;
}): void | Promise<void>;
}Usage Examples:
import { configure } from "@japa/runner";
import { disallowPinnedTests } from "@japa/runner/plugins";
// Custom plugin
const customPlugin = () => {
return ({ runner, emitter, config }) => {
emitter.on("test:end", (payload) => {
if (payload.hasError) {
console.log(`Test failed: ${payload.title}`);
}
});
};
};
configure({
files: ["tests/**/*.spec.ts"],
plugins: [
disallowPinnedTests({ disallow: true }),
customPlugin(),
],
});type Config = BaseConfig & (
| { files: TestFiles }
| { suites: TestSuite[] }
);
interface NormalizedConfig {
// All BaseConfig properties are required after normalization
cwd: string;
timeout: number;
retries: number;
filters: Filters;
configureSuite: (suite: Suite) => void;
reporters: {
activated: string[];
list: NamedReporterContract[];
};
plugins: PluginFn[];
importer: (filePath: URL) => void | Promise<void>;
refiner: Refiner;
forceExit: boolean;
setup: SetupHookHandler[];
teardown: TeardownHookHandler[];
exclude: string[];
} & (
| { files: TestFiles }
| { suites: Required<TestSuite>[] }
);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;
}