borp 0.4.2 → 0.6.0
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/.github/workflows/ci.yml +13 -3
- package/README.md +66 -1
- package/borp.js +63 -11
- package/fixtures/gc/gc.test.js +8 -0
- package/fixtures/js-esm/lib/add.js +3 -0
- package/fixtures/js-esm/test/add.test.js +7 -0
- package/fixtures/js-esm/test/add2.test.js +7 -0
- package/lib/reporters.js +114 -0
- package/lib/run.js +17 -4
- package/package.json +6 -2
- package/test/basic.test.js +21 -0
- package/test/cli.test.js +21 -0
- package/test/coverage.test.js +1 -0
- package/test/reporters.test.js +172 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -19,10 +19,10 @@ jobs:
|
|
|
19
19
|
node-version: [18.x, 20.x, 21.x]
|
|
20
20
|
os: [ubuntu-latest, windows-latest]
|
|
21
21
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
23
|
|
|
24
24
|
- name: Use Node.js
|
|
25
|
-
uses: actions/setup-node@
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
26
|
with:
|
|
27
27
|
node-version: ${{ matrix.node-version }}
|
|
28
28
|
|
|
@@ -30,6 +30,16 @@ jobs:
|
|
|
30
30
|
run: |
|
|
31
31
|
npm install
|
|
32
32
|
|
|
33
|
+
- name: Lint
|
|
34
|
+
run: |
|
|
35
|
+
npm run lint
|
|
36
|
+
|
|
33
37
|
- name: Run tests
|
|
34
38
|
run: |
|
|
35
|
-
npm run
|
|
39
|
+
npm run unit -- --reporter spec --reporter md:report.md --reporter gh
|
|
40
|
+
|
|
41
|
+
- name: Upload report
|
|
42
|
+
shell: bash
|
|
43
|
+
if: success() || failure()
|
|
44
|
+
run: |
|
|
45
|
+
cat report.md >> "$GITHUB_STEP_SUMMARY"
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ npm i borp --save-dev
|
|
|
17
17
|
borp --coverage
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Borp will
|
|
20
|
+
Borp will automatically run all tests files matching `*.test.{js|ts}`.
|
|
21
21
|
|
|
22
22
|
### Example project setup
|
|
23
23
|
|
|
@@ -91,7 +91,72 @@ Note the use of `incremental: true`, which speed up compilation massively.
|
|
|
91
91
|
* `--timeout` or `-t`, timeouts the tests after a given time; default is 30000 ms
|
|
92
92
|
* `--coverage-exclude` or `-X`, a list of comma-separated patterns to exclude from the coverage report. All tests files are ignored by default.
|
|
93
93
|
* `--ignore` or `-i`, ignore a glob pattern, and not look for tests there
|
|
94
|
+
* `--expose-gc`, exposes the gc() function to tests
|
|
94
95
|
* `--pattern` or `-p`, run tests matching the given glob pattern
|
|
96
|
+
* `--reporter` or `-r`, set up a reporter, use a colon to set a file destination. Default: `spec`.
|
|
97
|
+
|
|
98
|
+
## Reporters
|
|
99
|
+
|
|
100
|
+
Here are the available reporters:
|
|
101
|
+
|
|
102
|
+
* `md`: creates a markdown table, useful for setting up a Summary in your GitHub Action
|
|
103
|
+
* `gh`: emits `::error` workflow commands for GitHub Actions to show inlined error. Enabled by default when running on GHA.
|
|
104
|
+
* `tap`: outputs the test results in the TAP format.
|
|
105
|
+
* `spec`: outputs the test results in a human-readable format.
|
|
106
|
+
* `dot`: outputs the test results in a compact format, where each passing test is represented by a ., and each failing test is represented by a X.
|
|
107
|
+
* `junit`: outputs test results in a jUnit XML format
|
|
108
|
+
|
|
109
|
+
## GitHub Action Summary
|
|
110
|
+
|
|
111
|
+
The following will automatically show the summary of the test run in the summary page of GitHub Actions.
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
name: ci
|
|
115
|
+
|
|
116
|
+
on:
|
|
117
|
+
push:
|
|
118
|
+
paths-ignore:
|
|
119
|
+
- 'docs/**'
|
|
120
|
+
- '*.md'
|
|
121
|
+
pull_request:
|
|
122
|
+
paths-ignore:
|
|
123
|
+
- 'docs/**'
|
|
124
|
+
- '*.md'
|
|
125
|
+
|
|
126
|
+
jobs:
|
|
127
|
+
test:
|
|
128
|
+
runs-on: ${{matrix.os}}
|
|
129
|
+
|
|
130
|
+
strategy:
|
|
131
|
+
matrix:
|
|
132
|
+
node-version: [18.x, 20.x, 21.x]
|
|
133
|
+
os: [ubuntu-latest, windows-latest]
|
|
134
|
+
steps:
|
|
135
|
+
- uses: actions/checkout@v4
|
|
136
|
+
|
|
137
|
+
- name: Use Node.js
|
|
138
|
+
uses: actions/setup-node@v4
|
|
139
|
+
with:
|
|
140
|
+
node-version: ${{ matrix.node-version }}
|
|
141
|
+
|
|
142
|
+
- name: Install
|
|
143
|
+
run: |
|
|
144
|
+
npm install
|
|
145
|
+
|
|
146
|
+
- name: Lint
|
|
147
|
+
run: |
|
|
148
|
+
npm run lint
|
|
149
|
+
|
|
150
|
+
- name: Run tests
|
|
151
|
+
run: |
|
|
152
|
+
npm run unit -- --reporter spec --reporter md:report.md
|
|
153
|
+
|
|
154
|
+
- name: Upload report
|
|
155
|
+
shell: bash
|
|
156
|
+
if: success() || failure()
|
|
157
|
+
run: |
|
|
158
|
+
cat report.md >> "$GITHUB_STEP_SUMMARY"
|
|
159
|
+
```
|
|
95
160
|
|
|
96
161
|
## License
|
|
97
162
|
|
package/borp.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { parseArgs } from 'node:util'
|
|
4
|
-
import
|
|
4
|
+
import Reporters from 'node:test/reporters'
|
|
5
5
|
import { mkdtemp, rm, readFile } from 'node:fs/promises'
|
|
6
|
+
import { createWriteStream } from 'node:fs'
|
|
6
7
|
import { finished } from 'node:stream/promises'
|
|
7
8
|
import { join, relative } from 'node:path'
|
|
8
9
|
import posix from 'node:path/posix'
|
|
9
10
|
import runWithTypeScript from './lib/run.js'
|
|
11
|
+
import { MarkdownReporter, GithubWorkflowFailuresReporter } from './lib/reporters.js'
|
|
10
12
|
import { Report } from 'c8'
|
|
11
13
|
import os from 'node:os'
|
|
14
|
+
import { execa } from 'execa'
|
|
12
15
|
|
|
13
|
-
let reporter
|
|
14
16
|
/* c8 ignore next 4 */
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
reporter = tap
|
|
20
|
-
}
|
|
17
|
+
process.on('unhandledRejection', (err) => {
|
|
18
|
+
console.error(err)
|
|
19
|
+
process.exit(1)
|
|
20
|
+
})
|
|
21
21
|
|
|
22
22
|
const args = parseArgs({
|
|
23
23
|
args: process.argv.slice(2),
|
|
@@ -30,17 +30,38 @@ const args = parseArgs({
|
|
|
30
30
|
timeout: { type: 'string', short: 't', default: '30000' },
|
|
31
31
|
'coverage-exclude': { type: 'string', short: 'X', multiple: true },
|
|
32
32
|
ignore: { type: 'string', short: 'i', multiple: true },
|
|
33
|
-
|
|
33
|
+
'expose-gc': { type: 'boolean' },
|
|
34
|
+
help: { type: 'boolean', short: 'h' },
|
|
35
|
+
reporter: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
short: 'r',
|
|
38
|
+
default: ['spec'],
|
|
39
|
+
multiple: true
|
|
40
|
+
}
|
|
34
41
|
},
|
|
35
42
|
allowPositionals: true
|
|
36
43
|
})
|
|
37
44
|
|
|
38
|
-
/* c8 ignore next
|
|
45
|
+
/* c8 ignore next 5 */
|
|
39
46
|
if (args.values.help) {
|
|
40
47
|
console.log(await readFile(new URL('./README.md', import.meta.url), 'utf8'))
|
|
41
48
|
process.exit(0)
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
if (args.values['expose-gc'] && typeof global.gc !== 'function') {
|
|
52
|
+
try {
|
|
53
|
+
await execa('node', ['--expose-gc', ...process.argv.slice(1)], {
|
|
54
|
+
stdio: 'inherit',
|
|
55
|
+
env: {
|
|
56
|
+
...process.env
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
process.exit(0)
|
|
60
|
+
} catch (error) {
|
|
61
|
+
process.exit(1)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
44
65
|
if (args.values.concurrency) {
|
|
45
66
|
args.values.concurrency = parseInt(args.values.concurrency)
|
|
46
67
|
}
|
|
@@ -63,13 +84,44 @@ const config = {
|
|
|
63
84
|
}
|
|
64
85
|
|
|
65
86
|
try {
|
|
87
|
+
const pipes = []
|
|
88
|
+
|
|
89
|
+
const reporters = {
|
|
90
|
+
...Reporters,
|
|
91
|
+
md: new MarkdownReporter(config),
|
|
92
|
+
gh: new GithubWorkflowFailuresReporter(config),
|
|
93
|
+
/* eslint new-cap: "off" */
|
|
94
|
+
spec: new Reporters.spec()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// If we're running in a GitHub action, adds the gh reporter
|
|
98
|
+
// by default so that we can report failures to GitHub
|
|
99
|
+
if (process.env.GITHUB_ACTION) {
|
|
100
|
+
args.values.reporter.push('gh')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const input of args.values.reporter) {
|
|
104
|
+
const [name, dest] = input.split(':')
|
|
105
|
+
const reporter = reporters[name]
|
|
106
|
+
if (!reporter) {
|
|
107
|
+
throw new Error(`Unknown reporter: ${name}`)
|
|
108
|
+
}
|
|
109
|
+
let output = process.stdout
|
|
110
|
+
if (dest) {
|
|
111
|
+
output = createWriteStream(dest)
|
|
112
|
+
}
|
|
113
|
+
pipes.push([reporter, output])
|
|
114
|
+
}
|
|
115
|
+
|
|
66
116
|
const stream = await runWithTypeScript(config)
|
|
67
117
|
|
|
68
118
|
stream.on('test:fail', () => {
|
|
69
119
|
process.exitCode = 1
|
|
70
120
|
})
|
|
71
121
|
|
|
72
|
-
|
|
122
|
+
for (const [reporter, output] of pipes) {
|
|
123
|
+
stream.compose(reporter).pipe(output)
|
|
124
|
+
}
|
|
73
125
|
|
|
74
126
|
await finished(stream)
|
|
75
127
|
|
package/lib/reporters.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Transform } from 'node:stream'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
|
|
4
|
+
function normalizeFile (file, cwd) {
|
|
5
|
+
let res = file
|
|
6
|
+
if (file.startsWith('file://')) {
|
|
7
|
+
try {
|
|
8
|
+
res = fileURLToPath(new URL(file))
|
|
9
|
+
} catch (err) {
|
|
10
|
+
if (err.code === 'ERR_INVALID_FILE_URL_PATH') {
|
|
11
|
+
res = fileURLToPath(new URL(file.replace('file:///', 'file://')))
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
res = res.replace(cwd, '')
|
|
16
|
+
if (res.startsWith('/') || res.startsWith('\\')) {
|
|
17
|
+
res = res.slice(1)
|
|
18
|
+
}
|
|
19
|
+
return res
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function eventToLine (event) {
|
|
23
|
+
return `* __${event.data.name}__, duration ${event.data.details.duration_ms}ms, line ${event.data.line}\n`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class MarkdownReporter extends Transform {
|
|
27
|
+
constructor (opts) {
|
|
28
|
+
super({
|
|
29
|
+
...opts,
|
|
30
|
+
objectMode: true
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
this._files = {}
|
|
34
|
+
this._cwd = opts?.cwd
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getFile (path) {
|
|
38
|
+
const file = this._files[path] || {
|
|
39
|
+
pass: [],
|
|
40
|
+
fail: []
|
|
41
|
+
}
|
|
42
|
+
this._files[path] = file
|
|
43
|
+
return file
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_transform (event, encoding, callback) {
|
|
47
|
+
if (!event.data.file) {
|
|
48
|
+
callback()
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const path = normalizeFile(event.data.file, this._cwd)
|
|
53
|
+
const file = this.getFile(path)
|
|
54
|
+
switch (event.type) {
|
|
55
|
+
case 'test:pass':
|
|
56
|
+
file.pass.push(event)
|
|
57
|
+
break
|
|
58
|
+
case 'test:fail':
|
|
59
|
+
file.fail.push(event)
|
|
60
|
+
break
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
callback()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_flush (callback) {
|
|
67
|
+
this.push('# Summary\n')
|
|
68
|
+
for (const [path, file] of Object.entries(this._files)) {
|
|
69
|
+
this.push(`## ${path}\n`)
|
|
70
|
+
if (file.pass.length > 0) {
|
|
71
|
+
this.push('### :white_check_mark: Pass\n')
|
|
72
|
+
for (const event of file.pass) {
|
|
73
|
+
this.push(eventToLine(event))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (file.fail.length > 0) {
|
|
77
|
+
this.push('### :x: Fail\n')
|
|
78
|
+
for (const event of file.fail) {
|
|
79
|
+
this.push(eventToLine(event))
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.push(null)
|
|
84
|
+
callback()
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class GithubWorkflowFailuresReporter extends Transform {
|
|
89
|
+
constructor (opts) {
|
|
90
|
+
super({
|
|
91
|
+
...opts,
|
|
92
|
+
objectMode: true
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
this._files = {}
|
|
96
|
+
this._cwd = opts?.cwd
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_transform (event, encoding, callback) {
|
|
100
|
+
if (!event.data.file) {
|
|
101
|
+
callback()
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const path = normalizeFile(event.data.file, this._cwd)
|
|
106
|
+
switch (event.type) {
|
|
107
|
+
case 'test:fail':
|
|
108
|
+
this.push(`::error file=${path},line=${event.data.line}::${event.data.name}\n`)
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
callback()
|
|
113
|
+
}
|
|
114
|
+
}
|
package/lib/run.js
CHANGED
|
@@ -17,6 +17,10 @@ function deferred () {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export default async function runWithTypeScript (config) {
|
|
20
|
+
// This is a hack to override
|
|
21
|
+
// https://github.com/nodejs/node/commit/d5c9adf3df
|
|
22
|
+
delete process.env.NODE_TEST_CONTEXT
|
|
23
|
+
|
|
20
24
|
const { cwd } = config
|
|
21
25
|
let pushable = []
|
|
22
26
|
const tsconfigPath = await findUp('tsconfig.json', { cwd })
|
|
@@ -36,6 +40,7 @@ export default async function runWithTypeScript (config) {
|
|
|
36
40
|
if (!config.watch) {
|
|
37
41
|
const start = Date.now()
|
|
38
42
|
await execa('node', [tscPath], { cwd: dirname(tsconfigPath) })
|
|
43
|
+
process.stdout.write(`TypeScript compilation complete (${Date.now() - start}ms)\n`)
|
|
39
44
|
pushable.push({
|
|
40
45
|
type: 'test:diagnostic',
|
|
41
46
|
data: {
|
|
@@ -53,10 +58,18 @@ export default async function runWithTypeScript (config) {
|
|
|
53
58
|
}
|
|
54
59
|
config.prefix = prefix
|
|
55
60
|
config.setup = (test) => {
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
/* c8 ignore next 12 */
|
|
62
|
+
if (test.reporter) {
|
|
63
|
+
for (const chunk of pushable) {
|
|
64
|
+
test.reporter.push(chunk)
|
|
65
|
+
}
|
|
66
|
+
pushable = test.reporter
|
|
67
|
+
} else {
|
|
68
|
+
for (const chunk of pushable) {
|
|
69
|
+
test.push(chunk)
|
|
70
|
+
}
|
|
71
|
+
pushable = test
|
|
58
72
|
}
|
|
59
|
-
pushable = test.reporter
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
let tscChild
|
|
@@ -119,7 +132,7 @@ export default async function runWithTypeScript (config) {
|
|
|
119
132
|
} else if (prefix) {
|
|
120
133
|
files = await glob(join(prefix, join('**', '*.test.{cjs,mjs,js}')), { ignore, cwd, windowsPathsNoEscape: true })
|
|
121
134
|
} else {
|
|
122
|
-
files = await glob(join('**', '*.test.{cjs,mjs,js}'), { ignore, cwd, windowsPathsNoEscape: true })
|
|
135
|
+
files = await glob(join('**', '*.test.{cjs,mjs,js}'), { ignore, cwd, windowsPathsNoEscape: true, absolute: true })
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
config.files = files
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "node:test wrapper with TypeScript support",
|
|
6
6
|
"main": "borp.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"borp": "borp.js"
|
|
9
9
|
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/mcollina/borp"
|
|
13
|
+
},
|
|
10
14
|
"scripts": {
|
|
11
15
|
"clean": "rm -rf fixtures/*/dist .test-*",
|
|
12
16
|
"lint": "standard | snazzy",
|
|
@@ -25,7 +29,7 @@
|
|
|
25
29
|
"typescript": "^5.3.2"
|
|
26
30
|
},
|
|
27
31
|
"dependencies": {
|
|
28
|
-
"c8": "^
|
|
32
|
+
"c8": "^9.0.0",
|
|
29
33
|
"execa": "^8.0.1",
|
|
30
34
|
"find-up": "^7.0.0",
|
|
31
35
|
"glob": "^10.3.10"
|
package/test/basic.test.js
CHANGED
|
@@ -165,3 +165,24 @@ test('only-src', async (t) => {
|
|
|
165
165
|
|
|
166
166
|
await completed
|
|
167
167
|
})
|
|
168
|
+
|
|
169
|
+
test('js-esm', async (t) => {
|
|
170
|
+
const { strictEqual, completed } = tspl(t, { plan: 2 })
|
|
171
|
+
const config = {
|
|
172
|
+
files: [],
|
|
173
|
+
cwd: join(import.meta.url, '..', 'fixtures', 'js-esm')
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const stream = await runWithTypeScript(config)
|
|
177
|
+
|
|
178
|
+
const names = new Set(['add', 'add2'])
|
|
179
|
+
|
|
180
|
+
stream.on('test:pass', (test) => {
|
|
181
|
+
strictEqual(names.has(test.name), true)
|
|
182
|
+
names.delete(test.name)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
stream.resume()
|
|
186
|
+
|
|
187
|
+
await completed
|
|
188
|
+
})
|
package/test/cli.test.js
CHANGED
|
@@ -5,6 +5,8 @@ import { rejects } from 'node:assert'
|
|
|
5
5
|
|
|
6
6
|
const borp = join(import.meta.url, '..', 'borp.js')
|
|
7
7
|
|
|
8
|
+
delete process.env.GITHUB_ACTION
|
|
9
|
+
|
|
8
10
|
test('limit concurrency', async () => {
|
|
9
11
|
await execa('node', [
|
|
10
12
|
borp,
|
|
@@ -23,3 +25,22 @@ test('failing test set correct status code', async () => {
|
|
|
23
25
|
cwd: join(import.meta.url, '..', 'fixtures', 'fails')
|
|
24
26
|
}))
|
|
25
27
|
})
|
|
28
|
+
|
|
29
|
+
test('--expose-gc flag enables garbage collection in tests', async () => {
|
|
30
|
+
await execa('node', [
|
|
31
|
+
borp,
|
|
32
|
+
'--expose-gc'
|
|
33
|
+
], {
|
|
34
|
+
cwd: join(import.meta.url, '..', 'fixtures', 'gc')
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('failing test with --expose-gc flag sets correct status code', async () => {
|
|
39
|
+
// execa rejects if status code is not 0
|
|
40
|
+
await rejects(execa('node', [
|
|
41
|
+
borp,
|
|
42
|
+
'--expose-gc'
|
|
43
|
+
], {
|
|
44
|
+
cwd: join(import.meta.url, '..', 'fixtures', 'fails')
|
|
45
|
+
}))
|
|
46
|
+
})
|
package/test/coverage.test.js
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { MarkdownReporter, GithubWorkflowFailuresReporter } from '../lib/reporters.js'
|
|
2
|
+
import { test, describe } from 'node:test'
|
|
3
|
+
import { strictEqual } from 'node:assert'
|
|
4
|
+
|
|
5
|
+
const cwd = process.platform === 'win32' ? 'C:\\foo' : '/foo'
|
|
6
|
+
const base = process.platform === 'win32' ? 'file://C:\\foo\\test\\' : 'file:///foo/test/'
|
|
7
|
+
|
|
8
|
+
describe('MarkdownReporter', async () => {
|
|
9
|
+
test('should write a report', async () => {
|
|
10
|
+
const reporter = new MarkdownReporter({ cwd })
|
|
11
|
+
|
|
12
|
+
// This is skipped
|
|
13
|
+
reporter.write({
|
|
14
|
+
type: 'test:start',
|
|
15
|
+
data: {}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
reporter.write({
|
|
19
|
+
type: 'test:pass',
|
|
20
|
+
data: {
|
|
21
|
+
name: 'add',
|
|
22
|
+
file: base + 'add.test.ts',
|
|
23
|
+
line: 1,
|
|
24
|
+
details: {
|
|
25
|
+
duration_ms: 100
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
reporter.write({
|
|
31
|
+
type: 'test:pass',
|
|
32
|
+
data: {
|
|
33
|
+
name: 'add2',
|
|
34
|
+
file: base + 'add.test.ts',
|
|
35
|
+
line: 2,
|
|
36
|
+
details: {
|
|
37
|
+
duration_ms: 100
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
reporter.write({
|
|
43
|
+
type: 'test:fail',
|
|
44
|
+
data: {
|
|
45
|
+
name: 'add3',
|
|
46
|
+
file: base + 'add.test.ts',
|
|
47
|
+
line: 10,
|
|
48
|
+
details: {
|
|
49
|
+
duration_ms: 100
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
reporter.end()
|
|
54
|
+
|
|
55
|
+
let output = ''
|
|
56
|
+
for await (const chunk of reporter) {
|
|
57
|
+
output += chunk
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
strictEqual(output.replaceAll('\\', '/'), `# Summary
|
|
61
|
+
## test/add.test.ts
|
|
62
|
+
### :white_check_mark: Pass
|
|
63
|
+
* __add__, duration 100ms, line 1
|
|
64
|
+
* __add2__, duration 100ms, line 2
|
|
65
|
+
### :x: Fail
|
|
66
|
+
* __add3__, duration 100ms, line 10
|
|
67
|
+
`)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('skip fail heading if no failing tests', async () => {
|
|
71
|
+
const reporter = new MarkdownReporter({ cwd })
|
|
72
|
+
|
|
73
|
+
reporter.write({
|
|
74
|
+
type: 'test:pass',
|
|
75
|
+
data: {
|
|
76
|
+
name: 'add',
|
|
77
|
+
file: base + 'add.test.ts',
|
|
78
|
+
line: 1,
|
|
79
|
+
details: {
|
|
80
|
+
duration_ms: 100
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
reporter.write({
|
|
86
|
+
type: 'test:pass',
|
|
87
|
+
data: {
|
|
88
|
+
name: 'add2',
|
|
89
|
+
file: base + 'add.test.ts',
|
|
90
|
+
line: 2,
|
|
91
|
+
details: {
|
|
92
|
+
duration_ms: 100
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
reporter.end()
|
|
98
|
+
|
|
99
|
+
let output = ''
|
|
100
|
+
for await (const chunk of reporter) {
|
|
101
|
+
output += chunk
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
strictEqual(output.replaceAll('\\', '/'), `# Summary
|
|
105
|
+
## test/add.test.ts
|
|
106
|
+
### :white_check_mark: Pass
|
|
107
|
+
* __add__, duration 100ms, line 1
|
|
108
|
+
* __add2__, duration 100ms, line 2
|
|
109
|
+
`)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('GithubWorkflowFailuresReporter', async () => {
|
|
114
|
+
test('should write error in github format', async () => {
|
|
115
|
+
const reporter = new GithubWorkflowFailuresReporter({ cwd })
|
|
116
|
+
|
|
117
|
+
// This is skipped
|
|
118
|
+
reporter.write({
|
|
119
|
+
type: 'test:start',
|
|
120
|
+
data: {}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
reporter.write({
|
|
124
|
+
type: 'test:pass',
|
|
125
|
+
data: {
|
|
126
|
+
name: 'add',
|
|
127
|
+
file: base + 'add.test.ts',
|
|
128
|
+
line: 1,
|
|
129
|
+
details: {
|
|
130
|
+
duration_ms: 100
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
reporter.write({
|
|
136
|
+
type: 'test:fail',
|
|
137
|
+
data: {
|
|
138
|
+
name: 'add2',
|
|
139
|
+
file: base + 'add.test.ts',
|
|
140
|
+
line: 2,
|
|
141
|
+
details: {
|
|
142
|
+
duration_ms: 100
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
reporter.write({
|
|
148
|
+
type: 'test:fail',
|
|
149
|
+
data: {
|
|
150
|
+
name: 'add3',
|
|
151
|
+
file: base + 'add.test.ts',
|
|
152
|
+
line: 10,
|
|
153
|
+
details: {
|
|
154
|
+
duration_ms: 100
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
reporter.end()
|
|
159
|
+
|
|
160
|
+
let output = ''
|
|
161
|
+
for await (const chunk of reporter) {
|
|
162
|
+
output += chunk
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const expected = [
|
|
166
|
+
'::error file=test/add.test.ts,line=2::add2\n',
|
|
167
|
+
'::error file=test/add.test.ts,line=10::add3\n'
|
|
168
|
+
].join('')
|
|
169
|
+
|
|
170
|
+
strictEqual(output.replaceAll('\\', '/'), expected)
|
|
171
|
+
})
|
|
172
|
+
})
|