Skip to content

link-foundation/test-anywhere

Repository files navigation

test-anywhere

npm version npm downloads CI/CD License

A universal JavaScript testing framework that works seamlessly across Bun, Deno, and Node.js. Write your tests once and run them anywhere.

Features

  • Universal API - Single test API that works across all three runtimes
  • Zero Dependencies - Built on top of native testing frameworks
  • Runtime Detection - Automatically uses the appropriate native test implementation
  • Simple Assertions - Built-in assertion library for common testing needs
  • Type Safe - Written with modern JavaScript/ESM modules

Installation

Node.js

npm install test-anywhere

Bun

bun add test-anywhere

Deno

No installation needed! Import directly from npm:

import { test, assert } from 'npm:test-anywhere';

Or from your local installation:

import { test, assert } from './node_modules/test-anywhere/index.js';

Usage

Basic Test Syntax

You can use either test() or it() (Mocha/Jest style):

import { test, it, assert } from 'test-anywhere';

// Using test()
test('basic math works', () => {
  assert.equal(1 + 1, 2);
});

// Using it() - same as test()
it('should compare objects', () => {
  assert.deepEqual({ a: 1 }, { a: 1 });
});

BDD-Style with describe()

Group related tests using describe() blocks:

import { describe, it, assert } from 'test-anywhere';

describe('user module', () => {
  describe('creation', () => {
    it('should create a new user', () => {
      assert.ok(true);
    });

    it('should validate email format', () => {
      assert.match('[email protected]', /@/);
    });
  });

  describe('deletion', () => {
    it('should delete existing user', () => {
      assert.ok(true);
    });
  });
});

Node.js

Run tests:

node --test
# or
npm test

Deno

Create a test file (e.g., example.test.js):

import { test, assert } from 'npm:test-anywhere';

test('basic math works', () => {
  assert.equal(1 + 1, 2);
});

test('strings work', () => {
  assert.ok('hello'.includes('ell'));
});

Run tests:

deno test --allow-read

The --allow-read permission is needed for Deno to import the module.

Bun

Create a test file (e.g., example.test.js):

import { test, assert } from 'test-anywhere';

test('basic math works', () => {
  assert.equal(1 + 1, 2);
});

test('async operations work', async () => {
  const result = await Promise.resolve(42);
  assert.equal(result, 42);
});

Run tests:

bun test

API Reference

Test Definition

test(name, fn) / it(name, fn)

Creates a test with the given name and test function. it() is an alias for test().

Parameters:

  • name (string): The name/description of the test
  • fn (function): The test function to execute

Example:

test('my test name', () => {
  // test code here
});

// or using it() - Mocha/Jest style
it('should do something', () => {
  // test code here
});

describe(name, fn)

Groups related tests together (BDD style).

Parameters:

  • name (string): The suite name
  • fn (function): Function containing tests and setup/teardown hooks

Example:

describe('user authentication', () => {
  it('should login with valid credentials', () => {
    // test code
  });

  it('should reject invalid credentials', () => {
    // test code
  });
});

Test Modifiers

test.skip(name, fn) / it.skip(name, fn)

Skip a test (won't be executed).

test.skip('broken test', () => {
  // This test will be skipped
});

test.only(name, fn) / it.only(name, fn)

Run only this test (useful for debugging).

test.only('debug this test', () => {
  // Only this test will run
});

test.todo(name) / it.todo(name)

Mark a test as pending/TODO.

test.todo('implement this feature');

describe.skip(name, fn) / describe.only(name, fn)

Skip or isolate an entire test suite.

describe.skip('integration tests', () => {
  // All tests in this suite will be skipped
});

describe.only('unit tests', () => {
  // Only tests in this suite will run
});

Test Configuration

setDefaultTimeout(timeout)

Set the default timeout for all tests in milliseconds. This is useful when tests need more time to complete (e.g., integration tests, API calls).

Parameters:

  • timeout (number): Timeout in milliseconds

Example:

import { test, setDefaultTimeout } from 'test-anywhere';

// Set default timeout to 60 seconds
setDefaultTimeout(60000);

test('long running operation', async () => {
  // This test can take up to 60 seconds
  await someSlowOperation();
});

Note:

  • For Bun: Uses the native setDefaultTimeout from bun:test
  • For Node.js and Deno: Not supported natively. A warning will be logged, and you should use timeout options in individual test calls instead.

Assertions

assert.ok(value, message?)

Asserts that a value is truthy.

Example:

assert.ok(true);
assert.ok(1 === 1, 'one should equal one');

assert.equal(actual, expected, message?)

Asserts that two values are strictly equal (===).

Example:

assert.equal(2 + 2, 4);
assert.equal('hello', 'hello');

assert.deepEqual(actual, expected, message?)

Asserts that two values are deeply equal (compares object/array contents).

Example:

assert.deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 });
assert.deepEqual([1, 2, 3], [1, 2, 3]);

assert.throws(fn, message?)

Asserts that a function throws an error when called.

Example:

assert.throws(() => {
  throw new Error('oops');
});

Multiple Assertion Styles

test-anywhere supports three assertion styles to provide maximum compatibility and ease of migration:

