@exodus/test 1.0.0-rc.50 → 1.0.0-rc.51

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/bin/inband.js ADDED
@@ -0,0 +1,11 @@
1
+ import { resolve } from 'node:path'
2
+ import { describe } from '../src/engine.js'
3
+
4
+ const files = JSON.parse(process.env.EXODUS_TEST_INBAND)
5
+ if (!Array.isArray(files)) throw new Error('Unexpected')
6
+
7
+ for (const file of files.sort()) {
8
+ await describe(`EXODUS_TEST_INBAND:${file}`, async () => {
9
+ await import(resolve(file))
10
+ })
11
+ }
package/bin/index.js CHANGED
@@ -394,6 +394,17 @@ if (tsTests.length > 0 && !options.esbuild && !options.typescript) {
394
394
  console.warn(`Flag --typescript has been used, but there were no TypeScript tests found!`)
395
395
  }
396
396
 
397
+ if (!options.bundle) {
398
+ // uses top-level await, :bundle doesn't have that
399
+ const inband = new Set(files.filter((f) => basename(f).includes('.inband.')))
400
+ if (inband.size > 0) {
401
+ process.env.EXODUS_TEST_INBAND = JSON.stringify([...inband])
402
+ const remaning = files.filter((f) => !inband.has(f))
403
+ files.length = 0
404
+ files.push(fileURLToPath(import.meta.resolve('./inband.js')), ...remaning)
405
+ }
406
+ }
407
+
397
408
  if (!Object.hasOwn(process.env, 'NODE_ENV')) process.env.NODE_ENV = 'test'
398
409
 
