CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-japa--runner

A simple yet powerful testing framework for Node.js backend applications and libraries

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

factories.mddocs/

Factory System

Test runner factory for testing reporters, plugins, and creating isolated test environments.

Capabilities

Runner Factory Function

Creates a new instance of the runner factory for testing and development purposes.

/**
 * Create an instance of the runner factory
 * @returns RunnerFactory instance for creating isolated test environments
 */
function runner(): RunnerFactory;

RunnerFactory Class

Factory class that provides an API to run dummy suites, groups, and tests for testing reporters and plugins.

/**
 * Runner factory exposes the API to run dummy suites, groups and tests.
 * You might want to use the factory for testing reporters and plugins usage.
 */
class RunnerFactory {
  /** Configure the factory with test configuration and CLI arguments */
  configure(config: Config, argv?: string[]): this;
  
  /** Define a custom emitter instance to use */
  useEmitter(emitter: Emitter): this;
  
  /** Run a single test using the runner */
  async runTest(title: string, callback: TestExecutor<TestContext, undefined>): Promise<RunnerSummary>;
  
  /** Enable/disable the bail mode */
  bail(toggle?: boolean): this;
  
  /** Run dummy test suites */
  async runSuites(suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[]): Promise<RunnerSummary>;
}

Usage Examples:

import { runner } from "@japa/runner/factories";
import { assert } from "chai";

// Create factory instance
const factory = runner();

// Configure the factory
factory.configure({
  files: ["tests/**/*.spec.ts"],
  reporters: {
    activated: ["spec"],
  },
});

// Run a single test
const summary = await factory.runTest("should work", async (ctx) => {
  assert.equal(2 + 2, 4);
});

console.log(`Test result: ${summary.hasError ? "FAILED" : "PASSED"}`);

Testing Reporters

Use the factory to test custom reporters in isolation.

Usage Examples:

import { runner } from "@japa/runner/factories";
import { Emitter, Suite, Test, TestContext } from "@japa/runner/core";
import { assert } from "chai";

// Custom reporter to test
const customReporter = {
  name: "test-reporter",
  handler: (runner, emitter) => {
    const results: string[] = [];
    
    emitter.on("test:start", (payload) => {
      results.push(`START: ${payload.title}`);
    });
    
    emitter.on("test:end", (payload) => {
      const status = payload.hasError ? "FAIL" : "PASS";
      results.push(`END: ${payload.title} - ${status}`);
    });
    
    return { results };
  },
};

// Test the reporter
const factory = runner();
factory.configure({
  files: [],
  reporters: {
    activated: ["test-reporter"],
    list: [customReporter],
  },
});

// Run test with custom reporter
const summary = await factory.runTest("sample test", async (ctx) => {
  assert.isTrue(true);
});

// Verify reporter output
console.log("Reporter captured:", customReporter.handler().results);

Testing Plugins

Use the factory to test custom plugins in isolation.

Usage Examples:

import { runner } from "@japa/runner/factories";
import { assert } from "chai";

// Custom plugin to test
const testPlugin = () => {
  const events: string[] = [];
  
  return ({ emitter }) => {
    emitter.on("runner:start", () => {
      events.push("runner started");
    });
    
    emitter.on("test:start", (payload) => {
      events.push(`test started: ${payload.title}`);
    });
    
    emitter.on("test:end", (payload) => {
      events.push(`test ended: ${payload.title}`);
    });
    
    emitter.on("runner:end", () => {
      events.push("runner ended");
    });
    
    // Expose events for testing
    return { events };
  };
};

// Test the plugin
const factory = runner();
const pluginInstance = testPlugin();

factory.configure({
  files: [],
  plugins: [pluginInstance],
});

// Run test with plugin
await factory.runTest("plugin test", async (ctx) => {
  assert.equal(1 + 1, 2);
});

// Verify plugin behavior
console.log("Plugin events:", pluginInstance().events);

Running Multiple Test Suites

Create and run complex test scenarios with multiple suites.

Usage Examples:

import { runner } from "@japa/runner/factories";
import { Suite, Test, TestContext, Group, Emitter, Refiner } from "@japa/runner/core";
import { assert } from "chai";

const factory = runner();

factory.configure({
  files: [],
  reporters: {
    activated: ["spec"],
  },
});

// Create test suites programmatically
const summary = await factory.runSuites((emitter, refiner, file) => {
  // Unit tests suite
  const unitSuite = new Suite("unit", emitter, refiner);
  
  const mathGroup = new Group("Math operations", emitter, refiner);
  const addTest = new Test("should add numbers", (test) => new TestContext(test), emitter, refiner, mathGroup);
  addTest.run(async (ctx) => {
    assert.equal(2 + 3, 5);
  }, new Error());
  
  unitSuite.add(mathGroup);
  
  // Integration tests suite
  const integrationSuite = new Suite("integration", emitter, refiner);
  
  const apiTest = new Test("should call API", (test) => new TestContext(test), emitter, refiner);
  apiTest.run(async (ctx) => {
    // Mock API call
    const result = await Promise.resolve({ status: "ok" });
    assert.equal(result.status, "ok");
  }, new Error());
  
  integrationSuite.add(apiTest);
  
  return [unitSuite, integrationSuite];
});

