@exodus/test 1.0.0-rc.107 → 1.0.0-rc.109
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 +4 -2
- package/bin/find-binary.js +5 -0
- package/bin/index.js +17 -7
- package/package.json +7 -5
- package/src/benchmark.js +5 -3
- package/src/engine.pure.snapshot.cjs +1 -1
- package/src/replay.js +5 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ It can run your existing tests on [all runtimes and also browsers](#engines), wi
|
|
|
12
12
|
and typestrip (via `--typescript`) modes
|
|
13
13
|
- Runs on Node.js [node:test](https://nodejs.org/api/test.html), Bun, Deno, Electron,
|
|
14
14
|
[v8 CLI](https://v8.dev/docs/d8), JSC, [Hermes](https://hermesengine.dev), [SpiderMonkey](https://spidermonkey.dev/),
|
|
15
|
-
Chrome, Firefox, WebKit, Brave, Microsoft Edge,
|
|
15
|
+
Chrome, Firefox, WebKit, Brave, Microsoft Edge, [Servo](https://servo.org/),
|
|
16
16
|
[QuickJS](https://github.com/quickjs-ng/quickjs), [XS](https://github.com/Moddable-OpenSource/moddable-xst),
|
|
17
17
|
[GraalJS](https://github.com/oracle/graaljs), [Escargot](https://github.com/Samsung/escargot),
|
|
18
18
|
[Boa](https://github.com/boa-dev/boa), and even [engine262](https://github.com/engine262/engine262).
|
|
@@ -66,6 +66,8 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
66
66
|
- `firefox:puppeteer` — Firefox
|
|
67
67
|
- `brave:puppeteer` — Brave
|
|
68
68
|
- `msedge:puppeteer` — Microsoft Edge
|
|
69
|
+
- Bundle
|
|
70
|
+
- `servo:bundle` — Servo (expects it to be installed in the system or in PATH)
|
|
69
71
|
- Barebone engines (system-provided or installed with `npx jsvu` / `npx esvu`):
|
|
70
72
|
- `v8:bundle` — [v8 CLI](https://v8.dev/docs/d8) (Chrome/Blink/Node.js JavaScript engine)
|
|
71
73
|
- `jsc:bundle` — [JavaScriptCore](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html) (Safari/WebKit JavaScript engine)
|
|
@@ -128,7 +130,7 @@ Use `--engine` (or `EXODUS_TEST_ENGINE=`) to specify one of:
|
|
|
128
130
|
</pre>
|
|
129
131
|
</details>
|
|
130
132
|
|
|
131
|
-
See live output in [CI](https://github.com/
|
|
133
|
+
See live output in [CI](https://github.com/ExodusOSS/test/actions/workflows/checks.yaml)
|
|
132
134
|
|
|
133
135
|
## Library
|
|
134
136
|
|
package/bin/find-binary.js
CHANGED
|
@@ -60,6 +60,7 @@ function findBinaryOnce(name) {
|
|
|
60
60
|
case 'ladybird-js': // naming by esvu
|
|
61
61
|
case 'engine262':
|
|
62
62
|
return findFile([jsvu, esvu])
|
|
63
|
+
case 'shermes': // our temporary name for static hermes
|
|
63
64
|
case 'xs':
|
|
64
65
|
return findFile([jsvu, esvu], false)
|
|
65
66
|
case 'electron':
|
|
@@ -90,6 +91,10 @@ function findBinaryOnce(name) {
|
|
|
90
91
|
case 'safari':
|
|
91
92
|
addPaths('darwin', '/Applications/Safari.app/Contents/MacOS/Safari')
|
|
92
93
|
break
|
|
94
|
+
case 'servo':
|
|
95
|
+
addPaths('darwin', '/Applications/Servo.app/Contents/MacOS/servo')
|
|
96
|
+
addPaths('linux', '/usr/bin/servo')
|
|
97
|
+
break
|
|
93
98
|
default:
|
|
94
99
|
throw new Error('Trying to find an unexpected executable name')
|
|
95
100
|
}
|
package/bin/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
7
7
|
import { basename, join } from 'node:path'
|
|
8
8
|
import { randomUUID } from 'node:crypto'
|
|
9
9
|
import { existsSync, rmSync, realpathSync } from 'node:fs'
|
|
10
|
-
import { unlink } from 'node:fs/promises'
|
|
10
|
+
import { writeFile, unlink } from 'node:fs/promises'
|
|
11
11
|
import { tmpdir, availableParallelism, homedir } from 'node:os'
|
|
12
12
|
import assert from 'node:assert/strict'
|
|
13
13
|
// The following make sense only when we run the code in the same Node.js version, i.e. engineOptions.haveIsOk
|
|
@@ -20,6 +20,7 @@ const DEFAULT_PATTERNS = [`**/?(*.)+(spec|test).?([cm])[jt]s?(x)`] // do not tru
|
|
|
20
20
|
const bundleOpts = { pure: true, bundle: true, esbuild: true, ts: 'auto' }
|
|
21
21
|
const bareboneOpts = { ...bundleOpts, barebone: true }
|
|
22
22
|
const hermesA = ['-w', '-Xmicrotask-queue'] // -Xes6-class fails with -O0 / -Og, --block-scoping fails in default, any of that is bad
|
|
23
|
+
const hermesS = [...hermesA, '-Xes6-block-scoping']
|
|
23
24
|
const denoA = ['run', '--allow-all'] // also will set DENO_COMPAT=1 env flag below
|
|
24
25
|
const denoT = ['test', '--allow-all']
|
|
25
26
|
const nodeTS = process.features.typescript ? 'auto' : 'flag'
|
|
@@ -42,6 +43,7 @@ const ENGINES = new Map(
|
|
|
42
43
|
'v8:bundle': { binary: 'd8', binaryArgs: ['--expose-gc'], ...bareboneOpts },
|
|
43
44
|
'jsc:bundle': { binary: 'jsc', target: 'safari13', ...bareboneOpts },
|
|
44
45
|
'hermes:bundle': { binary: 'hermes', binaryArgs: hermesA, target: 'es2018', ...bareboneOpts },
|
|
46
|
+
'shermes:bundle': { binary: 'shermes', binaryArgs: hermesS, target: 'es2018', ...bareboneOpts },
|
|
45
47
|
'spidermonkey:bundle': { binary: 'spidermonkey', ...bareboneOpts },
|
|
46
48
|
'engine262:bundle': { binary: 'engine262', ...bareboneOpts },
|
|
47
49
|
'quickjs:bundle': { binary: 'quickjs', binaryArgs: ['--std'], ...bareboneOpts },
|
|
@@ -50,6 +52,8 @@ const ENGINES = new Map(
|
|
|
50
52
|
'escargot:bundle': { binary: 'escargot', ...bareboneOpts },
|
|
51
53
|
'boa:bundle': { binary: 'boa', binaryArgs: ['-m'], ...bareboneOpts },
|
|
52
54
|
'jerryscript:bundle': { binary: 'jerryscript', ...bareboneOpts },
|
|
55
|
+
// Special case: running a browser from CLI like a bundle
|
|
56
|
+
'servo:bundle': { binary: 'servo', binaryArgs: ['--headless'], ...bundleOpts, html: true },
|
|
53
57
|
// Browser engines
|
|
54
58
|
'chrome:puppeteer': { binary: 'chrome', browsers: 'puppeteer', ...bundleOpts },
|
|
55
59
|
'firefox:puppeteer': { binary: 'firefox', browsers: 'puppeteer', ...bundleOpts },
|
|
@@ -62,8 +66,8 @@ const ENGINES = new Map(
|
|
|
62
66
|
'msedge:playwright': { binary: 'msedge', browsers: 'playwright', ...bundleOpts },
|
|
63
67
|
})
|
|
64
68
|
)
|
|
65
|
-
const barebonesOk = ['v8', 'd8', 'spidermonkey', 'quickjs', 'xs', 'hermes']
|
|
66
|
-
const barebonesUnhandled = ['jsc', 'escargot', 'boa', 'graaljs', 'jerry', 'engine262']
|
|
69
|
+
const barebonesOk = ['v8', 'd8', 'spidermonkey', 'quickjs', 'xs', 'hermes', 'shermes']
|
|
70
|
+
const barebonesUnhandled = ['jsc', 'escargot', 'boa', 'graaljs', 'jerry', 'engine262', 'servo']
|
|
67
71
|
|
|
68
72
|
const getEnvFlag = (name) => {
|
|
69
73
|
if (!Object.hasOwn(process.env, name)) return
|
|
@@ -280,9 +284,9 @@ const engineOptions = ENGINES.get(options.engine)
|
|
|
280
284
|
assert(engineOptions, `Unknown engine: ${options.engine}`)
|
|
281
285
|
Object.assign(options, engineOptions)
|
|
282
286
|
options.platform = options.binary // binary can be overriden by c8 or electron
|
|
283
|
-
const isBrowserLike = options.browsers || options.electron
|
|
287
|
+
const isBrowserLike = options.browsers || options.electron || options.html
|
|
284
288
|
setEnv('EXODUS_TEST_ENGINE', options.engine) // e.g. 'hermes:bundle', 'node:bundle', 'node:test', 'node:pure'
|
|
285
|
-
setEnv('EXODUS_TEST_PLATFORM', options.binary) // e.g. 'hermes', 'node'
|
|
289
|
+
setEnv('EXODUS_TEST_PLATFORM', options.binary === 'shermes' ? 'hermes' : options.binary) // e.g. 'hermes', 'node'
|
|
286
290
|
setEnv('EXODUS_TEST_TIMEOUT', options.testTimeout)
|
|
287
291
|
setEnv('EXODUS_TEST_DEVTOOLS', options.devtools ? '1' : '')
|
|
288
292
|
setEnv('EXODUS_TEST_IS_BROWSER', isBrowserLike ? '1' : '')
|
|
@@ -593,7 +597,7 @@ if (options.binary === 'electron') {
|
|
|
593
597
|
}
|
|
594
598
|
}
|
|
595
599
|
|
|
596
|
-
if (options.barebone || ['electron', 'workerd'].includes(options.binary)) {
|
|
600
|
+
if (options.barebone || ['electron', 'workerd', 'servo'].includes(options.binary)) {
|
|
597
601
|
options.binary = findBinary(options.binary)
|
|
598
602
|
options.binaryCanBeAbsolute = true
|
|
599
603
|
}
|
|
@@ -687,9 +691,14 @@ if (options.pure) {
|
|
|
687
691
|
const runOne = async (inputFile) => {
|
|
688
692
|
const bundled = buildFile ? await buildFile(inputFile) : undefined
|
|
689
693
|
if (buildFile) assert(bundled.file)
|
|
690
|
-
const file = buildFile ? bundled.file : inputFile
|
|
691
694
|
if (bundled?.errors.length > 0) return { ok: false, output: bundled.errors }
|
|
695
|
+
if (bundled && options.html) {
|
|
696
|
+
bundled.fileHtml = `${bundled.file}.html`
|
|
697
|
+
assert(/^[a-z0-9/_.-]+\.js$/iu.test(bundled.file), bundled.file)
|
|
698
|
+
await writeFile(bundled.fileHtml, `<script src="${bundled.file}"></script>`)
|
|
699
|
+
}
|
|
692
700
|
|
|
701
|
+
const file = buildFile ? bundled.fileHtml ?? bundled.file : inputFile
|
|
693
702
|
const failedBare = 'EXODUS_TEST_FAILED_EXIT_CODE_1'
|
|
694
703
|
const cleanOut = (out) => out.replaceAll(`\n${failedBare}\n`, '\n').replaceAll(failedBare, '')
|
|
695
704
|
// Timeout is fallback if timeout in script hangs, 50x as it can be adjusted per-script inside them
|
|
@@ -719,6 +728,7 @@ if (options.pure) {
|
|
|
719
728
|
throw err // Internal test runner error, e.g. launch() failed
|
|
720
729
|
} finally {
|
|
721
730
|
if (bundled) await unlink(bundled.file)
|
|
731
|
+
if (bundled?.fileHtml) await unlink(bundled.fileHtml)
|
|
722
732
|
}
|
|
723
733
|
}
|
|
724
734
|
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/test",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.109",
|
|
4
4
|
"author": "Exodus Movement, Inc.",
|
|
5
5
|
"description": "A test suite runner",
|
|
6
|
-
"homepage": "https://github.com/
|
|
6
|
+
"homepage": "https://github.com/ExodusOSS/test",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "https://github.com/ExodusOSS/test.git"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/
|
|
12
|
+
"url": "https://github.com/ExodusOSS/tests/issues"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
15
|
"test",
|
|
@@ -122,7 +122,9 @@
|
|
|
122
122
|
"test:v8": "EXODUS_TEST_ENGINE=v8:bundle npm run test:_bundle --",
|
|
123
123
|
"test:jsc": "EXODUS_TEST_ENGINE=jsc:bundle npm run test:_bundle --",
|
|
124
124
|
"test:hermes": "EXODUS_TEST_ENGINE=hermes:bundle npm run test:_bundle --",
|
|
125
|
+
"test:shermes": "EXODUS_TEST_ENGINE=shermes:bundle npm run test:_bundle --",
|
|
125
126
|
"test:spidermonkey": "EXODUS_TEST_ENGINE=spidermonkey:bundle npm run test:_bundle --",
|
|
127
|
+
"test:servo": "EXODUS_TEST_ENGINE=servo:bundle npm run test:_bundle --",
|
|
126
128
|
"test:engine262": "EXODUS_TEST_ENGINE=engine262:bundle npm run test:_bundle --",
|
|
127
129
|
"test:quickjs": "EXODUS_TEST_ENGINE=quickjs:bundle npm run test:_bundle --",
|
|
128
130
|
"test:xs": "EXODUS_TEST_ENGINE=xs:bundle npm run test:_bundle --",
|
|
@@ -143,7 +145,7 @@
|
|
|
143
145
|
"optionalDependencies": {
|
|
144
146
|
"@chalker/queue": "^1.0.1",
|
|
145
147
|
"@exodus/replay": "^1.0.0-rc.9",
|
|
146
|
-
"@exodus/test-bundler": "1.0.0-rc.
|
|
148
|
+
"@exodus/test-bundler": "1.0.0-rc.10",
|
|
147
149
|
"c8": "^9.1.0",
|
|
148
150
|
"expect": "^30.2.0",
|
|
149
151
|
"fast-glob": "^3.2.11",
|
package/src/benchmark.js
CHANGED
|
@@ -37,6 +37,7 @@ export async function benchmark(name, options, fn) {
|
|
|
37
37
|
let min, max
|
|
38
38
|
let total = 0n
|
|
39
39
|
let count = 0
|
|
40
|
+
const endAt = getTime() + BigInt(timeout) * 10n ** 6n
|
|
40
41
|
while (true) {
|
|
41
42
|
const arg = args ? args[count % args.length] : count
|
|
42
43
|
count++
|
|
@@ -48,14 +49,15 @@ export async function benchmark(name, options, fn) {
|
|
|
48
49
|
total += diff
|
|
49
50
|
if (min === undefined || min > diff) min = diff
|
|
50
51
|
if (max === undefined || max < diff) max = diff
|
|
51
|
-
if (
|
|
52
|
+
if (stop >= endAt) break
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
const mean = total / BigInt(count)
|
|
55
|
-
|
|
56
|
+
const rps = (1e9 * count) / Number(total) // Loss in precision to doubles on very fast ops, but this is better than mean rounding
|
|
57
|
+
let res = `${name} x ${fRps(rps)} ops/sec @ ${fTime(mean)}/op`
|
|
56
58
|
if (fTime(min) !== fTime(max)) res += ` (${fTime(min)}..${fTime(max)})`
|
|
57
59
|
console.log(res)
|
|
58
60
|
|
|
59
61
|
if (gc) for (let i = 0; i < 4; i++) gc()
|
|
60
|
-
return { total, count, mean, min, max }
|
|
62
|
+
return { rps, total, count, mean, min, max }
|
|
61
63
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const nameCounts = new Map()
|
|
2
2
|
let snapshotText, snapshotTextClean
|
|
3
3
|
|
|
4
|
-
const escapeSnapshot = (str) => str.replaceAll(/([\\`])/gu, '\\$1')
|
|
4
|
+
const escapeSnapshot = (str) => str.replaceAll(/([\\`]|\$\{)/gu, '\\$1')
|
|
5
5
|
|
|
6
6
|
function matchSnapshot(readSnapshot, assert, name, serialized) {
|
|
7
7
|
// We don't have native snapshots, polyfill reading
|
package/src/replay.js
CHANGED
|
@@ -6,10 +6,12 @@ let readRecordingRaw, writeRecording
|
|
|
6
6
|
function loadReplayBundle() {
|
|
7
7
|
// TODO: also under process.features.require_module
|
|
8
8
|
if (process.env.EXODUS_TEST_ENVIRONMENT === 'bundle') {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
try {
|
|
10
|
+
replay = require('@exodus/replay') // synchronous
|
|
11
|
+
} catch {}
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
if (!replay) throw new Error('Failed to load @exodus/replay')
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
// Optimized out in 'bundle' env
|