Skip to content

dy/tst

Repository files navigation

tst test npm package minimized gzipped size npm demo

Test without efforts.

  • vanilla ESM — no build, no tooling
  • node + browser
  • standalone assertions
  • async, timeouts, TAP
  • 0 deps, ~400 LOC

usage

import test from 'tst.js'

test('math', ({ ok, is }) => {
  ok(true)
  is(1 + 1, 2)
  is({a: 1}, {a: 1})  // deep equality
})

test('async', async ({ ok }) => {
  await fetch('/api')
  ok(true)
})

assertions

Function Description
ok(a, msg?) Assert truthy
is(a, b, msg?) Assert equal (Object.is for primitives, deep equal for objects)
not(a, b, msg?) Assert not equal
any(a, [x,y,z], msg?) Assert value is one of options
same(a, b, msg?) Assert same members (order-independent)
throws(fn, match?, msg?) Assert fn throws (optionally matching regex/class)
rejects(fn, match?, msg?) Assert async fn rejects (optionally matching regex/class)
almost(a, b, eps?, msg?) Assert approximate equality
pass(msg) / fail(msg) Explicit pass/fail

Note

Standalone use: import { ok, is, not, any, same, throws, rejects, almost, pass, fail } from 'tst/assert.js'

modifiers

test.skip('ignored', t => {})      // skip test
test.todo('future feature')        // mark as todo
test.only('focus', t => {})        // run only this
test.mute('quiet', t => {})        // hide assertions, show summary
test.demo('example', t => {})      // run but don't fail exit code
test.fork('isolate', t => {})      // run in worker thread (fresh V8 context)

// Combine via options
test('both', { fork: true, only: true }, t => {})

Note

Fork has no scope access — use data for values, await import() for modules.

Tip

Use .fork for tests with potential infinite loops — timeout can only terminate forked workers, not main thread.

options

test('name', {
  timeout: 3000,           // override default 5000ms
  data: { x: 1 },          // pass to callback as 2nd arg
  retry: 3,                // retry up to n times (flaky tests)

  // modifiers
  only: process.env.DEBUG, // run only this test when debugging
  skip: isCI,              // conditionally skip
  todo: !featureComplete,  // mark as todo until feature is ready
  mute: isCI,              // hide assertions in CI, show summary
  demo: true,              // run but don't fail exit code (for examples)
  fork: bench              // run in worker thread (fresh V8 context)
}, (t, data) => {})

config

Manual run (disables auto-run):

import test from 'tst.js'
await test.run({
  grep: /api/,       // filter by name
  bail: true,        // stop on first failure
  mute: true,        // hide passing tests
  timeout: 10000,    // fail if takes >10s
  format: 'tap'      // pretty (default), tap or custom object
})

Or env vars:

TST_GREP=pattern node test.js  # filter by name
TST_BAIL=1 node test.js        # stop on first failure
TST_MUTE=1 node test.js        # hide passing tests
TST_FORMAT=tap node test.js    # TAP output (pipeable)

Or URL params (browser):

test.html?grep=pattern
test.html?bail
test.html?mute
test.html?format=tap

Note

Tests run sequentially. For parallelism, run separate test files.

why?

You want to test add(1, 2) === 3.
Jest wants jest.config.js, babel.config.js, 200MB node_modules, transformation pipelines, mock systems.
Testing should be: write test, run file, see result. No setup, no maintenance, no build step.
Spiritual successor to tape — browser + node, ESM-native, async-native.

About

Tests without efforts

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors