@exodus/test 1.0.0-rc.45 → 1.0.0-rc.47

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.
Files changed (2) hide show
  1. package/bin/reporter.js +34 -16
  2. package/package.json +1 -1
package/bin/reporter.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict'
2
2
  import { inspect } from 'node:util'
3
- import { relative } from 'node:path'
3
+ import { relative, resolve } from 'node:path'
4
4
  import { spec as SpecReporter } from 'node:test/reporters'
5
5
 
6
6
  const { FORCE_COLOR, CI, GITHUB_WORKSPACE, LERNA_PACKAGE_NAME } = process.env
@@ -32,6 +32,7 @@ export const format = (chunk) => {
32
32
  }
33
33
 
34
34
  const formatTime = (ms) => (ms ? color(` (${ms}ms)`, dim) : '')
35
+ const formatSuffix = (d) => `${formatTime(d.details.duration_ms)}${d.todo ? ' # TODO' : ''}`
35
36
 
36
37
  const groupCI = CI && !process.execArgv.includes('--watch') && !LERNA_PACKAGE_NAME // lerna+nx groups already
37
38
  export const timeLabel = color('Total time', dim)
@@ -77,6 +78,22 @@ const extractError = ({ details: { error }, ...data }, file) => {
77
78
  return { body: cleanWorkspace(body), loc }
78
79
  }
79
80
 
81
+ try {
82
+ // Welp, in some cases there is no other way to tell the entry point
83
+ // E.g. when the test file is just an import of another one, the reported 'file' is the imported one
84
+ // We want to know the original entry points instead
85
+ const runner = await import('node:internal/test_runner/runner') // eslint-disable-line @exodus/import/no-unresolved
86
+ const { FileTest } = runner.default || runner
87
+ const { addToReport } = FileTest.prototype
88
+ FileTest.prototype.addToReport = function (item, ...rest) {
89
+ if (item?.type === 'test:start' && !item.data.entry) {
90
+ item.data.entry = this.loc?.file || (this.name && resolve(this.name)) // eslint-disable-line @exodus/mutable/no-param-reassign-prop-only
91
+ }
92
+
93
+ return addToReport.call(this, item, ...rest)
94
+ }
95
+ } catch {}
96
+
80
97
  export default async function nodeTestReporterExodus(source) {
81
98
  const spec = new SpecReporter()
82
99
  spec.on('data', (data) => {
@@ -97,41 +114,42 @@ export default async function nodeTestReporterExodus(source) {
97
114
  const cwd = process.cwd()
98
115
  const path = []
99
116
  let file
100
- const formatSuffix = (d) => `${formatTime(d.details.duration_ms)}${d.todo ? ' # TODO' : ''}`
117
+ const diagnostic = []
118
+ const delayed = []
119
+ const isTopLevelTest = ({ nesting, line, column, name, file }) =>
120
+ nesting === 0 && line === 1 && column === 1 && file.endsWith(name) && resolve(name) === file // some events have data.file resolved, some not)
101
121
  const processNewFile = (data) => {
102
- const newFile = relative(cwd, data.file) // some events have data.file resolved, some not
122
+ const newFile = relative(cwd, data.entry || data.file) // some events have data.file resolved, some not
103
123
  if (newFile === file) return
104
124
  if (file !== undefined) dump()
105
125
  file = newFile
106
- files.add(file)
126
+ assert(files.has(file), 'Cound not determine file')
107
127
  head(file)
108
128
  }
109
129
 
110
- const diagnostic = []
111
-
112
130
  for await (const { type, data } of source) {
113
131
  // Ignored: test:complete (no support on older Node.js), test:plan, test:dequeue, test:enqueue
114
132
  switch (type) {
133
+ 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))
136
+ break
115
137
  case 'test:start':
116
138
  processNewFile(data)
117
139
  path.push(data.name)
140
+ while (delayed.length > 0) print(delayed.shift())
118
141
  break
119
142
  case 'test:pass':
120
- if (data.skip) {
121
- print(`${color('⏭ SKIP ', dim)}${path.join(' > ')}${formatSuffix(data)}`)
122
- } else {
123
- print(`${color('✔ PASS ', 'green')}${path.join(' > ')}${formatSuffix(data)}`)
124
- }
125
-
143
+ const label = data.skip ? color('⏭ SKIP ', dim) : color('✔ PASS ', 'green')
144
+ print(`${label}${path.join(' > ')}${formatSuffix(data)}`)
126
145
  assert(path.pop() === data.name)
127
146
  break
128
147
  case 'test:fail':
129
148
  print(`${color('✖ FAIL ', 'red')}${path.join(' > ')}${formatSuffix(data)}`)
130
149
  assert(path.pop() === data.name)
131
- assert.equal(file, relative(cwd, data.file))
132
150
  if (!data.todo) failedFiles.add(file)
133
151
  if (!notPrintedError(data.details.error)) {
134
- const { body, loc } = extractError(data, file)
152
+ const { body, loc } = extractError(data, relative(cwd, data.file)) // might be different from current file if in subimport
135
153
  if (!data.todo && CI && loc.line != null && loc.col != null) {
136
154
  print(`::error ${serializeGitHub(Object.entries(loc))}::${escapeGitHub(body)}`)
137
155
  } else if (body) {
@@ -150,8 +168,8 @@ export default async function nodeTestReporterExodus(source) {
150
168
  break
151
169
  case 'test:stderr':
152
170
  case 'test:stdout':
153
- processNewFile(data)
154
- print(data.message.replace(/\n$/, ''))
171
+ const handle = path.length > 0 ? print : (arg) => delayed.push(arg)
172
+ handle(data.message.replace(/\n$/, '')) // these are printed at test:start
155
173
  break
156
174
  case 'test:coverage':
157
175
  spec.write({ type, data }) // let spec reporter handle that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/test",
3
- "version": "1.0.0-rc.45",
3
+ "version": "1.0.0-rc.47",
4
4
  "author": "Exodus Movement, Inc.",
5
5
  "description": "A test suite runner",
6
6
  "homepage": "https://github.com/ExodusMovement/test",