399
410
  const setEnv = (name, value) => {
package/bin/reporter.js CHANGED
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
2
2
  import { inspect } from 'node:util'
3
3
  import { relative, resolve } from 'node:path'
4
4
  import { spec as SpecReporter } from 'node:test/reporters'
5
+ import { fileURLToPath } from 'node:url'
5
6
 
6
7
  const { FORCE_COLOR, CI, GITHUB_WORKSPACE, LERNA_PACKAGE_NAME } = process.env
7
8
  const haveColors = process.stdout.hasColors?.() || FORCE_COLOR === '1' // 0 is already handled by hasColors()
@@ -34,9 +35,15 @@ export const format = (chunk) => {
34
35
  const formatTime = (ms) => (ms ? color(` (${ms}ms)`, dim) : '')
35
36
  const formatSuffix = (d) => `${formatTime(d.details.duration_ms)}${d.todo ? ' # TODO' : ''}`
36
37
 
38
+ const cwd = process.cwd()
39
+ const INBAND_PREFIX = 'EXODUS_TEST_INBAND:'
40
+ const inbandFileAbsolute = fileURLToPath(import.meta.resolve('./inband.js'))
41
+ const inbandFile = relative(cwd, inbandFileAbsolute)
42
+
37
43
  const groupCI = CI && !process.execArgv.includes('--watch') && !LERNA_PACKAGE_NAME // lerna+nx groups already
38
44
  export const timeLabel = color('Total time', dim)
39
- export const head = groupCI ? () => {} : (file) => console.log(color(`# ${file}`, 'bold'))
45
+ const filename = (f) => (f === inbandFile || f === inbandFileAbsolute ? 'In-band tests' : f)
46
+ export const head = groupCI ? () => {} : (file) => console.log(color(`# ${filename(file)}`, 'bold'))
40
47
  export const middle = (file, ok, ms) => {
41
48
  if (!groupCI) return
42
49
  console.log(`::group::${ok ? '✅' : '❌'} ${color(file, 'bold')}${formatTime(ms)}`)
@@ -111,7 +118,6 @@ export default async function nodeTestReporterExodus(source) {
111
118
 
112
119
  const files = new Set()
113
120
  const failedFiles = new Set()
114
- const cwd = process.cwd()
115
121
  const path = []
116
122
  let file
117
123
  const diagnostic = []
@@ -119,20 +125,31 @@ export default async function nodeTestReporterExodus(source) {
119
125
  const isTopLevelTest = ({ nesting, line, column, name, file }) =>
120
126
  nesting === 0 && line === 1 && column === 1 && file.endsWith(name) && resolve(name) === file // some events have data.file resolved, some not)
121
127
  const processNewFile = (data) => {
122
- const newFile = relative(cwd, data.entry || data.file || data.name) // some events have data.file resolved, some not
123
- if (newFile === file) return
128
+ const band = data.name?.startsWith?.(INBAND_PREFIX) && data.name.slice(INBAND_PREFIX.length)
129
+ const newFile = relative(cwd, band || data.entry || data.file || data.name) // some events have data.file resolved, some not
130
+ if (newFile === file || newFile === inbandFile) return
124
131
  if (file !== undefined) dump()
125
132
  file = newFile
126
133
  assert(files.has(file), 'Cound not determine file')
127
134
  head(file)
128
135
  }
129
136
 
137
+ const pathstr = (p) => (p[0]?.startsWith(INBAND_PREFIX) ? p.slice(1) : p).join(' > ')
138
+ const pskip = (p) => path.length === 1 && p[0].startsWith(INBAND_PREFIX)
139
+
130
140
  for await (const { type, data } of source) {
131
141
  // Ignored: test:complete (no support on older Node.js), test:plan, test:dequeue, test:enqueue
132
142
  switch (type) {
133
143
  case 'test:dequeue':
134
- if (data.nesting === 0 && !Object.hasOwn(data, 'file')) files.add(relative(cwd, data.name)) // old-style
135
- if (isTopLevelTest(data)) files.add(relative(cwd, data.file))
144
+ if (data.nesting === 0 && data.name?.startsWith?.(INBAND_PREFIX)) {
145
+ files.add(data.name.slice(INBAND_PREFIX.length))
146
+ } else if (data.nesting === 0 && !Object.hasOwn(data, 'file')) {
147
+ files.add(relative(cwd, data.name)) // old-style
148
+ } else if (isTopLevelTest(data)) {
149
+ files.add(relative(cwd, data.file))
150
+ }
151
+
152
+ files.delete(inbandFile) // ensure we don't add that one
136
153
  break
137
154
  case 'test:start':
138
155
  processNewFile(data)
@@ -141,11 +158,11 @@ export default async function nodeTestReporterExodus(source) {
141
158
  break
142
159
  case 'test:pass':
143
160
  const label = data.skip ? color('⏭ SKIP ', dim) : color('✔ PASS ', 'green')
144
- print(`${label}${path.join(' > ')}${formatSuffix(data)}`)
161
+ if (!pskip(path)) print(`${label}${pathstr(path)}${formatSuffix(data)}`)
145
162
  assert(path.pop() === data.name)
146
163
  break
147
164
  case 'test:fail':
148
- print(`${color('✖ FAIL ', 'red')}${path.join(' > ')}${formatSuffix(data)}`)
165
+ if (!pskip(path)) print(`${color('✖ FAIL ', 'red')}${pathstr(path)}${formatSuffix(data)}`)
149
166
  assert(path.pop() === data.name)
150
167
  if (!data.todo) failedFiles.add(file)
151
168
  if (!notPrintedError(data.details.error)) {
package/bundler/bundle.js CHANGED
@@ -167,6 +167,27 @@ export const build = async (...files) => {
167
167
 
168
168
  const hasBuffer = ['node', 'bun'].includes(options.platform)
169
169
  const api = (f) => resolveRequire(`./modules/${f}`)
170
+ const nodeUnprefixed = {
171
+ assert: dirname(dirname(resolveRequire('assert/'))),
172
+ 'assert/strict': api('assert-strict.cjs'),
173
+ buffer: hasBuffer ? api('node-buffer.cjs') : dirname(resolveRequire('buffer/')),
174
+ child_process: api('child_process.cjs'),
175
+ constants: resolveRequire('constants-browserify'),
176
+ crypto: api('crypto.cjs'),
177
+ events: dirname(resolveRequire('events/')),
178
+ fs: api('fs.cjs'),
179
+ 'fs/promises': api('fs-promises.cjs'),
180
+ http: api('http.cjs'),
181
+ https: api('https.cjs'),
182
+ os: resolveRequire('os-browserify'),
183
+ path: resolveRequire('path-browserify'),
184
+ querystring: resolveRequire('querystring-es3'),
185
+ stream: resolveRequire('stream-browserify'),
186
+ timers: resolveRequire('timers-browserify'),
187
+ url: dirname(resolveRequire('url/')),
188
+ util: dirname(resolveRequire('util/')),
189
+ zlib: resolveRequire('browserify-zlib'),
190
+ }
170
191
  const res = await buildWrap({
171
192
  logLevel: 'silent',
172
193
  stdin: {
@@ -214,29 +235,9 @@ export const build = async (...files) => {
214
235
  'node:test': resolveImport('../src/node.js'),
215
236
  // Inner
216
237
  'exodus-test:util-format': api('util-format.cjs'),
217
- // Node browserify
218
- 'node:assert': dirname(dirname(resolveRequire('assert/'))),
219
- 'node:assert/strict': api('assert-strict.cjs'),
220
- 'node:fs': api('fs.cjs'),
221
- 'node:fs/promises': api('fs-promises.cjs'),
222
- fs: api('fs.cjs'),
223
- 'fs/promises': api('fs-promises.cjs'),
224
- assert: dirname(dirname(resolveRequire('assert/'))),
225
- buffer: hasBuffer ? api('node-buffer.cjs') : dirname(resolveRequire('buffer/')),
226
- child_process: api('child_process.cjs'),
227
- constants: resolveRequire('constants-browserify'),
228
- crypto: api('crypto.cjs'),
229
- events: dirname(resolveRequire('events/')),
230
- http: api('http.cjs'),
231
- https: api('https.cjs'),
232
- os: resolveRequire('os-browserify'),
233
- path: resolveRequire('path-browserify'),
234
- querystring: resolveRequire('querystring-es3'),
235
- stream: resolveRequire('stream-browserify'),
236
- timers: resolveRequire('timers-browserify'),
237
- url: dirname(resolveRequire('url/')),
238
- util: dirname(resolveRequire('util/')),
239
- zlib: resolveRequire('browserify-zlib'),
238
+ // Node.js (except node:test)
239
+ ...Object.fromEntries(Object.entries(nodeUnprefixed).map(([k, v]) => [`node:${k}`, v])),
240
+ ...nodeUnprefixed,
240
241
  // expect-related deps
241
242
  'ansi-styles': api('ansi-styles.cjs'),
242
243
  'jest-util': api('jest-util.js'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/test",
3
- "version": "1.0.0-rc.50",
3
+ "version": "1.0.0-rc.51",
4
4
  "author": "Exodus Movement, Inc.",
5
5
  "description": "A test suite runner",
6
6
  "homepage": "https://github.com/ExodusMovement/test",
@@ -36,6 +36,7 @@
36
36
  },
37
37
  "prettier": "@exodus/prettier",
38
38
  "files": [
39
+ "bin/inband.js",
39
40
  "bin/jest.js",
40
41
  "bin/reporter.js",
41
42
  "bundler/babel-worker.cjs",
@@ -4,6 +4,7 @@ const assertLoose = require('node:assert')
4
4
  const { setTimeout, setInterval, setImmediate, Date } = globalThis
5
5
  const { clearTimeout, clearInterval, clearImmediate } = globalThis
6
6
 
7
+ const INBAND_PREFIX_REGEX = /^EXODUS_TEST_INBAND:/
7
8
  const print = console.log.bind(console) // we don not want overrides
8
9
  Error.stackTraceLimit = 100
9
10
 
@@ -31,6 +32,7 @@ class Context {
31
32
  constructor(parent, name, options = {}) {
32
33
  Object.assign(this, { root: parent?.root, parent, name, options })
33
34
  this.fullName = parent && parent !== parent.root ? `${parent.fullName} > ${name}` : name
35
+ if (this.fullName === name) this.fullName = this.fullName.replace(INBAND_PREFIX_REGEX, '')
34
36
  if (this.root) {
35
37
  this.parent.children.push(this)
36
38
  } else {