test.mjs provides tools for JS tests and benchmarks. Similar to https://deno.land/std/testing, but runs in all environments: browsers, Deno, Node, and possibly more.
Important non-features:
- No CLI required.
- Doesn't require Node or Deno.
- Doesn't require TypeScript.
- No external dependencies.
- No slowness.
Features:
- Small. Native JS module. Can be imported by URL.
- Runs in all environments: browsers, Deno, Node, possibly more.
- Assertion shortcuts such as
is
,eq
,ok
, and more. - Filter tests by name.
- Filter benchmarks by name.
- Multiple benchmarking strategies.
TimeRunner
: by total runtime in ms.CountRunner
: by run count.- Pluggable: bring your own runner.
- Multiple reporting strategies.
- Can report start, end, timing, number of runs, in any combination.
- Pluggable: bring your own reporter.
- Test and benchmark functions must be named.
- Functions are registered and filtered by their name, not by an arbitrary string. This forces them to be indexable and searchable in editors.
- Benchmarks support warmup for stable results.
- Benchmark precision is tuned to 1/10th of a nanosecond.
- Tested in Deno with
--allow-hrtime
.
- Tested in Deno with
- Supports async tests.
- Non-verbose. Tests are silent by default.
Ported from https://github.com/mitranim/test which is also available separately.
- Undocumented, or rather documented only through comments. Read the source. Docs are planned but not written yet.
- Benchmarks are only synchronous. Async support is planned but not implemented.
- Tests can be sync or async.
- Almost no support for additional messages accompanying failed tests.
- No support for timeouts. A hanged test stays hanged.
Deno requires --allow-hrtime
for better benchmark precision and --unstable
for measuring terminal width.
Performance is variable due to factors such as JIT tiers, CPU boost, inline caching, and possibly more. Code affects other code. Order is significant. Benchmarks affect each other. Consider calling deopt
before benches
.
Timing precision varies by JS engine and environment.
Simple testing example:
import * as t from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/test.mjs'
t.test(function test_some_feature() {
t.eq(someFunction(someInputs), `expected result`)
})
Simple benchmarking example:
import * as t from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/test.mjs'
t.bench(function bench_some_feature() {
someFunction(someInputs)
})
t.deopt()
t.benches()
Complex example:
import * as t from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/test.mjs'
// Optional CLI flag parsing.
const cli = t.Args.os()
// Optional filtering.
t.conf.setTestFilter(cli.get(`test`))
t.conf.setBenchFilter(cli.get(`bench`))
// Optional bench adjustment. Can be overridden per-function.
t.conf.benchRunner = new t.TimeRunner(1024)
// Filterable tests with assertion shortcuts.
t.test(function test_some_feature() {
t.eq(someFunction(someInputs), `expected result`)
})
// Easy and precise benchmarks.
t.bench(function bench_some_feature() {
someFunction(someInputs)
})
t.deopt()
t.benches()
The following APIs are exported but undocumented. Check test.mjs.
class AssertError
class InternalError
class Run
class FinRunner
class CountRunner
class TimeRunner
class DeoptRunner
class StringReporter
class ConsoleReporter
class ConsoleStartReporter
class ConsoleAvgReporter
class ConsoleStartEndAvgReporter
class ConsoleRunsReporter
class ConsoleBenchReporter
function tsMilli
function tsMicro
function tsNano
function tsPico
const conf
function test
function bench
class Bench
function deopt
function benches
function ok
function no
function is
function isnt
function eq
function notEq
function own
function inst
function optInst
function throws
function throwsCaught
function throwsGotErr
function throwsReturned
function throwsFunMsg
function throwsErrMsg
function equal
class Eq
function now
function nowAvg
function isRunner
function isReporter