CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tap

A Test-Anything-Protocol library for JavaScript with comprehensive testing capabilities and plugin-based architecture

Pending
Overview
Eval results
Files

test-organization.mddocs/

Test Organization

Test creation, skipping, planning, and control flow management for organizing test suites with comprehensive test lifecycle control.

Capabilities

Test Creation

Core methods for creating and organizing tests with various execution strategies.

/**
 * Create a new test with the given name and function
 * @param name - Descriptive name for the test
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function test(name: string, fn?: TestFunction): Promise<void>;

/**
 * Create a new test with options
 * @param name - Descriptive name for the test
 * @param options - Test configuration options
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function test(name: string, options: TestOpts, fn?: TestFunction): Promise<void>;

/**
 * Skip a test - it won't be executed but will appear in output
 * @param name - Descriptive name for the skipped test
 * @param fn - Test function (not executed)
 * @returns Promise that resolves immediately
 */
function skip(name: string, fn?: TestFunction): Promise<void>;

/**
 * Skip a test with options
 * @param name - Descriptive name for the skipped test
 * @param options - Test configuration options
 * @param fn - Test function (not executed)
 * @returns Promise that resolves immediately
 */
function skip(name: string, options: TestOpts, fn?: TestFunction): Promise<void>;

/**
 * Mark a test as todo - it will run but failures won't cause test suite to fail
 * @param name - Descriptive name for the todo test
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function todo(name: string, fn?: TestFunction): Promise<void>;

/**
 * Mark a test as todo with options
 * @param name - Descriptive name for the todo test
 * @param options - Test configuration options
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function todo(name: string, options: TestOpts, fn?: TestFunction): Promise<void>;

/**
 * Run only this test (requires filter plugin) - other tests will be skipped
 * @param name - Descriptive name for the test
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function only(name: string, fn?: TestFunction): Promise<void>;

/**
 * Run only this test with options
 * @param name - Descriptive name for the test
 * @param options - Test configuration options
 * @param fn - Test function to execute
 * @returns Promise that resolves when test completes
 */
function only(name: string, options: TestOpts, fn?: TestFunction): Promise<void>;

Usage Examples:

import { test, skip, todo, only } from "tap";

// Basic test
test("addition works", (t) => {
  t.equal(2 + 2, 4);
  t.end();
});

// Test with options
test("async test", { timeout: 5000 }, async (t) => {
  const result = await asyncOperation();
  t.ok(result.success);
});

// Skip a test
skip("not implemented yet", (t) => {
  // This won't run
  t.fail("should not run");
  t.end();
});

// Todo test - runs but failures don't fail the suite
todo("fix this later", (t) => {
  t.fail("known issue"); // Won't cause suite failure
  t.end();
});

// Only run this test (requires --only flag or filter plugin)
only("debug this test", (t) => {
  t.ok(true);
  t.end();
});

Test Control

Methods for controlling test execution flow and planning.

/**
 * Set the expected number of assertions in this test
 * @param count - Number of assertions expected
 */
function plan(count: number): void;

/**
 * Explicitly end the test - useful for async tests
 */
function end(): void;

/**
 * Bail out of the entire test run with an optional reason
 * @param reason - Optional reason for bailing out
 */
function bailout(reason?: string): void;

/**
 * Set timeout for the current test in milliseconds
 * @param ms - Timeout in milliseconds
 */
function timeout(ms: number): void;

/**
 * Add a comment to the TAP output stream
 * @param message - Comment message
 */
function comment(message: string): void;

/**
 * Add a pragma directive to the TAP output
 * @param pragma - Pragma directive
 */
function pragma(pragma: string): void;

Usage Examples:

// Planned test - expects exactly 3 assertions
test("planned test", (t) => {
  t.plan(3);
  t.ok(true, "first assertion");
  t.ok(true, "second assertion");
  t.ok(true, "third assertion");
  // Test ends automatically after 3 assertions
});

