1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110import {Done, spawn, SuiteFn, Test, TestFn, TestApi} from '@abstractest/core'
import {Mocker} from '@abstractest/types'
import {expect, SnapshotState} from '@abstractest/expect'
import {mock} from '@abstractest/mock'
import {after, afterEach, before, beforeEach, describe, it} from 'node:test'
import * as path from 'node:path'
export const _api = {
spawn,
it,
describe,
after,
afterEach,
before,
beforeEach,
mock
}
const g: any = global
const currentTestNameChunks: string[] = []
const queue: string[] = []
const trackName = (handler: (name: string, fn: any) => any): typeof handler => (name, fn) => {
currentTestNameChunks.push(name)
handler(name, fn)
currentTestNameChunks.pop()
}
const adaptTest = (method: any): Test => trackName((name, fn) => {
queue.push(currentTestNameChunks.join(' '))
const handler = (done = (_result?: any) => {/* noop */}) => {
let save = () => {/* noop */} // eslint-disable-line unicorn/consistent-function-scoping
if (g.__testPath && g.__testRoot) {
const currentTestName = queue.shift()
const testPath = g.__testPath
const snapshotPath = path.join(g.__testRoot, '__snapshots__', `${path.basename(testPath)}.snap`)
const snapshotState = new SnapshotState(snapshotPath, {
expand: undefined,
snapshotFormat: { escapeString: false, printBasicPrototype: false },
updateSnapshot: 'new',
rootDir: process.cwd(),
prettierPath: 'prettier',
// rootDir: config.rootDir,
// snapshotFormat: config.snapshotFormat,
// updateSnapshot: globalConfig.updateSnapshot,
});
save = () => {
snapshotState.save()
// eslint-disable-next-line
// @ts-ignore
expect?.setState({snapshotState: undefined, testPath: undefined, currentTestName: undefined})
}
// eslint-disable-next-line
// @ts-ignore
expect?.setState({snapshotState, testPath, currentTestName})
}
let cb = (result?: any) => { save(); done(result); cb = () => {/* noop */}}
const result = fn?.(cb)
return typeof result?.then == 'function'
? result.then(() => cb()).catch(cb)
: cb()
}
// TODO refactor workaround
if (/^[^(]+\([^)]+,/.test(fn?.toString() + '')) {
method(name, (_ctx: any, done: Done) => handler(done))
} else {
method(name, () => handler())
}
})
const _it =
Object.assign((name: string, fn?: TestFn) => { adaptTest(_api.it)(name, fn) }, {
only(name: string, fn?: TestFn) { adaptTest(_api.it.only)(name, fn) },
skip(name: string, fn?: TestFn) { adaptTest(_api.it.skip)(name, fn) },
todo(name: string, fn?: TestFn) { adaptTest(_api.it.todo)(name, fn) },
})
const _describe =
Object.assign((name: string, fn?: SuiteFn) => { trackName(_api.describe)(name, fn)}, {
only(name: string, fn?: SuiteFn) { trackName(_api.describe.only)(name, fn) },
skip(name: string, fn?: SuiteFn) { trackName(_api.describe.skip)(name, fn) },
todo(name: string, fn?: SuiteFn) { trackName(_api.describe.todo)(name, fn) },
})
const _mock: Mocker = {
// eslint-disable-next-line
// @ts-ignore
spyOn(...args: any[]) { return _api.mock.spyOn(...args) },
// eslint-disable-next-line
// @ts-ignore
fn(...args: any[]) { return _api.mock.fn(...args) },
}
export const api: TestApi = {
expect,
it: _it,
describe: _describe,
before(fn) { return _api.before(fn) },
beforeEach(fn) { return _api.beforeEach(fn) },
after(fn) { return _api.after(fn) },
afterEach(fn) { return _api.afterEach(fn) },
mock: _mock,
}