Skip to content

Commit

Permalink
feat: support explicit in-band tests grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
ChALkeR committed Sep 8, 2024
1 parent 1deb507 commit 7aaeb09
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 8 deletions.
11 changes: 11 additions & 0 deletions bin/inband.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { resolve } from 'node:path'
import { describe } from '../src/engine.js'

const files = JSON.parse(process.env.EXODUS_TEST_INBAND)
if (!Array.isArray(files)) throw new Error('Unexpected')

for (const file of files.sort()) {
await describe(`EXODUS_TEST_INBAND:${file}`, async () => {
await import(resolve(file))
})
}
8 changes: 8 additions & 0 deletions bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,14 @@ if (tsTests.length > 0 && !options.esbuild && !options.typescript) {
console.warn(`Flag --typescript has been used, but there were no TypeScript tests found!`)
}

const inband = new Set(files.filter((f) => basename(f).includes('.inband.')))
if (inband.size > 0) {
process.env.EXODUS_TEST_INBAND = JSON.stringify([...inband])
const remaning = files.filter((f) => !inband.has(f))
files.length = 0
files.push(fileURLToPath(import.meta.resolve('./inband.js')), ...remaning)
}

if (!Object.hasOwn(process.env, 'NODE_ENV')) process.env.NODE_ENV = 'test'

const setEnv = (name, value) => {
Expand Down
33 changes: 25 additions & 8 deletions bin/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
import { inspect } from 'node:util'
import { relative, resolve } from 'node:path'
import { spec as SpecReporter } from 'node:test/reporters'
import { fileURLToPath } from 'node:url'

const { FORCE_COLOR, CI, GITHUB_WORKSPACE, LERNA_PACKAGE_NAME } = process.env
const haveColors = process.stdout.hasColors?.() || FORCE_COLOR === '1' // 0 is already handled by hasColors()
Expand Down Expand Up @@ -34,9 +35,15 @@ export const format = (chunk) => {
const formatTime = (ms) => (ms ? color(` (${ms}ms)`, dim) : '')
const formatSuffix = (d) => `${formatTime(d.details.duration_ms)}${d.todo ? ' # TODO' : ''}`

const cwd = process.cwd()
const INBAND_PREFIX = 'EXODUS_TEST_INBAND:'
const inbandFileAbsolute = fileURLToPath(import.meta.resolve('./inband.js'))
const inbandFile = relative(cwd, inbandFileAbsolute)

const groupCI = CI && !process.execArgv.includes('--watch') && !LERNA_PACKAGE_NAME // lerna+nx groups already
export const timeLabel = color('Total time', dim)
export const head = groupCI ? () => {} : (file) => console.log(color(`# ${file}`, 'bold'))
const filename = (f) => (f === inbandFile || f === inbandFileAbsolute ? 'In-band tests' : f)
export const head = groupCI ? () => {} : (file) => console.log(color(`# ${filename(file)}`, 'bold'))
export const middle = (file, ok, ms) => {
if (!groupCI) return
console.log(`::group::${ok ? '✅' : '❌'} ${color(file, 'bold')}${formatTime(ms)}`)
Expand Down Expand Up @@ -111,28 +118,38 @@ export default async function nodeTestReporterExodus(source) {

const files = new Set()
const failedFiles = new Set()
const cwd = process.cwd()
const path = []
let file
const diagnostic = []
const delayed = []
const isTopLevelTest = ({ nesting, line, column, name, file }) =>
nesting === 0 && line === 1 && column === 1 && file.endsWith(name) && resolve(name) === file // some events have data.file resolved, some not)
const processNewFile = (data) => {
const newFile = relative(cwd, data.entry || data.file || data.name) // some events have data.file resolved, some not
if (newFile === file) return
const band = data.name?.startsWith?.(INBAND_PREFIX) && data.name.slice(INBAND_PREFIX.length)
const newFile = relative(cwd, band || data.entry || data.file || data.name) // some events have data.file resolved, some not
if (newFile === file || newFile === inbandFile) return
if (file !== undefined) dump()
file = newFile
assert(files.has(file), 'Cound not determine file')
head(file)
}

const pathstr = (p) => (p[0]?.startsWith(INBAND_PREFIX) ? p.slice(1) : p).join(' > ')
const pskip = (p) => path.length === 1 && p[0].startsWith(INBAND_PREFIX)

for await (const { type, data } of source) {
// Ignored: test:complete (no support on older Node.js), test:plan, test:dequeue, test:enqueue
switch (type) {
case 'test:dequeue':
if (data.nesting === 0 && !Object.hasOwn(data, 'file')) files.add(relative(cwd, data.name)) // old-style
if (isTopLevelTest(data)) files.add(relative(cwd, data.file))
if (data.nesting === 0 && data.name?.startsWith?.(INBAND_PREFIX)) {
files.add(data.name.slice(INBAND_PREFIX.length))
} else if (data.nesting === 0 && !Object.hasOwn(data, 'file')) {
files.add(relative(cwd, data.name)) // old-style
} else if (isTopLevelTest(data)) {
files.add(relative(cwd, data.file))
}

files.delete(inbandFile) // ensure we don't add that one
break
case 'test:start':
processNewFile(data)
Expand All @@ -141,11 +158,11 @@ export default async function nodeTestReporterExodus(source) {
break
case 'test:pass':
const label = data.skip ? color('⏭ SKIP ', dim) : color('✔ PASS ', 'green')
print(`${label}${path.join(' > ')}${formatSuffix(data)}`)
if (!pskip(path)) print(`${label}${pathstr(path)}${formatSuffix(data)}`)
assert(path.pop() === data.name)
break
case 'test:fail':
print(`${color('✖ FAIL ', 'red')}${path.join(' > ')}${formatSuffix(data)}`)
if (!pskip(path)) print(`${color('✖ FAIL ', 'red')}${pathstr(path)}${formatSuffix(data)}`)
assert(path.pop() === data.name)
if (!data.todo) failedFiles.add(file)
if (!notPrintedError(data.details.error)) {
Expand Down
2 changes: 2 additions & 0 deletions src/engine.pure.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const assertLoose = require('node:assert')
const { setTimeout, setInterval, setImmediate, Date } = globalThis
const { clearTimeout, clearInterval, clearImmediate } = globalThis

const INBAND_PREFIX_REGEX = /^EXODUS_TEST_INBAND:/
const print = console.log.bind(console) // we don not want overrides
Error.stackTraceLimit = 100

Expand Down Expand Up @@ -31,6 +32,7 @@ class Context {
constructor(parent, name, options = {}) {
Object.assign(this, { root: parent?.root, parent, name, options })
this.fullName = parent && parent !== parent.root ? `${parent.fullName} > ${name}` : name
if (this.fullName === name) this.fullName = this.fullName.replace(INBAND_PREFIX_REGEX, '')
if (this.root) {
this.parent.children.push(this)
} else {
Expand Down

0 comments on commit 7aaeb09

Please sign in to comment.