console.log(`Ran ${summary.aggregates.total} tests, ${summary.aggregates.passed} passed`);

Factory with Custom Emitter

Use a custom emitter to capture and analyze test events.

Usage Examples:

import { runner } from "@japa/runner/factories";
import { Emitter } from "@japa/runner/core";
import { assert } from "chai";

// Custom emitter with event logging
class LoggingEmitter extends Emitter {
  private eventLog: Array<{ event: string; timestamp: number; payload?: any }> = [];
  
  emit(event: string, ...args: any[]) {
    this.eventLog.push({
      event,
      timestamp: Date.now(),
      payload: args.length === 1 ? args[0] : args,
    });
    
    return super.emit(event, ...args);
  }
  
  getEventLog() {
    return this.eventLog;
  }
  
  clearLog() {
    this.eventLog = [];
  }
}

// Use custom emitter with factory
const customEmitter = new LoggingEmitter();
const factory = runner();

factory
  .useEmitter(customEmitter)
  .configure({
    files: [],
  });

// Run test and capture events
await factory.runTest("event logging test", async (ctx) => {
  assert.isTrue(true);
});

// Analyze captured events
const events = customEmitter.getEventLog();
console.log("Captured events:", events.map(e => e.event));

Bail Mode Testing

Test bail mode behavior where execution stops on first failure.

Usage Examples:

import { runner } from "@japa/runner/factories";
import { assert } from "chai";

const factory = runner();

// Enable bail mode
factory
  .bail(true)
  .configure({
    files: [],
  });

// Run suites with bail mode
const summary = await factory.runSuites((emitter, refiner) => {
  const suite = new Suite("bail test", emitter, refiner);
  
  // First test (will fail)
  const failingTest = new Test("failing test", (test) => new TestContext(test), emitter, refiner);
  failingTest.run(async (ctx) => {
    assert.equal(1, 2); // This will fail
  }, new Error());
  
  // Second test (should not run due to bail)
  const passingTest = new Test("passing test", (test) => new TestContext(test), emitter, refiner);
  passingTest.run(async (ctx) => {
    assert.equal(1, 1);
  }, new Error());
  
  suite.add(failingTest);
  suite.add(passingTest);
  
  return [suite];
});

console.log(`Bail mode: ${summary.aggregates.total} total, ${summary.aggregates.failed} failed`);

Sync Reporter

Built-in synchronous reporter for testing that throws on test failures.

/**
 * Synchronous reporter that throws errors on test failures
 * Useful for testing scenarios where you want immediate failure feedback
 */
const syncReporter: ReporterContract;

Usage Examples:

import { runner, syncReporter } from "@japa/runner/factories";
import { assert } from "chai";

const factory = runner();

factory.configure({
  files: [],
  reporters: {
    activated: ["sync"],
    list: [syncReporter],
  },
});

try {
  // This will throw if any test fails
  await factory.runTest("failing test", async (ctx) => {
    assert.equal(1, 2);
  });
} catch (error) {
  console.log("Test failed as expected:", error.message);
}

Create Dummy Tests

Utility function for creating test data and scenarios.

/**
 * Create dummy tests for testing and development purposes
 */
function createDummyTests(): any; // Implementation specific

Types

Factory Types

interface RunnerFactory {
  configure(config: Config, argv?: string[]): this;
  useEmitter(emitter: Emitter): this;
  runTest(title: string, callback: TestExecutor<TestContext, undefined>): Promise<RunnerSummary>;
  bail(toggle?: boolean): this;
  runSuites(suites: (emitter: Emitter, refiner: Refiner, file?: string) => Suite[]): Promise<RunnerSummary>;
}

interface RunnerSummary {
  hasError: boolean;
  aggregates: {
    passed: number;
    failed: number;
    skipped: number;
    todo: number;
    total: number;
  };
  failureTree: Array<{
    name: string;
    errors: Array<{ phase: string; error: Error }>;
    children: Array<{
      name: string;
      errors: Array<{ phase: string; error: Error }>;
    }>;
  }>;
}

Suite Factory Function Type

type SuiteFactory = (emitter: Emitter, refiner: Refiner, file?: string) => Suite[];

docs

configuration.md

core-api.md

core-classes.md

factories.md

index.md

plugins.md

reporters.md

test-management.md

tile.json