@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 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/ExodusMovement/test/actions/workflows/checks.yaml)
133
+ See live output in [CI](https://github.com/ExodusOSS/test/actions/workflows/checks.yaml)
132
134
 
133
135
  ## Library
134
136
 
@@ -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.107",
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/ExodusMovement/test",
6
+ "homepage": "https://github.com/ExodusOSS/test",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/ExodusMovement/test.git"
9
+ "url": "https://github.com/ExodusOSS/test.git"
10
10
  },
11
11
  "bugs": {
12
- "url": "https://github.com/ExodusMovement/tests/issues"
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.8",
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 (total >= BigInt(timeout) * 10n ** 6n) break
52
+ if (stop >= endAt) break
52
53
  }
53
54
 
54
55
  const mean = total / BigInt(count)
55
- let res = `${name} x ${fRps(1e9 / Number(mean))} ops/sec @ ${fTime(mean)}/op`
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
- replay = require('@exodus/replay') // synchronous
10
- } else if (!replay) {
11
- throw new Error('Failed to load @exodus/replay')
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