@exodus/test 1.0.0-rc.109 → 1.0.0-rc.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -52
- package/bin/index.js +32 -14
- package/loader/deno-import-map.json +0 -1
- package/loader/deno-import-map.pure.json +9 -0
- package/loader/node-test.js +2 -0
- package/loader/remap.cjs +26 -0
- package/loader/remap.loader.js +9 -0
- package/package.json +47 -14
- package/src/benchmark.d.ts +40 -0
- package/src/engine.pure.cjs +2 -1
- package/src/expect.d.ts +29 -0
- package/src/index.d.ts +12 -0
- package/src/index.js +11 -0
- package/src/jest.d.ts +28 -0
- package/src/jest.environment.js +2 -1
- package/src/mock.d.ts +54 -0
- package/src/node.d.ts +21 -0
- package/src/node.js +1 -1
- package/src/tape.cjs +1 -0
- package/src/tape.d.ts +166 -0
- package/src/tape.js +1 -0
- package/tape.js +1 -0
- package/CHANGELOG.md +0 -3
package/README.md
CHANGED
|
@@ -1,21 +1,53 @@
|
|
|
1
1
|
# @exodus/test
|
|
2
2
|
|
|
3
|
+
[](https://npmjs.org/package/@exodus/test)
|
|
4
|
+
[](https://github.com/ExodusOSS/test/releases)
|
|
5
|
+
[](https://github.com/ExodusOSS/test/blob/HEAD/LICENSE)
|
|
6
|
+
[](https://github.com/ExodusOSS/test/actions/workflows/checks.yml?query=branch%3Amain)
|
|
7
|
+
[](https://github.com/ExodusOSS/test/stargazers)
|
|
8
|
+
|
|
3
9
|
A runner for `node:test`, `jest`, and `tape` test suites on top of `node:test` (and any runtime).
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
It can run your existing tests on [all runtimes and also browsers](#engines), with snapshots and module mocks:
|
|
14
|
+
|
|
15
|
+
[](https://nodejs.org/api/test.html)
|
|
16
|
+
[](https://deno.com/)
|
|
17
|
+
[](https://bun.sh/)
|
|
18
|
+
[](http://electronjs.org/)\
|
|
19
|
+
[](https://www.chromium.org/Home/)
|
|
20
|
+
[](http://webkit.org/)
|
|
21
|
+
[](https://github.com/mozilla-firefox)
|
|
22
|
+
[](https://github.com/brave)
|
|
23
|
+
[](https://github.com/microsoftedge)
|
|
24
|
+
[](https://servo.org/)\
|
|
25
|
+
[](https://hermesengine.dev)
|
|
26
|
+
[](https://v8.dev/docs/d8)
|
|
27
|
+
[](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html)
|
|
28
|
+
[](https://spidermonkey.dev/)
|
|
29
|
+
[](https://github.com/quickjs-ng/quickjs)
|
|
30
|
+
[](https://github.com/Moddable-OpenSource/moddable-xst)
|
|
31
|
+
[](https://github.com/oracle/graaljs)
|
|
32
|
+
[](https://github.com/boa-dev/boa)
|
|
33
|
+
[](https://github.com/Samsung/escargot)
|
|
34
|
+
[](https://github.com/engine262/engine262)
|
|
35
|
+
|
|
36
|
+
Compatible with tests written in:
|
|
37
|
+
|
|
38
|
+
[](#using-with-nodetest-tests)
|
|
39
|
+
[](#migrating-from-jest)
|
|
40
|
+
[](#migrating-from-tape)
|
|
41
|
+
|
|
42
|
+
See [documentation](https://exodusoss.github.io/test/).
|
|
6
43
|
|
|
7
44
|
## Features
|
|
8
45
|
|
|
9
46
|
- Native ESM, including in Jest tests
|
|
10
|
-
- Esbuild on the fly for
|
|
11
|
-
- TypeScript support
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
[v8 CLI](https://v8.dev/docs/d8), JSC, [Hermes](https://hermesengine.dev), [SpiderMonkey](https://spidermonkey.dev/),
|
|
15
|
-
Chrome, Firefox, WebKit, Brave, Microsoft Edge, [Servo](https://servo.org/),
|
|
16
|
-
[QuickJS](https://github.com/quickjs-ng/quickjs), [XS](https://github.com/Moddable-OpenSource/moddable-xst),
|
|
17
|
-
[GraalJS](https://github.com/oracle/graaljs), [Escargot](https://github.com/Samsung/escargot),
|
|
18
|
-
[Boa](https://github.com/boa-dev/boa), and even [engine262](https://github.com/engine262/engine262).
|
|
47
|
+
- Esbuild on the fly for old faux-ESM interop (enable via `--esbuild`)
|
|
48
|
+
- TypeScript support
|
|
49
|
+
- Runs anywhere (including Hermes, the [React Native](https://reactnative.dev/) JavaScript engine)
|
|
50
|
+
- Use snapshots to cross-compare between runtimes, browsers and barebones (including Hermes)
|
|
19
51
|
- Testsuite-agnostic — can run any file as long as it sets exit code based on test results
|
|
20
52
|
- Built-in [Jest](https://jestjs.io) compatibility (with `--jest`), including `jest.*` global
|
|
21
53
|
- Up to ~10x faster depending on the original setup
|
|
@@ -35,7 +67,73 @@ It can run your existing tests on [all runtimes and also browsers](#engines), wi
|
|
|
35
67
|
- Unlike `bun:test`, it runs test files in isolated contexts \
|
|
36
68
|
Bun leaks globals / side effects between test files ([ref](https://github.com/oven-sh/bun/issues/6024)),
|
|
37
69
|
and has incompatible `test()` lifecycle / order
|
|
38
|
-
|
|
70
|
+
|
|
71
|
+
## Getting started
|
|
72
|
+
|
|
73
|
+
First install with `npm install --save-dev @exodus/test` (or with your favorite package manager)
|
|
74
|
+
|
|
75
|
+
Then, add this to `package.json` scripts (or see [engines example](https://github.com/ExodusOSS/bytes/blob/v1.11.0/package.json#L25-L42)):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
"test": "exodus-test"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
That's it. It works zero-config.
|
|
82
|
+
|
|
83
|
+
See [Options](#options) to change defaults, e.g. to enable Jest globals with `--jest`.
|
|
84
|
+
|
|
85
|
+
To use [Engines](#engines) on CI, see e.g. GitHub CI config of [@exodus/bytes](https://github.com/ExodusOSS/bytes/blob/main/.github/workflows/test.yml).
|
|
86
|
+
|
|
87
|
+
### Using with node:test tests
|
|
88
|
+
|
|
89
|
+
You don't need to change the tests or any extra configuration on top of [Getting started](#getting-started).
|
|
90
|
+
|
|
91
|
+
It just works out of the box, and on Node.js native `node:test` is used under the hood.
|
|
92
|
+
|
|
93
|
+
Using this script is similar to `node --test`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
"test": "exodus-test"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
But, unlike bare `node --test` it supports [engines](#engines) and the [GitHub CI reporter](#github-actions).
|
|
100
|
+
|
|
101
|
+
### Migrating from Jest
|
|
102
|
+
|
|
103
|
+
Use this in `package.json` scripts:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
"test": "exodus-test --jest"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If that doesn't work (e.g. some deps are faux-ESM), add `--esbuild` to transpile those:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
"test": "exodus-test --jest --esbuild"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
To adjust module mocks for native ESM support, see [Module mocking in ESM](#module-mocking-in-esm).
|
|
116
|
+
|
|
117
|
+
Some complex setups with React Native don't work yet.
|
|
118
|
+
|
|
119
|
+
### Migrating from tape
|
|
120
|
+
|
|
121
|
+
Use this in `package.json` scripts:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
"test": "exodus-test"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Great! Now your tape tests run on top of `node:test`, and are also runnable in browsers / barebone [engines](#engines).
|
|
128
|
+
|
|
129
|
+
> [!TIP]
|
|
130
|
+
> You can optionally replace `tape` imports with `@exodus/test/tape`
|
|
131
|
+
> to be able to be individually run them with just `node ./path-to-file.js`:
|
|
132
|
+
>
|
|
133
|
+
> ```js
|
|
134
|
+
> import test from '@exodus/test/tape' // ESM
|
|
135
|
+
> const test = require('@exodus/test/tape') // CJS
|
|
136
|
+
> ```
|
|
39
137
|
|
|
40
138
|
## Engines
|
|
41
139
|
|
|
@@ -67,7 +165,7 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
67
165
|
- `brave:puppeteer` — Brave
|
|
68
166
|
- `msedge:puppeteer` — Microsoft Edge
|
|
69
167
|
- Bundle
|
|
70
|
-
- `servo:bundle` — Servo (expects it to be installed in the system
|
|
168
|
+
- `servo:bundle` — Servo (expects it to be installed in the system)
|
|
71
169
|
- Barebone engines (system-provided or installed with `npx jsvu` / `npx esvu`):
|
|
72
170
|
- `v8:bundle` — [v8 CLI](https://v8.dev/docs/d8) (Chrome/Blink/Node.js JavaScript engine)
|
|
73
171
|
- `jsc:bundle` — [JavaScriptCore](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html) (Safari/WebKit JavaScript engine)
|
|
@@ -81,9 +179,39 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
81
179
|
- `engine262:bundle` - [engine262](https://github.com/engine262/engine262), the per-spec implementation of ECMA-262
|
|
82
180
|
(install with [esvu](https://npmjs.com/package/esvu))
|
|
83
181
|
|
|
182
|
+
## Options
|
|
183
|
+
|
|
184
|
+
- `--jest` — register jest test helpers as global variables, also load `jest.config.*` configuration options
|
|
185
|
+
|
|
186
|
+
- `--esbuild` — use esbuild loader, also enables Typescript support on old Node.js
|
|
187
|
+
|
|
188
|
+
- `--typescript` — enable Typescript type stripping (only needed on older Node.js versions which don't have it natively)
|
|
189
|
+
|
|
190
|
+
- `--babel` — use babel loader (slower than `--esbuild`, makes sense if you have a special config)
|
|
191
|
+
|
|
192
|
+
- `--coverage` — enable coverage, prints coverage output (varies by coverage engine)
|
|
193
|
+
|
|
194
|
+
- `--coverage-engine c8` — use c8 coverage engine (default), also generates `./coverage/` dirs
|
|
195
|
+
|
|
196
|
+
- `--coverage-engine node` — use Node.js builtint coverage engine
|
|
197
|
+
|
|
198
|
+
- `--watch` — operate in watch mode and re-run tests on file changes
|
|
199
|
+
|
|
200
|
+
- `--only` — only run the tests marked with `test.only`
|
|
201
|
+
|
|
202
|
+
- `--passWithNoTests` — do not error when no test files were found
|
|
203
|
+
|
|
204
|
+
- `--write-snapshots` — write snapshots instead of verifying them (has `--test-update-snapshots` alias)
|
|
205
|
+
|
|
206
|
+
- `--test-force-exit` — force exit after tests are done
|
|
207
|
+
|
|
208
|
+
- `--engine` — specify one of [Engines](#engines) to run on
|
|
209
|
+
|
|
84
210
|
## Reporter samples
|
|
85
211
|
|
|
86
|
-
|
|
212
|
+
### CLI
|
|
213
|
+
|
|
214
|
+
Uses colors when output supports them, e.g. in terminal.
|
|
87
215
|
|
|
88
216
|
```console
|
|
89
217
|
# tests/jest/expect.mock.test.js
|
|
@@ -100,7 +228,9 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
100
228
|
✔ PASS mock.invocationCallOrder (4.221042ms)
|
|
101
229
|
```
|
|
102
230
|
|
|
103
|
-
|
|
231
|
+
### GitHub Actions
|
|
232
|
+
|
|
233
|
+
Collapses test results per-file, like this:
|
|
104
234
|
|
|
105
235
|
<details>
|
|
106
236
|
<summary>✅ <strong>tests/jest/lifecycle.test.js</strong></summary>
|
|
@@ -132,44 +262,6 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
132
262
|
|
|
133
263
|
See live output in [CI](https://github.com/ExodusOSS/test/actions/workflows/checks.yaml)
|
|
134
264
|
|
|
135
|
-
## Library
|
|
136
|
-
|
|
137
|
-
### List of exports
|
|
138
|
-
|
|
139
|
-
- `@exodus/test/node` — `node:test` API, working under non-Node.js platforms
|
|
140
|
-
|
|
141
|
-
- `@exodus/test/jest` — `jest` implementation
|
|
142
|
-
|
|
143
|
-
- `@exodus/test/tape` — `tape` mock (can also be helpful when moving from `tap`)
|
|
144
|
-
|
|
145
|
-
## Binary
|
|
146
|
-
|
|
147
|
-
Just use `"test": "exodus-test"`
|
|
148
|
-
|
|
149
|
-
### Options
|
|
150
|
-
|
|
151
|
-
- `--jest` — register jest test helpers as global variables, also load `jest.config.*` configuration options
|
|
152
|
-
|
|
153
|
-
- `--esbuild` — use esbuild loader, also enables Typescript support
|
|
154
|
-
|
|
155
|
-
- `--babel` — use babel loader (slower than `--esbuild`, makes sense if you have a special config)
|
|
156
|
-
|
|
157
|
-
- `--coverage` — enable coverage, prints coverage output (varies by coverage engine)
|
|
158
|
-
|
|
159
|
-
- `--coverage-engine c8` — use c8 coverage engine (default), also generates `./coverage/` dirs
|
|
160
|
-
|
|
161
|
-
- `--coverage-engine node` — use Node.js builtint coverage engine
|
|
162
|
-
|
|
163
|
-
- `--watch` — operate in watch mode and re-run tests on file changes
|
|
164
|
-
|
|
165
|
-
- `--only` — only run the tests marked with `test.only`
|
|
166
|
-
|
|
167
|
-
- `--passWithNoTests` — do not error when no test files were found
|
|
168
|
-
|
|
169
|
-
- `--write-snapshots` — write snapshots instead of verifying them (has `--test-update-snapshots` alias)
|
|
170
|
-
|
|
171
|
-
- `--test-force-exit` — force exit after tests are done
|
|
172
|
-
|
|
173
265
|
## Module mocking in ESM
|
|
174
266
|
|
|
175
267
|
Module mocks in ESM is a common source of confusion, as Jest in most old setups does not run real ESM,
|
package/bin/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { glob as globImplementation } from '../src/glob.cjs'
|
|
|
19
19
|
const DEFAULT_PATTERNS = [`**/?(*.)+(spec|test).?([cm])[jt]s?(x)`] // do not trust magic dirs by default
|
|
20
20
|
const bundleOpts = { pure: true, bundle: true, esbuild: true, ts: 'auto' }
|
|
21
21
|
const bareboneOpts = { ...bundleOpts, barebone: true }
|
|
22
|
-
const hermesA = ['-w', '-Xmicrotask-queue'] // -Xes6-class fails with -O0 / -Og, --block-scoping fails in default, any of that is bad
|
|
22
|
+
const hermesA = ['-w', '-Xmicrotask-queue', '-eager'] // -Xes6-class fails with -O0 / -Og, --block-scoping fails in default, any of that is bad
|
|
23
23
|
const hermesS = [...hermesA, '-Xes6-block-scoping']
|
|
24
24
|
const denoA = ['run', '--allow-all'] // also will set DENO_COMPAT=1 env flag below
|
|
25
25
|
const denoT = ['test', '--allow-all']
|
|
@@ -45,6 +45,7 @@ const ENGINES = new Map(
|
|
|
45
45
|
'hermes:bundle': { binary: 'hermes', binaryArgs: hermesA, target: 'es2018', ...bareboneOpts },
|
|
46
46
|
'shermes:bundle': { binary: 'shermes', binaryArgs: hermesS, target: 'es2018', ...bareboneOpts },
|
|
47
47
|
'spidermonkey:bundle': { binary: 'spidermonkey', ...bareboneOpts },
|
|
48
|
+
'ladybird-js:bundle': { binary: 'ladybird-js', binaryArgs: ['-i'], ...bareboneOpts },
|
|
48
49
|
'engine262:bundle': { binary: 'engine262', ...bareboneOpts },
|
|
49
50
|
'quickjs:bundle': { binary: 'quickjs', binaryArgs: ['--std'], ...bareboneOpts },
|
|
50
51
|
'xs:bundle': { binary: 'xs', ...bareboneOpts },
|
|
@@ -66,8 +67,9 @@ const ENGINES = new Map(
|
|
|
66
67
|
'msedge:playwright': { binary: 'msedge', browsers: 'playwright', ...bundleOpts },
|
|
67
68
|
})
|
|
68
69
|
)
|
|
69
|
-
const
|
|
70
|
-
const
|
|
70
|
+
const bareOk = ['v8', 'd8', 'spidermonkey', 'quickjs', 'xs', 'hermes', 'shermes']
|
|
71
|
+
const bareUnhandled = ['jsc', 'escargot', 'boa', 'graaljs', 'jerry', 'engine262', 'servo']
|
|
72
|
+
const bareIncomplete = ['ladybird-js']
|
|
71
73
|
|
|
72
74
|
const getEnvFlag = (name) => {
|
|
73
75
|
if (!Object.hasOwn(process.env, name)) return
|
|
@@ -353,10 +355,13 @@ if (process.env.EXODUS_TEST_IGNORE) {
|
|
|
353
355
|
|
|
354
356
|
// This might be used in presets, so has to be loaded before jest
|
|
355
357
|
if (options.flow && !options.bundle) args.push('--import', import.meta.resolve('../loader/flow.js'))
|
|
356
|
-
if (['node:test', 'electron-as-node:test', 'deno:test'].includes(options.engine)) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
if (['node:test', 'electron-as-node:test', 'deno:test', 'deno:pure'].includes(options.engine)) {
|
|
359
|
+
args.push('--import', import.meta.resolve('../loader/remap.cjs'))
|
|
360
|
+
if (options.engine === 'deno:test') {
|
|
361
|
+
args.push('--import-map', import.meta.resolve('../loader/deno-import-map.json'))
|
|
362
|
+
} else if (options.engine === 'deno:pure') {
|
|
363
|
+
args.push('--import-map', import.meta.resolve('../loader/deno-import-map.pure.json'))
|
|
364
|
+
}
|
|
360
365
|
} else if (!options.bundle) {
|
|
361
366
|
args.push(options.loader ?? '-r', import.meta.resolve('../loader/node-test.js'))
|
|
362
367
|
}
|
|
@@ -489,7 +494,7 @@ async function glob(patterns, { ignore, cwd }) {
|
|
|
489
494
|
|
|
490
495
|
if (patterns.length === 0) patterns.push(...DEFAULT_PATTERNS) // defaults
|
|
491
496
|
const globbed = await glob(patterns, { ignore })
|
|
492
|
-
const allfiles = filter ? globbed.filter(filter) : globbed
|
|
497
|
+
const allfiles = (filter ? globbed.filter(filter) : globbed).sort()
|
|
493
498
|
|
|
494
499
|
if (allfiles.length === 0) {
|
|
495
500
|
if (options.passWithNoTests) {
|
|
@@ -653,7 +658,7 @@ async function launch(binary, args, opts = {}, buffering = false) {
|
|
|
653
658
|
return browsers.run(runner, args, { binary, devtools, dropNetwork, timeout, throttle })
|
|
654
659
|
}
|
|
655
660
|
|
|
656
|
-
const barebones = [...
|
|
661
|
+
const barebones = [...bareOk, ...bareUnhandled, ...bareIncomplete]
|
|
657
662
|
assertBinary(binary, ['node', 'bun', 'deno', 'electron', 'workerd', ...barebones])
|
|
658
663
|
if (binary === c8 && process.platform === 'win32') {
|
|
659
664
|
;[binary, args] = ['node', [binary, ...args]]
|
|
@@ -684,9 +689,10 @@ if (options.pure) {
|
|
|
684
689
|
}
|
|
685
690
|
|
|
686
691
|
setEnv('EXODUS_TEST_CONTEXT', 'pure')
|
|
687
|
-
|
|
688
|
-
const
|
|
692
|
+
const missUnhandled = bareUnhandled.includes(options.platform) || isBrowserLike
|
|
693
|
+
const isIncomplete = bareIncomplete.includes(options.platform)
|
|
689
694
|
if (missUnhandled) warnHuman(`Warning: ${engineName} does not have unhandled rejections tracking`)
|
|
695
|
+
if (isIncomplete) warnHuman(`Warning: ${engineName} support is incomplete`)
|
|
690
696
|
|
|
691
697
|
const runOne = async (inputFile) => {
|
|
692
698
|
const bundled = buildFile ? await buildFile(inputFile) : undefined
|
|
@@ -700,7 +706,19 @@ if (options.pure) {
|
|
|
700
706
|
|
|
701
707
|
const file = buildFile ? bundled.fileHtml ?? bundled.file : inputFile
|
|
702
708
|
const failedBare = 'EXODUS_TEST_FAILED_EXIT_CODE_1'
|
|
703
|
-
const cleanOut = (out) =>
|
|
709
|
+
const cleanOut = (out, ok) => {
|
|
710
|
+
if (options.engine === 'ladybird-js:bundle') {
|
|
711
|
+
// It wrapps all prints/console.log in double quotes for strings, and escapes \b \n \v \f \r \, but does not wrap "
|
|
712
|
+
const unmap = { __proto__: null, b: '\b', n: '\n', v: '\v', f: '\f', r: '\r' }
|
|
713
|
+
const fix = (x) => x.slice(1, -1).replaceAll(/\\([bnvfr\\])/gu, (s) => unmap[s[1]] ?? s[1])
|
|
714
|
+
const lineMapper = (x) => (x.startsWith('"') && x.endsWith('"') ? fix(x) : x)
|
|
715
|
+
out = out.split('\n').map(lineMapper).join('\n')
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
out = out.replaceAll(`\n${failedBare}\n`, '\n').replaceAll(failedBare, '')
|
|
719
|
+
return out || (ok ? `✔ PASS ${file}` : `✖ FAIL ${file}`)
|
|
720
|
+
}
|
|
721
|
+
|
|
704
722
|
// Timeout is fallback if timeout in script hangs, 50x as it can be adjusted per-script inside them
|
|
705
723
|
// Do we want to extract timeouts from script code instead? Also, hermes might be slower, so makes sense to increase
|
|
706
724
|
const timeout = (options.testTimeout || jestConfig?.testTimeout || 5000) * 50
|
|
@@ -711,11 +729,11 @@ if (options.pure) {
|
|
|
711
729
|
const ms = Number(process.hrtime.bigint() - start) / 1e6
|
|
712
730
|
if (stdout.includes(failedBare)) return { ok: false, output: [cleanOut(stdout), stderr], ms }
|
|
713
731
|
const ok = code === 0 && !/^(✖ FAIL|‼ FATAL) /mu.test(stdout)
|
|
714
|
-
return { ok, output: [stdout, stderr], ms }
|
|
732
|
+
return { ok, output: [cleanOut(stdout, ok), stderr], ms }
|
|
715
733
|
} catch (err) {
|
|
716
734
|
const ms = Number(process.hrtime.bigint() - start) / 1e6
|
|
717
735
|
const { code, stderr = '', signal, killed } = err
|
|
718
|
-
const stdout = cleanOut(err.stdout || '')
|
|
736
|
+
const stdout = cleanOut(err.stdout || '', false)
|
|
719
737
|
if (code === null) {
|
|
720
738
|
assert(signal)
|
|
721
739
|
const message = ` ${signal}${killed ? ' (killed)' : ''}`
|
package/loader/node-test.js
CHANGED
|
@@ -12,3 +12,5 @@ Object.assign(testActual, test)
|
|
|
12
12
|
const nodeModule = require('node:module')
|
|
13
13
|
const syncBuiltinESMExports = nodeModule.syncBuiltinESMExports || nodeModule.syncBuiltinExports // old bun has it under a different name
|
|
14
14
|
if (syncBuiltinESMExports) syncBuiltinESMExports()
|
|
15
|
+
|
|
16
|
+
require('./remap.cjs')
|
package/loader/remap.cjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const nodeModule = require('node:module')
|
|
2
|
+
const { pathToFileURL } = require('node:url')
|
|
3
|
+
|
|
4
|
+
const remap = new Map(Object.entries(require('./deno-import-map.json').imports))
|
|
5
|
+
const resolveFile = (f) => require.resolve(f.endsWith('tape.js') ? `${f.slice(0, -2)}cjs` : f)
|
|
6
|
+
|
|
7
|
+
function resolve(specifier, context, nextResolve) {
|
|
8
|
+
if (!remap.has(specifier)) return nextResolve(specifier)
|
|
9
|
+
return { url: pathToFileURL(resolveFile(remap.get(specifier))).toString(), shortCircuit: true }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (nodeModule.registerHooks) {
|
|
13
|
+
nodeModule.registerHooks({ resolve })
|
|
14
|
+
} else if (globalThis.Bun) {
|
|
15
|
+
const { mock } = require('bun:test')
|
|
16
|
+
for (const [k, v] of remap) mock.module(k, () => (v.endsWith('jest.js') ? import(v) : require(v)))
|
|
17
|
+
} else {
|
|
18
|
+
if (nodeModule.register) nodeModule.register('./remap.loader.js', pathToFileURL(__filename))
|
|
19
|
+
if (nodeModule._resolveFilename) {
|
|
20
|
+
const { _resolveFilename } = nodeModule
|
|
21
|
+
nodeModule._resolveFilename = function (request, parent, isMain, options) {
|
|
22
|
+
if (remap.has(request)) return resolveFile(remap.get(request))
|
|
23
|
+
return _resolveFilename.call(this, request, parent, isMain, options)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// ESM version is the same as for Deno
|
|
2
|
+
import deno from './deno-import-map.json' with { type: 'json' }
|
|
3
|
+
|
|
4
|
+
const remap = new Map(Object.entries(deno.imports))
|
|
5
|
+
|
|
6
|
+
export function resolve(specifier, context, nextResolve) {
|
|
7
|
+
if (!remap.has(specifier)) return nextResolve(specifier)
|
|
8
|
+
return { url: new URL(remap.get(specifier), import.meta.url).toString(), shortCircuit: true }
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/test",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.110",
|
|
4
4
|
"author": "Exodus Movement, Inc.",
|
|
5
5
|
"description": "A test suite runner",
|
|
6
6
|
"homepage": "https://github.com/ExodusOSS/test",
|
|
@@ -19,21 +19,41 @@
|
|
|
19
19
|
],
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": "^20.
|
|
22
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
23
23
|
},
|
|
24
24
|
"type": "module",
|
|
25
25
|
"bin": {
|
|
26
26
|
"exodus-test": "bin/index.js"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./src/index.d.ts",
|
|
31
|
+
"default": "./src/index.js"
|
|
32
|
+
},
|
|
29
33
|
"./node-test-reporter": "./bin/reporter.js",
|
|
30
34
|
"./loader/jest": "./loader/jest.js",
|
|
31
|
-
"./benchmark":
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"./
|
|
35
|
+
"./benchmark": {
|
|
36
|
+
"types": "./src/benchmark.d.ts",
|
|
37
|
+
"default": "./src/benchmark.js"
|
|
38
|
+
},
|
|
39
|
+
"./expect": {
|
|
40
|
+
"types": "./src/expect.d.ts",
|
|
41
|
+
"default": "./src/expect.cjs"
|
|
42
|
+
},
|
|
43
|
+
"./jest": {
|
|
44
|
+
"types": "./src/jest.d.ts",
|
|
45
|
+
"default": "./src/jest.js"
|
|
46
|
+
},
|
|
47
|
+
"./mock": {
|
|
48
|
+
"types": "./src/mock.d.ts",
|
|
49
|
+
"default": "./src/mock.js"
|
|
50
|
+
},
|
|
51
|
+
"./node": {
|
|
52
|
+
"types": "./src/node.d.ts",
|
|
53
|
+
"default": "./src/node.js"
|
|
54
|
+
},
|
|
36
55
|
"./tape": {
|
|
56
|
+
"types": "./src/tape.d.ts",
|
|
37
57
|
"import": "./src/tape.js",
|
|
38
58
|
"require": "./src/tape.cjs"
|
|
39
59
|
}
|
|
@@ -49,14 +69,18 @@
|
|
|
49
69
|
"bin/reporter.js",
|
|
50
70
|
"loader/babel.cjs",
|
|
51
71
|
"loader/deno-import-map.json",
|
|
72
|
+
"loader/deno-import-map.pure.json",
|
|
52
73
|
"loader/esbuild.js",
|
|
53
74
|
"loader/esbuild.optional.js",
|
|
54
75
|
"loader/flow.js",
|
|
55
76
|
"loader/jest.js",
|
|
77
|
+
"loader/remap.cjs",
|
|
78
|
+
"loader/remap.loader.js",
|
|
56
79
|
"loader/node-test.js",
|
|
57
80
|
"loader/typescript.js",
|
|
58
81
|
"loader/typescript.loader.js",
|
|
59
82
|
"src/benchmark.js",
|
|
83
|
+
"src/benchmark.d.ts",
|
|
60
84
|
"src/dark.cjs",
|
|
61
85
|
"src/engine.js",
|
|
62
86
|
"src/engine.node.cjs",
|
|
@@ -65,8 +89,12 @@
|
|
|
65
89
|
"src/engine.select.cjs",
|
|
66
90
|
"src/exodus.js",
|
|
67
91
|
"src/expect.cjs",
|
|
92
|
+
"src/expect.d.ts",
|
|
68
93
|
"src/glob.cjs",
|
|
94
|
+
"src/index.js",
|
|
95
|
+
"src/index.d.ts",
|
|
69
96
|
"src/jest.js",
|
|
97
|
+
"src/jest.d.ts",
|
|
70
98
|
"src/jest.config.js",
|
|
71
99
|
"src/jest.config.fs.js",
|
|
72
100
|
"src/jest.environment.js",
|
|
@@ -76,10 +104,13 @@
|
|
|
76
104
|
"src/jest.snapshot.js",
|
|
77
105
|
"src/jest.timers.js",
|
|
78
106
|
"src/mock.js",
|
|
107
|
+
"src/mock.d.ts",
|
|
79
108
|
"src/node.js",
|
|
109
|
+
"src/node.d.ts",
|
|
80
110
|
"src/pretty-format.cjs",
|
|
81
111
|
"src/replay.js",
|
|
82
112
|
"src/tape.js",
|
|
113
|
+
"src/tape.d.ts",
|
|
83
114
|
"src/tape.cjs",
|
|
84
115
|
"src/timers-track.js",
|
|
85
116
|
"src/version.js",
|
|
@@ -88,8 +119,7 @@
|
|
|
88
119
|
"jest.js",
|
|
89
120
|
"mock.js",
|
|
90
121
|
"node.js",
|
|
91
|
-
"tape.js"
|
|
92
|
-
"CHANGELOG.md"
|
|
122
|
+
"tape.js"
|
|
93
123
|
],
|
|
94
124
|
"scripts": {
|
|
95
125
|
"test:_bundle": "EXODUS_TEST_IGNORE='tests/{{jest-extended,inband}/**,jest-when/when.test.*,jest/jest.resetModules.*,jest/mock/jest.mock.mocks-dir.test.js}' npm run test --",
|
|
@@ -124,6 +154,7 @@
|
|
|
124
154
|
"test:hermes": "EXODUS_TEST_ENGINE=hermes:bundle npm run test:_bundle --",
|
|
125
155
|
"test:shermes": "EXODUS_TEST_ENGINE=shermes:bundle npm run test:_bundle --",
|
|
126
156
|
"test:spidermonkey": "EXODUS_TEST_ENGINE=spidermonkey:bundle npm run test:_bundle --",
|
|
157
|
+
"test:ladybird-js": "EXODUS_TEST_ENGINE=ladybird-js:bundle npm run test:_bundle --",
|
|
127
158
|
"test:servo": "EXODUS_TEST_ENGINE=servo:bundle npm run test:_bundle --",
|
|
128
159
|
"test:engine262": "EXODUS_TEST_ENGINE=engine262:bundle npm run test:_bundle --",
|
|
129
160
|
"test:quickjs": "EXODUS_TEST_ENGINE=quickjs:bundle npm run test:_bundle --",
|
|
@@ -135,6 +166,7 @@
|
|
|
135
166
|
"test:fetch": "node ./bin/index.js --jest --drop-network --engine node:pure 'tests/replay/*.test.js'",
|
|
136
167
|
"test:jsdom": "EXODUS_TEST_JEST_CONFIG='{\"testMatch\":[\"**/*.jsdom-test.js\"],\"testEnvironment\":\"jsdom\", \"rootDir\": \".\"}' ./bin/index.js --jest",
|
|
137
168
|
"coverage": "node ./bin/index.js --jest --esbuild --coverage",
|
|
169
|
+
"typedoc": "typedoc && mkdir -p doc/assets && cp -r theme/styles doc/assets/",
|
|
138
170
|
"playwright": "node ./bin/index.js --playwright",
|
|
139
171
|
"esvu": "esvu",
|
|
140
172
|
"jsvu": "jsvu",
|
|
@@ -145,14 +177,14 @@
|
|
|
145
177
|
"optionalDependencies": {
|
|
146
178
|
"@chalker/queue": "^1.0.1",
|
|
147
179
|
"@exodus/replay": "^1.0.0-rc.9",
|
|
148
|
-
"@exodus/test-bundler": "1.0.0-rc.
|
|
180
|
+
"@exodus/test-bundler": "1.0.0-rc.11",
|
|
149
181
|
"c8": "^9.1.0",
|
|
150
182
|
"expect": "^30.2.0",
|
|
151
183
|
"fast-glob": "^3.2.11",
|
|
152
184
|
"playwright-core": "^1.52.0",
|
|
153
185
|
"pretty-format": "^30.2.0",
|
|
154
186
|
"puppeteer-core": "^24.14.0",
|
|
155
|
-
"tsx": "^4.
|
|
187
|
+
"tsx": "^4.21.0"
|
|
156
188
|
},
|
|
157
189
|
"devDependencies": {
|
|
158
190
|
"@exodus/eslint-config": "^5.24.0",
|
|
@@ -161,7 +193,7 @@
|
|
|
161
193
|
"@types/jest-when": "^3.5.2",
|
|
162
194
|
"@types/node": "^24.0.11",
|
|
163
195
|
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
|
164
|
-
"electron": "^
|
|
196
|
+
"electron": "^38.7.0",
|
|
165
197
|
"eslint": "^8.44.0",
|
|
166
198
|
"esvu": "^1.2.16",
|
|
167
199
|
"jest": "^29.7.0",
|
|
@@ -170,9 +202,10 @@
|
|
|
170
202
|
"jest-serializer-ansi-escapes": "^3.0.0",
|
|
171
203
|
"jest-when": "^3.6.0",
|
|
172
204
|
"jsdom": "^26.1.0",
|
|
173
|
-
"jsvu": "^3.0.
|
|
205
|
+
"jsvu": "^3.0.3",
|
|
174
206
|
"prettier": "^3.0.3",
|
|
175
|
-
"
|
|
207
|
+
"typedoc": "^0.28.16",
|
|
208
|
+
"workerd": "^1.20251217.0"
|
|
176
209
|
},
|
|
177
210
|
"peerDependencies": {
|
|
178
211
|
"@babel/register": "^7.0.0",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Benchmark utilities for performance testing
|
|
3
|
+
*
|
|
4
|
+
* ```js
|
|
5
|
+
* import { benchmark } from '@exodus/test/benchmark'
|
|
6
|
+
* ```
|
|
7
|
+
*
|
|
8
|
+
* Can be used with or without `@exodus/test` test runner.
|
|
9
|
+
* @module @exodus/test/benchmark
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Benchmark options
|
|
14
|
+
* @inline
|
|
15
|
+
*/
|
|
16
|
+
export interface BenchmarkOptions {
|
|
17
|
+
/** Array of arguments to pass to the benchmark function */
|
|
18
|
+
args?: any[]
|
|
19
|
+
/** Timeout in milliseconds (default: 1000) */
|
|
20
|
+
timeout?: number
|
|
21
|
+
/** Skip this benchmark */
|
|
22
|
+
skip?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Runs a benchmark
|
|
27
|
+
* @param name - Name of the benchmark
|
|
28
|
+
* @param options - Benchmark options
|
|
29
|
+
* @param fn - Function to benchmark
|
|
30
|
+
*/
|
|
31
|
+
export declare function benchmark<A>(
|
|
32
|
+
name: string,
|
|
33
|
+
options: BenchmarkOptions & { args: A[] },
|
|
34
|
+
fn: (arg: A) => any | Promise<any>
|
|
35
|
+
): Promise<void>
|
|
36
|
+
export declare function benchmark(
|
|
37
|
+
name: string,
|
|
38
|
+
options: BenchmarkOptions & { args?: undefined },
|
|
39
|
+
fn: (arg: number) => any | Promise<any>
|
|
40
|
+
): Promise<void>
|
package/src/engine.pure.cjs
CHANGED
|
@@ -137,9 +137,10 @@ async function runContext(context) {
|
|
|
137
137
|
const guard = { id: null, failed: false }
|
|
138
138
|
const timeout = options.timeout || Number(process.env.EXODUS_TEST_TIMEOUT) || 5000
|
|
139
139
|
guard.promise = new Promise((resolve) => {
|
|
140
|
-
if (process.env.EXODUS_TEST_PLATFORM
|
|
140
|
+
if (['engine262', 'ladybird-js'].includes(process.env.EXODUS_TEST_PLATFORM)) {
|
|
141
141
|
// parallel timeouts are slowing down everything on engine262
|
|
142
142
|
// so we let only the host timeout to catch us, not individual test timeout
|
|
143
|
+
// ladybird-js has no timers but has a maximium promise chain length, so it breaks
|
|
143
144
|
return
|
|
144
145
|
}
|
|
145
146
|
|
package/src/expect.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [Jest Expect](https://jestjs.io/docs/expect)-compatible API, but much faster
|
|
3
|
+
*
|
|
4
|
+
* If you are using Jest globals, you don't have to import this manually.
|
|
5
|
+
*
|
|
6
|
+
* Just run `@exodus/test` with `--jest` flag and use global `expect`.
|
|
7
|
+
*
|
|
8
|
+
* See [Jest Expect documentation](https://jestjs.io/docs/expect).
|
|
9
|
+
*
|
|
10
|
+
* If you want to import it directly:
|
|
11
|
+
* ```js
|
|
12
|
+
* import { expect } from '@exodus/test/expect'
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* This short-cuts most common cases and tries to avoid loading `expect` altogether,
|
|
16
|
+
* but for everything that can't be bypassed (e.g. test failures) it uses real `expect`.
|
|
17
|
+
*
|
|
18
|
+
* Everything including output formatting matches Jest `expect`.
|
|
19
|
+
* @module @exodus/test/expect
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export type { Expect } from 'expect'
|
|
23
|
+
export declare const expect: import('expect').Expect
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Load the expect library (for internal use)
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadExpect(reason?: string): import('expect').Expect
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ### The `@exodus/test` package consists of submodules, there is no single export.
|
|
3
|
+
* Import specific submodules instead.
|
|
4
|
+
*
|
|
5
|
+
* Straightforward setups:
|
|
6
|
+
* 1. Import `node:test` and run with `@exodus/test`
|
|
7
|
+
* 2. Use jest globals and run with `@exodus/test --jest`
|
|
8
|
+
* 3. Import `@exodus/test/tape` instead of tape or tap and run with `@exodus/test` (or `node`)
|
|
9
|
+
*
|
|
10
|
+
* See [README](https://github.com/ExodusOSS/test/blob/main/README.md).
|
|
11
|
+
*/
|
|
12
|
+
declare module '@exodus/test' {}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
throw new Error(
|
|
2
|
+
`This package consists of submodules, there is no single export. Import specific submodules instead.
|
|
3
|
+
|
|
4
|
+
Straightforward setups:
|
|
5
|
+
1. Import node:test and run with @exodus/test
|
|
6
|
+
2. Use jest globals and run with @exodus/test --jest
|
|
7
|
+
3. Import @exodus/test/tape instead of tape or tap and run with @exodus/test (or node)
|
|
8
|
+
|
|
9
|
+
See README: https://github.com/ExodusOSS/test/blob/main/README.md
|
|
10
|
+
`
|
|
11
|
+
)
|
package/src/jest.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [Jest](https://jestjs.io/)-compatible API, but much faster, ESM friendly, and based on `node:test`
|
|
3
|
+
*
|
|
4
|
+
* You likely don't have to import this manually.
|
|
5
|
+
*
|
|
6
|
+
* Just run `@exodus/test` with `--jest` flag.
|
|
7
|
+
*
|
|
8
|
+
* See [Jest API documentation](https://jestjs.io/docs/api).
|
|
9
|
+
*
|
|
10
|
+
* If you want to run Jest test files with just `node` (or without `--jest` flag), do e.g.:
|
|
11
|
+
* ```js
|
|
12
|
+
* import { describe, test, expect, jest } from '@exodus/test/jest'
|
|
13
|
+
* import { beforeEach, afterEach, beforeAll, afterAll } from '@exodus/test/jest'
|
|
14
|
+
* ```
|
|
15
|
+
* @module @exodus/test/jest
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Re-export Jest types from @jest/globals
|
|
19
|
+
export { describe, test, it, jest, beforeEach, afterEach, beforeAll, afterAll } from '@jest/globals'
|
|
20
|
+
export type { expect, Expect } from './expect.d.ts'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Alias for test()
|
|
24
|
+
*
|
|
25
|
+
* For using the resolution as a drop-in replacement for libs expecting `should()`
|
|
26
|
+
* @hidden
|
|
27
|
+
*/
|
|
28
|
+
export declare function should(name: string, fn: () => void | Promise<void>, timeout?: number): void
|
package/src/jest.environment.js
CHANGED
|
@@ -13,7 +13,8 @@ export const specialEnvironments = {
|
|
|
13
13
|
runScripts: 'dangerously',
|
|
14
14
|
virtualConsole,
|
|
15
15
|
})
|
|
16
|
-
virtualConsole.
|
|
16
|
+
const forwardTo = virtualConsole.forwardTo ? 'forwardTo' : 'sendTo'
|
|
17
|
+
virtualConsole[forwardTo](console, { omitJSDOMErrors: true })
|
|
17
18
|
virtualConsole.on('jsdomError', (error) => {
|
|
18
19
|
throw error
|
|
19
20
|
})
|
package/src/mock.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extra mocking and testing utilities
|
|
3
|
+
*
|
|
4
|
+
* - Record / replay / inspect `fetch()` sessions
|
|
5
|
+
* - Record / replay / inspect `WebSocket` sessions
|
|
6
|
+
* - Speed up timers
|
|
7
|
+
* - Debug (or assert no) active timers
|
|
8
|
+
* @module @exodus/test/mock
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/// <reference types="node" />
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Network replay utilities
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Records fetch calls and returns a fetch function */
|
|
18
|
+
export declare function fetchRecord(options?: any): typeof fetch
|
|
19
|
+
|
|
20
|
+
/** Replays fetch calls from recording and returns a fetch function */
|
|
21
|
+
export declare function fetchReplay(): typeof fetch
|
|
22
|
+
|
|
23
|
+
/** Records WebSocket calls and returns a WebSocket constructor */
|
|
24
|
+
export declare function websocketRecord(options?: any): typeof WebSocket
|
|
25
|
+
|
|
26
|
+
/** Replays WebSocket calls from recording and returns a WebSocket constructor */
|
|
27
|
+
export declare function websocketReplay(options?: any): typeof WebSocket
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Timer tracking and debugging utilities
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Enables timer tracking */
|
|
34
|
+
export declare function timersTrack(): void
|
|
35
|
+
|
|
36
|
+
/** Outputs debug information about active timers */
|
|
37
|
+
export declare function timersDebug(): void
|
|
38
|
+
|
|
39
|
+
/** Lists all active timers */
|
|
40
|
+
export declare function timersList(): any[]
|
|
41
|
+
|
|
42
|
+
/** Asserts no timers are active */
|
|
43
|
+
export declare function timersAssert(): void
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Speeds up timers by the given rate
|
|
47
|
+
* @param rate - Speed multiplier (e.g., 2 means 2x faster)
|
|
48
|
+
* @param options - Configuration options
|
|
49
|
+
* @param options.apis - Array of APIs to speed up (default: ['setTimeout', 'setInterval', 'Date'])
|
|
50
|
+
*/
|
|
51
|
+
export declare function timersSpeedup(
|
|
52
|
+
rate: number,
|
|
53
|
+
options?: { apis?: ('setTimeout' | 'setInterval' | 'Date')[] }
|
|
54
|
+
): void
|
package/src/node.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [node:test](https://nodejs.org/api/test.html)-compatible API
|
|
3
|
+
*
|
|
4
|
+
* You most likely don't have to import this manually, just use `node:test`.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* ```js
|
|
8
|
+
* import { test, describe } from 'node:test'
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* This import is what `@exodus/test` will resolve that to on non-Node.js engines,
|
|
12
|
+
* e.g. browsers and barebones.
|
|
13
|
+
*
|
|
14
|
+
* See [node:test documentation](https://nodejs.org/api/test.html).
|
|
15
|
+
* @module @exodus/test/node
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/// <reference types="node" />
|
|
19
|
+
|
|
20
|
+
// Re-export from node:test module
|
|
21
|
+
export { describe, test, it, beforeEach, afterEach, before, after, mock, snapshot } from 'node:test'
|
package/src/node.js
CHANGED
|
@@ -7,4 +7,4 @@ function setResolveSnapshotPath() {
|
|
|
7
7
|
|
|
8
8
|
export const snapshot = { setDefaultSnapshotSerializers, setResolveSnapshotPath }
|
|
9
9
|
|
|
10
|
-
export { mock, describe, test, beforeEach, afterEach, before, after } from './engine.js'
|
|
10
|
+
export { mock, describe, test, beforeEach, afterEach, before, after, test as it } from './engine.js'
|
package/src/tape.cjs
CHANGED
|
@@ -9,6 +9,7 @@ const loadLib = async () => {
|
|
|
9
9
|
const test = async (...args) => (await loadLib()).test(...args)
|
|
10
10
|
test.skip = async (...args) => (await loadLib()).test.skip(...args)
|
|
11
11
|
test.only = async (...args) => (await loadLib()).test.only(...args)
|
|
12
|
+
test.onFinish = async (...args) => (await loadLib()).test.onFinish(...args)
|
|
12
13
|
test.test = test
|
|
13
14
|
/* eslint-enable unicorn/no-await-expression-member */
|
|
14
15
|
|
package/src/tape.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [tape](https://npmjs.com/package/tape)-compatible API
|
|
3
|
+
*
|
|
4
|
+
* Replace your `tape` imports with `@exodus/test/tape` and it will run on top of `node:test`.
|
|
5
|
+
*
|
|
6
|
+
* And will be runnable in browsers / barebone engines with `@exodus/test`.
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
* ```js
|
|
10
|
+
* import test from '@exodus/test/tape' // ESM
|
|
11
|
+
* const test = require('@exodus/test/tape') // CJS
|
|
12
|
+
* ```
|
|
13
|
+
* @module @exodus/test/tape
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/// <reference types="node" />
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tape test context/assertion object
|
|
20
|
+
*/
|
|
21
|
+
export interface Test {
|
|
22
|
+
/** Plans the number of assertions */
|
|
23
|
+
plan(count: number): void
|
|
24
|
+
|
|
25
|
+
/** Ends the test */
|
|
26
|
+
end(): void
|
|
27
|
+
|
|
28
|
+
/** Skips the test */
|
|
29
|
+
skip(msg?: string): void
|
|
30
|
+
|
|
31
|
+
/** Marks test as todo */
|
|
32
|
+
todo(msg?: string): void
|
|
33
|
+
|
|
34
|
+
/** Adds a comment */
|
|
35
|
+
comment(msg: string): void
|
|
36
|
+
|
|
37
|
+
/** Nested test */
|
|
38
|
+
test(name: string, cb: (t: Test) => void): void
|
|
39
|
+
test(name: string, opts: TestOptions, cb: (t: Test) => void): void
|
|
40
|
+
|
|
41
|
+
/** Assertions */
|
|
42
|
+
|
|
43
|
+
/** Assert that value is truthy */
|
|
44
|
+
ok(value: any, msg?: string): void
|
|
45
|
+
true(value: any, msg?: string): void
|
|
46
|
+
assert(value: any, msg?: string): void
|
|
47
|
+
|
|
48
|
+
/** Assert that value is falsy */
|
|
49
|
+
notOk(value: any, msg?: string): void
|
|
50
|
+
false(value: any, msg?: string): void
|
|
51
|
+
notok(value: any, msg?: string): void
|
|
52
|
+
|
|
53
|
+
/** Assert strict equality */
|
|
54
|
+
equal(actual: any, expected: any, msg?: string): void
|
|
55
|
+
equals(actual: any, expected: any, msg?: string): void
|
|
56
|
+
isEqual(actual: any, expected: any, msg?: string): void
|
|
57
|
+
is(actual: any, expected: any, msg?: string): void
|
|
58
|
+
strictEqual(actual: any, expected: any, msg?: string): void
|
|
59
|
+
strictEquals(actual: any, expected: any, msg?: string): void
|
|
60
|
+
|
|
61
|
+
/** Assert strict inequality */
|
|
62
|
+
notEqual(actual: any, expected: any, msg?: string): void
|
|
63
|
+
notEquals(actual: any, expected: any, msg?: string): void
|
|
64
|
+
notStrictEqual(actual: any, expected: any, msg?: string): void
|
|
65
|
+
notStrictEquals(actual: any, expected: any, msg?: string): void
|
|
66
|
+
doesNotEqual(actual: any, expected: any, msg?: string): void
|
|
67
|
+
isNotEqual(actual: any, expected: any, msg?: string): void
|
|
68
|
+
isNot(actual: any, expected: any, msg?: string): void
|
|
69
|
+
not(actual: any, expected: any, msg?: string): void
|
|
70
|
+
isInequal(actual: any, expected: any, msg?: string): void
|
|
71
|
+
|
|
72
|
+
/** Assert loose equality */
|
|
73
|
+
looseEqual(actual: any, expected: any, msg?: string): void
|
|
74
|
+
looseEquals(actual: any, expected: any, msg?: string): void
|
|
75
|
+
|
|
76
|
+
/** Assert loose inequality */
|
|
77
|
+
notLooseEqual(actual: any, expected: any, msg?: string): void
|
|
78
|
+
notLooseEquals(actual: any, expected: any, msg?: string): void
|
|
79
|
+
|
|
80
|
+
/** Assert deep strict equality */
|
|
81
|
+
deepEqual(actual: any, expected: any, msg?: string): void
|
|
82
|
+
deepEquals(actual: any, expected: any, msg?: string): void
|
|
83
|
+
isEquivalent(actual: any, expected: any, msg?: string): void
|
|
84
|
+
same(actual: any, expected: any, msg?: string): void
|
|
85
|
+
|
|
86
|
+
/** Assert deep strict inequality */
|
|
87
|
+
notDeepEqual(actual: any, expected: any, msg?: string): void
|
|
88
|
+
notDeepEquals(actual: any, expected: any, msg?: string): void
|
|
89
|
+
notEquivalent(actual: any, expected: any, msg?: string): void
|
|
90
|
+
notDeeply(actual: any, expected: any, msg?: string): void
|
|
91
|
+
notSame(actual: any, expected: any, msg?: string): void
|
|
92
|
+
isNotDeepEqual(actual: any, expected: any, msg?: string): void
|
|
93
|
+
isNotDeeply(actual: any, expected: any, msg?: string): void
|
|
94
|
+
isNotEquivalent(actual: any, expected: any, msg?: string): void
|
|
95
|
+
isInequivalent(actual: any, expected: any, msg?: string): void
|
|
96
|
+
|
|
97
|
+
/** Assert deep loose equality */
|
|
98
|
+
deepLooseEqual(actual: any, expected: any, msg?: string): void
|
|
99
|
+
|
|
100
|
+
/** Assert deep loose inequality */
|
|
101
|
+
notDeepLooseEqual(actual: any, expected: any, msg?: string): void
|
|
102
|
+
|
|
103
|
+
/** Assert function throws */
|
|
104
|
+
throws(fn: () => any, expected?: RegExp | Function, msg?: string): void
|
|
105
|
+
|
|
106
|
+
/** Assert function does not throw */
|
|
107
|
+
doesNotThrow(fn: () => any, expected?: RegExp | Function, msg?: string): void
|
|
108
|
+
|
|
109
|
+
/** Assert promise rejects */
|
|
110
|
+
rejects(promise: Promise<any>, expected?: RegExp | Function, msg?: string): Promise<void>
|
|
111
|
+
|
|
112
|
+
/** Assert promise resolves */
|
|
113
|
+
resolves(promise: Promise<any>, msg?: string): Promise<void>
|
|
114
|
+
doesNotReject(promise: Promise<any>, expected?: RegExp | Function, msg?: string): Promise<void>
|
|
115
|
+
|
|
116
|
+
/** Force a passing assertion */
|
|
117
|
+
pass(msg?: string): void
|
|
118
|
+
|
|
119
|
+
/** Force a failing assertion */
|
|
120
|
+
fail(msg?: string): void
|
|
121
|
+
|
|
122
|
+
/** Assert no error */
|
|
123
|
+
error(err: any, msg?: string): void
|
|
124
|
+
ifError(err: any, msg?: string): void
|
|
125
|
+
ifErr(err: any, msg?: string): void
|
|
126
|
+
iferror(err: any, msg?: string): void
|
|
127
|
+
|
|
128
|
+
/** Custom assertion function */
|
|
129
|
+
assertion(fn: Function, ...args: any[]): void
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Test options
|
|
134
|
+
*/
|
|
135
|
+
export interface TestOptions {
|
|
136
|
+
skip?: boolean
|
|
137
|
+
todo?: boolean
|
|
138
|
+
timeout?: number
|
|
139
|
+
concurrency?: number
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Test function
|
|
144
|
+
*/
|
|
145
|
+
export interface TestFunction {
|
|
146
|
+
/** Run a test */
|
|
147
|
+
(name: string, cb: (t: Test) => void): void
|
|
148
|
+
(name: string, opts: TestOptions, cb: (t: Test) => void): void
|
|
149
|
+
(cb: (t: Test) => void): void
|
|
150
|
+
(opts: TestOptions, cb: (t: Test) => void): void
|
|
151
|
+
|
|
152
|
+
/** Only run this test */
|
|
153
|
+
only: TestFunction
|
|
154
|
+
|
|
155
|
+
/** Skip this test */
|
|
156
|
+
skip: TestFunction
|
|
157
|
+
|
|
158
|
+
/** Register a callback to run after all tests finish */
|
|
159
|
+
onFinish(fn: () => void): void
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
declare const test: TestFunction
|
|
163
|
+
|
|
164
|
+
export { test }
|
|
165
|
+
|
|
166
|
+
export default test
|
package/src/tape.js
CHANGED
package/tape.js
CHANGED
package/CHANGELOG.md
DELETED