// Explicit end for async tests
test("async test with explicit end", (t) => {
  setTimeout(() => {
    t.ok(true, "delayed assertion");
    t.end(); // Explicitly end the test
  }, 100);
});

// Test with timeout
test("timeout test", (t) => {
  t.timeout(1000); // 1 second timeout
  // Test will fail if it takes longer than 1 second
  t.ok(true);
  t.end();
});

// Adding comments and pragmas
test("documented test", (t) => {
  t.comment("Starting the test");
  t.pragma("version 14");
  t.ok(true);
  t.comment("Test completed successfully");
  t.end();
});

// Bail out example (use sparingly)
test("critical test", (t) => {
  if (!criticalCondition) {
    t.bailout("Critical condition not met, cannot continue");
    return;
  }
  t.ok(true);
  t.end();
});

Nested Tests

TAP supports nested test structures for organizing related tests.

test("parent test", (t) => {
  t.test("child test 1", (ct) => {
    ct.ok(true, "child assertion");
    ct.end();
  });
  
  t.test("child test 2", (ct) => {
    ct.equal(1 + 1, 2, "math works in child");
    ct.end();
  });
  
  t.end();
});

Test Options

interface TestOpts {
  /** Override the test name */
  name?: string;
  
  /** Timeout in milliseconds for this test */
  timeout?: number;
  
  /** Skip this test (boolean or reason string) */
  skip?: boolean | string;
  
  /** Mark as todo (boolean or reason string) */
  todo?: boolean | string;
  
  /** Run only this test (requires filter plugin) */
  only?: boolean;
  
  /** Bail out on first failure in this test */
  bail?: boolean;
  
  /** Run test even if parent test fails */
  autoend?: boolean;
  
  /** Buffer output until test completes */
  buffered?: boolean;
}

type TestFunction = (t: TAP) => void | Promise<void>;

Usage Examples:

// Test with multiple options
test("complex test", {
  timeout: 5000,
  skip: process.env.SKIP_SLOW_TESTS === "true",
  bail: true
}, async (t) => {
  await complexAsyncOperation();
  t.ok(true);
  t.end();
});

// Conditional skip
test("platform specific test", {
  skip: process.platform === "win32" ? "Not supported on Windows" : false
}, (t) => {
  t.ok(true);
  t.end();
});

// Todo with reason
test("future feature", {
  todo: "Waiting for API changes"
}, (t) => {
  t.ok(false, "This will fail but won't fail the suite");
  t.end();
});

Subtests vs Top-Level Tests

TAP distinguishes between top-level tests and subtests:

// Top-level test - runs in its own process
test("top level", (t) => {
  // This runs in a separate process
  t.ok(true);
  
  // Subtest - runs in the same process as parent
  t.test("subtest", (st) => {
    st.ok(true);
    st.end();
  });
  
  t.end();
});

Test Filtering

When using the filter plugin, you can control which tests run:

// Only run tests marked with 'only'
test("normal test", (t) => {
  // Skipped when --only is used
  t.ok(true);
  t.end();
});

only("focused test", (t) => {
  // Only this runs when --only is used
  t.ok(true);
  t.end();
});

Asynchronous Test Patterns

TAP supports several patterns for async testing:

// Promise-based test
test("promise test", async (t) => {
  const result = await fetchData();
  t.ok(result.success);
  // No need to call t.end() with async functions
});

// Callback-based test with explicit end
test("callback test", (t) => {
  fetchDataWithCallback((err, result) => {
    t.error(err);
    t.ok(result.success);
    t.end(); // Must call end() for non-async functions
  });
});

// Mixed async/sync with planning
test("mixed test", (t) => {
  t.plan(2);
  t.ok(true, "sync assertion");
  
  setTimeout(() => {
    t.ok(true, "async assertion");
    // Test ends after 2 assertions due to plan
  }, 100);
});

Install with Tessl CLI

npx tessl i tessl/npm-tap

docs

assertions.md

index.md

lifecycle-hooks.md

mocking.md

subprocess-testing.md

test-organization.md

tile.json