tst

Tests without efforts

MIT 83 个版本
安装
npm install tst
yarn add tst
pnpm add tst
bun add tst
README

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 mode (disables auto-run, keeps tests for re-run):

import test from 'tst.js'
test.manual = true

// register tests...
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
  parallel: true     // run tests concurrently (true = auto, or number for limit)
})

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)
TST_MANUAL=1 node test.js     # disable auto-run
TST_PARALLEL=1 node test.js   # run tests concurrently
TST_PARALLEL=4 node test.js   # concurrency limit of 4

Or URL params (browser):

test.html?grep=pattern
test.html?bail
test.html?mute
test.html?format=tap
test.html?manual
test.html?parallel
test.html?parallel=4

[!NOTE] Tests run sequentially. For parallelism, run separate test files.

why?

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.

版本列表
9.4.0 2026-03-21
9.3.0 2026-03-19
9.2.2 2026-01-31
9.2.1 2026-01-22
9.2.0 2026-01-15
9.1.3 2026-01-15
9.1.2 2026-01-15
9.1.1 2026-01-15
9.1.0 2026-01-15
9.0.0 2026-01-09
8.0.2 2025-02-01
8.0.1 2025-02-01
8.0.0 2025-01-28
7.3.0 2024-08-12
7.2.0 2024-07-07
7.1.1 2022-02-01
7.1.0 2022-01-14
7.0.0 2021-08-14
6.1.1 2020-05-29
6.1.0 2020-05-27
6.0.2 2020-04-26
6.0.1 2020-04-24
6.0.0 2020-04-23
5.3.3 2020-02-03
5.3.2 2020-02-03
5.3.1 2020-02-01
5.3.0 2020-02-01
5.2.1 2020-01-27
5.2.0 2020-01-27
5.1.1 2020-01-20
5.1.0 2020-01-04
5.0.11 2019-12-23
5.0.10 2019-12-23
5.0.9 2019-12-23
5.0.8 2019-12-23
5.0.7 2019-12-22
5.0.6 2019-12-22
5.0.5 2019-12-22
5.0.4 2019-12-22
5.0.3 2019-12-21
5.0.2 2019-12-21
5.0.1 2019-12-21
5.0.0 2019-12-21
4.2.3 2019-12-20
4.2.1 2019-12-19
4.2.0 2019-12-19
4.1.0 2019-12-19
4.0.0 2019-12-18
3.4.2 2019-12-04
3.4.1 2019-08-29
3.4.0 2019-08-07
3.3.0 2019-08-07
3.2.0 2019-07-27
3.1.0 2019-07-25
3.0.1 2019-07-22
3.0.0 2019-07-22
2.1.0 2019-07-01
2.0.2 2019-06-30
2.0.0 2019-06-30
1.3.2 2017-02-01
1.3.1 2016-03-01
1.3.0 2016-02-29
1.2.4 2016-02-20
1.2.3 2016-02-20
1.2.2 2016-02-16
1.2.1 2016-02-09
1.2.0 2016-02-09
1.1.8 2016-01-23
1.1.7 2016-01-05
1.1.6 2016-01-05
1.1.5 2016-01-05
1.1.4 2016-01-05
1.1.3 2016-01-05
1.1.2 2016-01-05
1.1.1 2016-01-05
1.1.0 2016-01-05
1.0.6 2016-01-04
1.0.5 2016-01-04
1.0.4 2016-01-04
1.0.3 2016-01-04
1.0.2 2016-01-04
1.0.1 2016-01-04
1.0.0 2016-01-04