A Test-Anything-Protocol library for JavaScript with comprehensive testing capabilities and plugin-based architecture
—
Test creation, skipping, planning, and control flow management for organizing test suites with comprehensive test lifecycle control.
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();
});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();
});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();
});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();
});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();
});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();
});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