1. Node.js/Classic Style (assert.*)

Traditional Node.js-style assertions (see above sections for details):

import { assert } from 'test-anywhere';

assert.ok(true);
assert.equal(1, 1);
assert.deepEqual([1, 2], [1, 2]);
assert.notEqual(1, 2);
assert.throws(() => {
  throw new Error();
});
assert.match('hello', /ell/);
assert.includes([1, 2, 3], 2);

2. Bun/Jest Style (expect())

Modern chainable API inspired by Jest and Bun:

import { expect } from 'test-anywhere';

expect(value).toBe(expected); // Strict equality (===)
expect(value).toEqual(expected); // Deep equality
expect(value).not.toBe(expected); // Negation
expect(value).toBeNull(); // null check
expect(value).toBeUndefined(); // undefined check
expect(value).toBeTruthy(); // Truthy check
expect(value).toBeFalsy(); // Falsy check
expect(array).toContain(item); // Array/string contains
expect(string).toMatch(/pattern/); // Regex match
expect(fn).toThrow(); // Function throws

Complete Example:

import { describe, it, expect } from 'test-anywhere';

describe('Calculator', () => {
  it('should add numbers', () => {
    expect(2 + 2).toBe(4);
    expect(2 + 2).toEqual(4);
  });

  it('should handle arrays', () => {
    expect([1, 2, 3]).toContain(2);
    expect([1, 2, 3]).toEqual([1, 2, 3]);
  });

  it('should validate strings', () => {
    expect('hello world').toMatch(/world/);
    expect('hello').not.toBe('goodbye');
  });
});

3. Deno Style (assertEquals, etc.)

Deno-inspired assertion functions from @std/assert:

import {
  assertEquals,
  assertNotEquals,
  assertStrictEquals,
  assertExists,
  assertMatch,
  assertArrayIncludes,
  assertThrows,
  assertRejects,
} from 'test-anywhere';

assertEquals(actual, expected); // Deep equality
assertNotEquals(actual, expected); // Not equal
assertStrictEquals(actual, expected); // Strict equality (===)
assertNotStrictEquals(actual, expected); // Strict inequality (!==)
assertExists(value); // Not null/undefined
assertMatch(string, /pattern/); // Regex match
assertArrayIncludes(arr, [items]); // Array includes items
assertThrows(() => {
  throw new Error();
}); // Sync throws
await assertRejects(async () => {
  throw new Error();
}); // Async rejects

Complete Example:

import {
  test,
  assertEquals,
  assertMatch,
  assertArrayIncludes,
} from 'test-anywhere';

test('user validation', () => {
  const user = { name: 'Alice', email: '[email protected]' };

  assertEquals(user.name, 'Alice');
  assertMatch(user.email, /@/);
});

test('array operations', () => {
  const numbers = [1, 2, 3, 4, 5];

  assertArrayIncludes(numbers, [2, 4]);
  assertEquals(numbers.length, 5);
});

Mix and Match

All three styles can be used together in the same project:

import { describe, it, assert, expect, assertEquals } from 'test-anywhere';

describe('Multi-style assertions', () => {
  it('supports all styles', () => {
    const value = 42;

    // Node style
    assert.equal(value, 42);

    // Bun/Jest style
    expect(value).toBe(42);

    // Deno style
    assertEquals(value, 42);
  });
});

Lifecycle Hooks

Setup and teardown hooks for test initialization and cleanup.

beforeAll(fn) / before(fn)

Runs once before all tests. before() is a Mocha-style alias.

import { beforeAll, describe, it } from 'test-anywhere';

describe('database tests', () => {
  beforeAll(() => {
    // Connect to database once
  });

  it('should query data', () => {
    // test code
  });
});

beforeEach(fn)

Runs before each test.

beforeEach(() => {
  // Reset state before each test
});

afterEach(fn)

Runs after each test.

afterEach(() => {
  // Clean up after each test
});

afterAll(fn) / after(fn)

Runs once after all tests. after() is a Mocha-style alias.

afterAll(() => {
  // Disconnect from database
});

getRuntime()

Returns the current runtime name.

Returns: 'node', 'bun', or 'deno'

Example:

import { getRuntime } from 'test-anywhere';

console.log(`Running on ${getRuntime()}`); // e.g., "Running on node"

Examples

Check out the examples directory for complete working examples:

  • Node.js: examples/node-example.test.js
  • Deno: examples/deno-example.test.js
  • Bun: examples/bun-example.test.js

How It Works

test-anywhere automatically detects the JavaScript runtime (Bun, Deno, or Node.js) and delegates to the appropriate native testing framework:

  • Bun → Uses bun:test
  • Deno → Uses Deno.test
  • Node.js → Uses node:test

This means you get the full performance and features of each runtime's native testing implementation while maintaining a consistent API across all platforms.

Requirements

  • Node.js: 20.0.0 or higher (for native test runner support)
  • Deno: 1.x or higher (native Deno.test support)
  • Bun: Any recent version (native bun:test support)

License

Unlicense - Public Domain

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

A JavaScript testing framework that is build up on build in testing frameworks of Bun, Deno, Node

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •