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

assertions.mddocs/

Assertions

Comprehensive assertion library providing deep equality, pattern matching, type checking, error handling, and promise testing with detailed failure reporting. The TAP assertion API includes over 30 methods for thorough testing.

Core Imports

import { test, ok, same, throws, equal } from "tap";
// All assertion methods are available on the test instance 't'

Types

type MessageExtra = [] | [msg: string, extra?: Extra] | [extra: Extra];

type ThrowsArgs = 
  | []
  | [msg: string, extra?: Extra] 
  | [wanted: ErrorMatch, ...messageExtra: MessageExtra];

interface Extra {
  [key: string]: any;
  compareOptions?: CompareOptions;
  // Additional optional properties for test metadata
}

type ErrorMatch = Error | typeof Error | RegExp | { message?: string | RegExp; [k: string]: any };

Capabilities

Basic Assertions

Core assertion methods for testing truthiness and basic conditions.

/**
 * Verify that the value is truthy
 */
function ok(obj: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value is not truthy  
 */
function notOk(obj: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * A passing (ok) Test Point
 */
function pass(...[msg, extra]: MessageExtra): boolean;

/**
 * A failing (not ok) Test Point
 */
function fail(...[msg, extra]: MessageExtra): boolean;

Usage Examples:

import { test } from "tap";

test("basic assertions", (t) => {
  t.ok(true, "true is truthy");
  t.ok(1, "1 is truthy"); 
  t.ok("hello", "non-empty string is truthy");
  
  t.notOk(false, "false is falsy");
  t.notOk(0, "0 is falsy");
  t.notOk("", "empty string is falsy");
  
  t.pass("this always passes");
  // t.fail("this would always fail");
  
  t.end();
});

Equality Assertions

Deep comparison methods for testing equality and inequality with different comparison strategies.

/**
 * Verify that the values are equal (strict equality with type guard)
 */
function equal<T extends unknown>(
  found: any,
  wanted: T,
  ...[msg, extra]: MessageExtra
): found is T;

/**
 * Verify that the values are not equal (strict inequality)
 */
function not(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value is loosely equivalent to the supplied pattern
 */
function same(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value is not loosely equivalent to the supplied pattern
 */
function notSame(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value is strictly equivalent to the supplied pattern
 */
function strictSame<T extends unknown>(
  found: any,
  wanted: T,
  ...[msg, extra]: MessageExtra
): found is T;

/**
 * Verify that the value is not strictly equivalent to the supplied pattern
 */
function strictNotSame(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

Usage Examples:

test("equality assertions", (t) => {
  // Strict equality with type guard
  t.equal(5, 5, "numbers are strictly equal");
  t.not("1", 1, "string and number are not equal");
  
  // Deep object equality
  t.same({ a: 1, b: 2 }, { a: 1, b: 2 }, "objects are loosely equal");
  t.strictSame([1, 2, 3], [1, 2, 3], "arrays are strictly equal");
  
  // Inequality
  t.notSame({ a: 1 }, { a: 2 }, "objects are different");  
  t.strictNotSame("1", 1, "string and number are strictly different");
  
  t.end();
});

Object Property Assertions

Methods for testing object properties and structure with various comparison modes.

/**
 * Verify that the object has all properties and values in the pattern (loose comparison)
 */
function has(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the object does NOT have all properties and values in the pattern (loose comparison)
 */
function notHas(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value has all properties and values in the pattern (strict comparison)
 */
function hasStrict(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value does NOT contain all properties and values in the pattern (strict comparison)
 */
function notHasStrict(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

Usage Examples:

test("property assertions", (t) => {
  const user = { name: "Alice", age: 30, active: true };
  
  t.has(user, { name: "Alice" }, "user has name property");
  t.has(user, { name: "Alice", age: 30 }, "user has name and age");
  t.notHas(user, { email: "test@example.com" }, "user doesn't have email");
  
  // Strict comparison
  t.hasStrict(user, { age: 30 }, "user has exact age");
  t.notHasStrict(user, { age: "30" }, "user age is number, not string");
  
  t.end();
});

Property Existence Methods

Methods for checking individual or multiple property existence.

/**
 * Verify that the object has the wanted property, anywhere in its prototype chain
 */
function hasProp<T extends {}>(
  found: T,
  wanted: string | number | symbol,
  ...[msg, extra]: MessageExtra
): boolean;

/**
 * Verify that the object has the wanted property, using Object#hasOwnProperty
 */
function hasOwnProp<T extends {}>(
  found: T,
  wanted: string | number | symbol,
  ...[msg, extra]: MessageExtra
): boolean;

/**
 * Verify that the object has all properties in the wanted list, anywhere in its prototype chain
 */
function hasProps<T extends {}>(
  found: T,
  wanted: Iterable<string | number | symbol>,
  ...[msg, extra]: MessageExtra
): boolean;

/**
 * Verify that the object has all properties in the wanted list, using Object#hasOwnProperties()
 */
function hasOwnProps<T extends {}>(
  found: T,
  wanted: Iterable<string | number | symbol>,
  ...[msg, extra]: MessageExtra
): boolean;

/**
 * Verify that the object has all properties in the wanted list and no others, using Object#hasOwnProperties()
 */
function hasOwnPropsOnly<T extends {}>(
  found: T,
  wanted: Iterable<string | number | symbol>,
  ...[msg, extra]: MessageExtra
): boolean;

Usage Examples:

test("property existence", (t) => {
  const obj = { a: 1, b: 2, c: 3 };
  
  t.hasProp(obj, "a", "object has property 'a'");
  t.hasOwnProp(obj, "b", "object has own property 'b'");
  
  t.hasProps(obj, ["a", "b"], "object has properties a and b");
  t.hasOwnProps(obj, ["a", "b", "c"], "object has all own properties");
  t.hasOwnPropsOnly(obj, ["a", "b", "c"], "object has exactly these properties");
  
  t.end();
});

Pattern Matching

Advanced pattern matching with regular expressions and object patterns.

/**
 * Verify that the value matches the pattern provided
 */
function match(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value does NOT match the pattern provided
 */
function notMatch(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value matches the pattern provided, with no extra properties
 */
function matchOnly(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value does not match the pattern or has extra properties
 */
function notMatchOnly(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value matches the pattern provided, but fail if any fields only match via type coercion
 */
function matchStrict(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value does not match the pattern provided, without type coercion
 */
function notMatchStrict(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value matches the pattern provided strictly, with no extra properties
 */
function matchOnlyStrict(found: any, wanted: any, ...[msg, extra]: MessageExtra): boolean;

/**
 * Verify that the value does not match the pattern strictly or has extra properties
 */
function notMatchOnlyStrict(found: any, doNotWant: any, ...[msg, extra]: MessageExtra): boolean;

Usage Examples:

test("pattern matching", (t) => {
  // Regex matching
  t.match("hello world", /world/, "string contains 'world'");
  t.notMatch("hello", /goodbye/, "string doesn't contain 'goodbye'");
  
  // Object pattern matching
  const response = { status: "success", data: { id: 123, name: "test" } };
  t.match(response, { status: "success" }, "response has success status");
  t.matchOnly({ a: 1 }, { a: 1 }, "exact match with no extra properties");
  
  // Strict matching prevents type coercion
  t.matchStrict({ a: 1 }, { a: Number }, "matches constructor type");
  // t.matchStrict({ a: 1 }, { a: '1' }, 'this would fail due to type coercion');
  
  t.end();
});

Type Checking

Type checking assertion methods.

/**
 * Verify that the value is of the type specified
 * Type can be either a string, or a constructor.
 * If a string, then it can match either the `typeof` result or 'null' for `null` values,
 * or the `name` property of the object's constructor.
 */
function type(
  obj: any,
  klass: string | Function,
  ...[msg, extra]: MessageExtra
): boolean;

Usage Examples:

test("type checking", (t) => {
  t.type("hello", "string", "value is a string");
  t.type(123, "number", "value is a number");
  t.type([], Array, "value is an array");
  t.type(new Date(), Date, "value is a Date object");
  
  t.end();
});

Exception Testing

Methods for testing function throws and error conditions.

/**
 * Verify that the function throws an error.
 * Thrown error is tested against the `wanted` param if provided, using `t.match()`.
 * Returns false on failure, or the error object thrown on success
 */
function throws(
  fn: Function | (() => any),
  ...[wanted, msg, extra]: ThrowsArgs
): boolean | Error;

/**
 * Returns the error object if it throws and that does not fail the test
 * (by virtue of being marked skip or todo). Otherwise returns the passing status.
 */
function doesNotThrow(
  fn: Function | (() => any),
  ...[msg, extra]: MessageExtra
): boolean | Error;

/**
 * Assert that an error object is not provided.
 * Useful for asserting that a callback did not receive an error.
 */
function error(er: unknown, ...[msg, extra]: MessageExtra): boolean;

Usage Examples:

test("exception testing", (t) => {
  // Test that function throws
  t.throws(() => { throw new Error("test error"); }, "function throws error");
  
  // Test specific error message
  t.throws(
    () => { throw new Error("specific message"); },
    { message: "specific message" },
    "function throws expected error"
  );
  
  // Test that function doesn't throw
  t.doesNotThrow(() => { return "ok"; }, "function doesn't throw");
  
  // Test no error occurred
  t.error(null, "no error occurred");
  t.error(undefined, "no error occurred");
  
  t.end();
});

Promise Testing

Assertions for testing Promise resolution, rejection, and resolved values.

/**
 * Resolves to the error object rejected if it rejects as expected,
 * 'false' if it does not, or 'true' if it fails to reject but is marked as skip/todo.
 */
async function rejects<T extends any = any>(
  fnOrPromise: (() => Promise<T>) | Promise<T>,
  ...[wanted, msg, extra]: ThrowsArgs
): Promise<boolean | Error>;

/**
 * Resolves to 'true' if the promise resolves successfully, 'false' if
 * it rejects and fails, or the rejection error if it rejects but the
 * failure is accepted by being marked todo or skip
 */
async function resolves<T extends any = any>(
  fnOrPromise: Promise<T> | (() => Promise<T>),
  ...[msg, extra]: MessageExtra
): Promise<boolean | Error>;

/**
 * Test the resolved promise result with `t.match()`
 * Resolves to true if it passes, false if the promise rejects or the match fails
 */
async function resolveMatch<T extends any = any>(
  fnOrPromise: Promise<T> | (() => Promise<T>),
  wanted: any,
  ...[msg, extra]: MessageExtra
): Promise<boolean>;

Usage Examples:

test("promise testing", async (t) => {
  // Test promise rejection
  await t.rejects(
    Promise.reject(new Error("failed")),
    "promise should reject"
  );
  
  // Test promise resolution
  await t.resolves(
    Promise.resolve("success"),
    "promise should resolve"
  );
  
  // Test resolved value matches pattern
  await t.resolveMatch(
    Promise.resolve({ status: "ok", data: [1, 2, 3] }),
    { status: "ok" },
    "resolved value matches expected pattern"
  );
  
  // Test async function
  await t.resolves(
    async () => {
      const result = await someAsyncOperation();
      return result;
    },
    "async function resolves successfully"
  );
});

Event Testing

Assert that events are emitted by event emitters.

/**
 * Asserts that the emitter emits the specified event before the test ends.
 * Returns a promise that resolves when the event is emitted.
 * Note that waiting on the returned promise within a test can deadlock
 * the test, if the event never emits.
 */
function emits(
  emitter: EventEmitter | EventTarget,
  event: string,
  ...[msg, extra]: MessageExtra
): Promise<void>;

Usage Examples:

import { EventEmitter } from "events";

test("event assertions", (t) => {
  const emitter = new EventEmitter();
  
  t.emits(emitter, "data", "emitter will emit data event");
  
  // Trigger the event
  setTimeout(() => {
    emitter.emit("data", { id: 123 });
  }, 10);
  
  t.end();
});

test("async event waiting", async (t) => {
  const emitter = new EventEmitter();
  
  // Start listening for the event
  const eventPromise = t.emits(emitter, "ready", "ready event will be emitted");
  
  // Trigger the event asynchronously
  setTimeout(() => emitter.emit("ready"), 50);
  
  // Wait for the event to fire
  await eventPromise;
  
  t.pass("event was successfully emitted");
});

Important Implementation Notes

MessageExtra Pattern

All assertion methods use a rest parameter pattern ...[msg, extra]: MessageExtra where:

  • MessageExtra can be empty [], just a message [string], just extra data [Extra], or both [string, Extra]
  • This provides flexible parameter handling for all assertion methods

Return Types

Many assertion methods return boolean | Error:

  • boolean for normal pass/fail results
  • Error object when an error occurs but the test is marked as todo/skip

Type Guards

Some methods like equal and strictSame include TypeScript type guards (found is T) that narrow the type of the tested value when the assertion passes.

Async Assertions

Promise-related assertions (rejects, resolves, resolveMatch) are async functions that return Promises, allowing for proper async/await usage in tests.

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