borp 0.5.0 → 0.7.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 +67 -2
- package/borp.js +48 -10
- 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/fixtures/ts-esm2/src/add.ts +4 -0
- package/fixtures/ts-esm2/test/add.test.ts +7 -0
- package/fixtures/ts-esm2/test/add2.test.ts +7 -0
- package/fixtures/ts-esm2/tsconfig.json +24 -0
- package/lib/reporters.js +114 -0
- package/lib/run.js +18 -5
- package/package.json +6 -2
- package/test/basic.test.js +22 -1
- package/test/cli.test.js +19 -1
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# borp
|
|
2
2
|
|
|
3
|
-
Borp is a typescript-aware runner for
|
|
3
|
+
Borp is a typescript-aware test runner for `node:test`.
|
|
4
4
|
It also support code coverage via [c8](http://npm.im/c8).
|
|
5
5
|
|
|
6
6
|
Borp is self-hosted, i.e. Borp runs its own tests.
|
|
@@ -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
|
|
|
@@ -93,6 +93,71 @@ Note the use of `incremental: true`, which speed up compilation massively.
|
|
|
93
93
|
* `--ignore` or `-i`, ignore a glob pattern, and not look for tests there
|
|
94
94
|
* `--expose-gc`, exposes the gc() function to tests
|
|
95
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
|
+
* `--no-typescript` or `-T`, disable automatic TypeScript compilation if `tsconfig.json` is found.
|
|
98
|
+
|
|
99
|
+
## Reporters
|
|
100
|
+
|
|
101
|
+
Here are the available reporters:
|
|
102
|
+
|
|
103
|
+
* `md`: creates a markdown table, useful for setting up a Summary in your GitHub Action
|
|
104
|
+
* `gh`: emits `::error` workflow commands for GitHub Actions to show inlined error. Enabled by default when running on GHA.
|
|
105
|
+
* `tap`: outputs the test results in the TAP format.
|
|
106
|
+
* `spec`: outputs the test results in a human-readable format.
|
|
107
|
+
* `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.
|
|
108
|
+
* `junit`: outputs test results in a jUnit XML format
|
|
109
|
+
|
|
110
|
+
## GitHub Action Summary
|
|
111
|
+
|
|
112
|
+
The following will automatically show the summary of the test run in the summary page of GitHub Actions.
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
name: ci
|
|
116
|
+
|
|
117
|
+
on:
|
|
118
|
+
push:
|
|
119
|
+
paths-ignore:
|
|
120
|
+
- 'docs/**'
|
|
121
|
+
- '*.md'
|
|
122
|
+
pull_request:
|
|
123
|
+
paths-ignore:
|
|
124
|
+
- 'docs/**'
|
|
125
|
+
- '*.md'
|
|
126
|
+
|
|
127
|
+
jobs:
|
|
128
|
+
test:
|
|
129
|
+
runs-on: ${{matrix.os}}
|
|
130
|
+
|
|
131
|
+
strategy:
|
|
132
|
+
matrix:
|
|
133
|
+
node-version: [18.x, 20.x, 21.x]
|
|
134
|
+
os: [ubuntu-latest, windows-latest]
|
|
135
|
+
steps:
|
|
136
|
+
- uses: actions/checkout@v4
|
|
137
|
+
|
|
138
|
+
- name: Use Node.js
|
|
139
|
+
uses: actions/setup-node@v4
|
|
140
|
+
with:
|
|
141
|
+
node-version: ${{ matrix.node-version }}
|
|
142
|
+
|
|
143
|
+
- name: Install
|
|
144
|
+
run: |
|
|
145
|
+
npm install
|
|
146
|
+
|
|
147
|
+
- name: Lint
|
|
148
|
+
run: |
|
|
149
|
+
npm run lint
|
|
150
|
+
|
|
151
|
+
- name: Run tests
|
|
152
|
+
run: |
|
|
153
|
+
npm run unit -- --reporter spec --reporter md:report.md
|
|
154
|
+
|
|
155
|
+
- name: Upload report
|
|
156
|
+
shell: bash
|
|
157
|
+
if: success() || failure()
|
|
158
|
+
run: |
|
|
159
|
+
cat report.md >> "$GITHUB_STEP_SUMMARY"
|
|
160
|
+
```
|
|
96
161
|
|
|
97
162
|
## License
|
|
98
163
|
|
package/borp.js
CHANGED
|
@@ -1,24 +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'
|
|
12
14
|
import { execa } from 'execa'
|
|
13
15
|
|
|
14
|
-
let reporter
|
|
15
16
|
/* c8 ignore next 4 */
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
reporter = tap
|
|
21
|
-
}
|
|
17
|
+
process.on('unhandledRejection', (err) => {
|
|
18
|
+
console.error(err)
|
|
19
|
+
process.exit(1)
|
|
20
|
+
})
|
|
22
21
|
|
|
23
22
|
const args = parseArgs({
|
|
24
23
|
args: process.argv.slice(2),
|
|
@@ -32,7 +31,14 @@ const args = parseArgs({
|
|
|
32
31
|
'coverage-exclude': { type: 'string', short: 'X', multiple: true },
|
|
33
32
|
ignore: { type: 'string', short: 'i', multiple: true },
|
|
34
33
|
'expose-gc': { type: 'boolean' },
|
|
35
|
-
help: { type: 'boolean', short: 'h' }
|
|
34
|
+
help: { type: 'boolean', short: 'h' },
|
|
35
|
+
'no-typescript': { type: 'boolean', short: 'T' },
|
|
36
|
+
reporter: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
short: 'r',
|
|
39
|
+
default: ['spec'],
|
|
40
|
+
multiple: true
|
|
41
|
+
}
|
|
36
42
|
},
|
|
37
43
|
allowPositionals: true
|
|
38
44
|
})
|
|
@@ -73,19 +79,51 @@ if (args.values.coverage) {
|
|
|
73
79
|
|
|
74
80
|
const config = {
|
|
75
81
|
...args.values,
|
|
82
|
+
typescript: !args.values['no-typescript'],
|
|
76
83
|
files: args.positionals,
|
|
77
84
|
pattern: args.values.pattern,
|
|
78
85
|
cwd: process.cwd()
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
try {
|
|
89
|
+
const pipes = []
|
|
90
|
+
|
|
91
|
+
const reporters = {
|
|
92
|
+
...Reporters,
|
|
93
|
+
md: new MarkdownReporter(config),
|
|
94
|
+
gh: new GithubWorkflowFailuresReporter(config),
|
|
95
|
+
/* eslint new-cap: "off" */
|
|
96
|
+
spec: new Reporters.spec()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If we're running in a GitHub action, adds the gh reporter
|
|
100
|
+
// by default so that we can report failures to GitHub
|
|
101
|
+
if (process.env.GITHUB_ACTION) {
|
|
102
|
+
args.values.reporter.push('gh')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const input of args.values.reporter) {
|
|
106
|
+
const [name, dest] = input.split(':')
|
|
107
|
+
const reporter = reporters[name]
|
|
108
|
+
if (!reporter) {
|
|
109
|
+
throw new Error(`Unknown reporter: ${name}`)
|
|
110
|
+
}
|
|
111
|
+
let output = process.stdout
|
|
112
|
+
if (dest) {
|
|
113
|
+
output = createWriteStream(dest)
|
|
114
|
+
}
|
|
115
|
+
pipes.push([reporter, output])
|
|
116
|
+
}
|
|
117
|
+
|
|
82
118
|
const stream = await runWithTypeScript(config)
|
|
83
119
|
|
|
84
120
|
stream.on('test:fail', () => {
|
|
85
121
|
process.exitCode = 1
|
|
86
122
|
})
|
|
87
123
|
|
|
88
|
-
|
|
124
|
+
for (const [reporter, output] of pipes) {
|
|
125
|
+
stream.compose(reporter).pipe(output)
|
|
126
|
+
}
|
|
89
127
|
|
|
90
128
|
await finished(stream)
|
|
91
129
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"sourceMap": true,
|
|
6
|
+
"target": "ES2022",
|
|
7
|
+
"module": "NodeNext",
|
|
8
|
+
"moduleResolution": "NodeNext",
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"removeComments": true,
|
|
13
|
+
"newLine": "lf",
|
|
14
|
+
"noUnusedLocals": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"forceConsistentCasingInFileNames": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"lib": [
|
|
20
|
+
"ESNext"
|
|
21
|
+
],
|
|
22
|
+
"incremental": true
|
|
23
|
+
}
|
|
24
|
+
}
|
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
|
@@ -28,7 +28,7 @@ export default async function runWithTypeScript (config) {
|
|
|
28
28
|
let prefix = ''
|
|
29
29
|
let tscPath
|
|
30
30
|
|
|
31
|
-
if (tsconfigPath) {
|
|
31
|
+
if (tsconfigPath && config.typescript !== false) {
|
|
32
32
|
const _require = createRequire(tsconfigPath)
|
|
33
33
|
const typescriptPathCWD = _require.resolve('typescript')
|
|
34
34
|
tscPath = join(typescriptPathCWD, '..', '..', 'bin', 'tsc')
|
|
@@ -56,12 +56,25 @@ export default async function runWithTypeScript (config) {
|
|
|
56
56
|
prefix = join(dirname(tsconfigPath), outDir)
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
// TODO remove those and create a new object
|
|
61
|
+
delete config.typescript
|
|
62
|
+
delete config['no-typescript']
|
|
63
|
+
|
|
59
64
|
config.prefix = prefix
|
|
60
65
|
config.setup = (test) => {
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
/* c8 ignore next 12 */
|
|
67
|
+
if (test.reporter) {
|
|
68
|
+
for (const chunk of pushable) {
|
|
69
|
+
test.reporter.push(chunk)
|
|
70
|
+
}
|
|
71
|
+
pushable = test.reporter
|
|
72
|
+
} else {
|
|
73
|
+
for (const chunk of pushable) {
|
|
74
|
+
test.push(chunk)
|
|
75
|
+
}
|
|
76
|
+
pushable = test
|
|
63
77
|
}
|
|
64
|
-
pushable = test.reporter
|
|
65
78
|
}
|
|
66
79
|
|
|
67
80
|
let tscChild
|
|
@@ -124,7 +137,7 @@ export default async function runWithTypeScript (config) {
|
|
|
124
137
|
} else if (prefix) {
|
|
125
138
|
files = await glob(join(prefix, join('**', '*.test.{cjs,mjs,js}')), { ignore, cwd, windowsPathsNoEscape: true })
|
|
126
139
|
} else {
|
|
127
|
-
files = await glob(join('**', '*.test.{cjs,mjs,js}'), { ignore, cwd, windowsPathsNoEscape: true })
|
|
140
|
+
files = await glob(join('**', '*.test.{cjs,mjs,js}'), { ignore, cwd, windowsPathsNoEscape: true, absolute: true })
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
config.files = files
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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
|
@@ -46,7 +46,7 @@ test('ts-cjs', async (t) => {
|
|
|
46
46
|
await completed
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
test('ts-esm with named
|
|
49
|
+
test('ts-esm with named files', async (t) => {
|
|
50
50
|
const { strictEqual, completed, match } = tspl(t, { plan: 3 })
|
|
51
51
|
const config = {
|
|
52
52
|
files: ['test/add.test.ts'],
|
|
@@ -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
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { test } from 'node:test'
|
|
2
2
|
import { execa } from 'execa'
|
|
3
3
|
import { join } from 'desm'
|
|
4
|
-
import { rejects } from 'node:assert'
|
|
4
|
+
import { rejects, strictEqual } from 'node:assert'
|
|
5
|
+
import { rm } from 'node:fs/promises'
|
|
6
|
+
import path from 'node:path'
|
|
5
7
|
|
|
6
8
|
const borp = join(import.meta.url, '..', 'borp.js')
|
|
7
9
|
|
|
10
|
+
delete process.env.GITHUB_ACTION
|
|
11
|
+
|
|
8
12
|
test('limit concurrency', async () => {
|
|
9
13
|
await execa('node', [
|
|
10
14
|
borp,
|
|
@@ -42,3 +46,17 @@ test('failing test with --expose-gc flag sets correct status code', async () =>
|
|
|
42
46
|
cwd: join(import.meta.url, '..', 'fixtures', 'fails')
|
|
43
47
|
}))
|
|
44
48
|
})
|
|
49
|
+
|
|
50
|
+
test('disable ts and run no tests', async () => {
|
|
51
|
+
const cwd = join(import.meta.url, '..', 'fixtures', 'ts-esm2')
|
|
52
|
+
await rm(path.join(cwd, 'dist'), { recursive: true, force: true })
|
|
53
|
+
const { stdout } = await execa('node', [
|
|
54
|
+
borp,
|
|
55
|
+
'--reporter=spec',
|
|
56
|
+
'--no-typescript'
|
|
57
|
+
], {
|
|
58
|
+
cwd
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
strictEqual(stdout.indexOf('tests 0') >= 0, true)
|
|
62
|
+
})
|
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
|
+
})
|