borp 0.7.0 → 0.9.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 +1 -7
- package/README.md +1 -54
- package/borp.js +4 -9
- package/package.json +3 -1
- package/test/cli.test.js +15 -0
- package/lib/reporters.js +0 -114
- package/test/reporters.test.js +0 -172
package/.github/workflows/ci.yml
CHANGED
|
@@ -36,10 +36,4 @@ jobs:
|
|
|
36
36
|
|
|
37
37
|
- name: Run tests
|
|
38
38
|
run: |
|
|
39
|
-
npm run unit -- --reporter spec
|
|
40
|
-
|
|
41
|
-
- name: Upload report
|
|
42
|
-
shell: bash
|
|
43
|
-
if: success() || failure()
|
|
44
|
-
run: |
|
|
45
|
-
cat report.md >> "$GITHUB_STEP_SUMMARY"
|
|
39
|
+
npm run unit -- --reporter spec
|
package/README.md
CHANGED
|
@@ -100,65 +100,12 @@ Note the use of `incremental: true`, which speed up compilation massively.
|
|
|
100
100
|
|
|
101
101
|
Here are the available reporters:
|
|
102
102
|
|
|
103
|
-
* `
|
|
104
|
-
* `gh`: emits `::error` workflow commands for GitHub Actions to show inlined error. Enabled by default when running on GHA.
|
|
103
|
+
* `gh`: emits `::error` workflow commands for GitHub Actions to show inlined errors. Enabled by default when running on GHA.
|
|
105
104
|
* `tap`: outputs the test results in the TAP format.
|
|
106
105
|
* `spec`: outputs the test results in a human-readable format.
|
|
107
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.
|
|
108
107
|
* `junit`: outputs test results in a jUnit XML format
|
|
109
108
|
|
|
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
|
-
```
|
|
161
|
-
|
|
162
109
|
## License
|
|
163
110
|
|
|
164
111
|
MIT
|
package/borp.js
CHANGED
|
@@ -8,7 +8,7 @@ import { finished } from 'node:stream/promises'
|
|
|
8
8
|
import { join, relative } from 'node:path'
|
|
9
9
|
import posix from 'node:path/posix'
|
|
10
10
|
import runWithTypeScript from './lib/run.js'
|
|
11
|
-
import
|
|
11
|
+
import githubReporter from '@reporters/github'
|
|
12
12
|
import { Report } from 'c8'
|
|
13
13
|
import os from 'node:os'
|
|
14
14
|
import { execa } from 'execa'
|
|
@@ -90,10 +90,7 @@ try {
|
|
|
90
90
|
|
|
91
91
|
const reporters = {
|
|
92
92
|
...Reporters,
|
|
93
|
-
|
|
94
|
-
gh: new GithubWorkflowFailuresReporter(config),
|
|
95
|
-
/* eslint new-cap: "off" */
|
|
96
|
-
spec: new Reporters.spec()
|
|
93
|
+
gh: githubReporter
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
// If we're running in a GitHub action, adds the gh reporter
|
|
@@ -104,10 +101,8 @@ try {
|
|
|
104
101
|
|
|
105
102
|
for (const input of args.values.reporter) {
|
|
106
103
|
const [name, dest] = input.split(':')
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
throw new Error(`Unknown reporter: ${name}`)
|
|
110
|
-
}
|
|
104
|
+
const Ctor = reporters[name] || await import(name).then((m) => m.default || m)
|
|
105
|
+
const reporter = Object.getOwnPropertyDescriptor(Ctor.prototype, 'constructor') ? new Ctor() : Ctor
|
|
111
106
|
let output = process.stdout
|
|
112
107
|
if (dest) {
|
|
113
108
|
output = createWriteStream(dest)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "node:test wrapper with TypeScript support",
|
|
6
6
|
"main": "borp.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@matteo.collina/tspl": "^0.1.0",
|
|
25
|
+
"@reporters/silent": "^1.2.4",
|
|
25
26
|
"@types/node": "^20.10.0",
|
|
26
27
|
"desm": "^1.3.0",
|
|
27
28
|
"snazzy": "^9.0.0",
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"typescript": "^5.3.2"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
33
|
+
"@reporters/github": "^1.5.4",
|
|
32
34
|
"c8": "^9.0.0",
|
|
33
35
|
"execa": "^8.0.1",
|
|
34
36
|
"find-up": "^7.0.0",
|
package/test/cli.test.js
CHANGED
|
@@ -60,3 +60,18 @@ test('disable ts and run no tests', async () => {
|
|
|
60
60
|
|
|
61
61
|
strictEqual(stdout.indexOf('tests 0') >= 0, true)
|
|
62
62
|
})
|
|
63
|
+
|
|
64
|
+
test('reporter from node_modules', async () => {
|
|
65
|
+
const cwd = join(import.meta.url, '..', 'fixtures', 'ts-esm2')
|
|
66
|
+
await rm(path.join(cwd, 'dist'), { recursive: true, force: true })
|
|
67
|
+
const { stdout } = await execa('node', [
|
|
68
|
+
borp,
|
|
69
|
+
'--reporter=spec',
|
|
70
|
+
'--reporter=@reporters/silent',
|
|
71
|
+
'--no-typescript'
|
|
72
|
+
], {
|
|
73
|
+
cwd
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
strictEqual(stdout.indexOf('tests 0') >= 0, true)
|
|
77
|
+
})
|
package/lib/reporters.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
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/test/reporters.test.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
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
|
-
})
|