@small-tech/tap-monkey 1.3.0 → 1.5.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/CHANGELOG.md +16 -0
- package/README.md +16 -0
- package/index.js +41 -29
- package/jsconfig.json +14 -0
- package/package.json +11 -5
- package/tests/index.js +295 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.5.0] - 2025-12-29
|
|
8
|
+
|
|
9
|
+
Maintenance monkey.
|
|
10
|
+
|
|
11
|
+
- Update all dependencies.
|
|
12
|
+
- Fix failing test.
|
|
13
|
+
- Remove all vulnerability warnings.
|
|
14
|
+
|
|
15
|
+
## [1.4.0] - 2022-05-24
|
|
16
|
+
|
|
17
|
+
Testy monkey.
|
|
18
|
+
|
|
19
|
+
## Added
|
|
20
|
+
|
|
21
|
+
- 100% code coverage. Now using tape and *drumroll* Tap Monkey itself for the tests.
|
|
22
|
+
|
|
7
23
|
## [1.3.0] - 2021-03-05
|
|
8
24
|
|
|
9
25
|
Debug monkey.
|
package/README.md
CHANGED
|
@@ -107,6 +107,22 @@ export default function log (...args) {
|
|
|
107
107
|
|
|
108
108
|
If your test runner (e.g., [ESM Tape Runner](https://github.com/small-tech/esm-tape-runner)) encounters an error in your app’s source code (e.g., a syntax error in one of your classes), it should bail out (and hopefully also log the error so you know what it is). Tap Monkey will respond to bail out events by displaying them and exiting (your test runner should have exit also so you should not get any pipe errors).
|
|
109
109
|
|
|
110
|
+
## Testing Tap Monkey
|
|
111
|
+
|
|
112
|
+
Tap Monkey itself, of course, comes with unit tests displayed by none other than _\*drumroll\*_ Tap Monkey!
|
|
113
|
+
|
|
114
|
+
### Run tests
|
|
115
|
+
|
|
116
|
+
```shell
|
|
117
|
+
npm run -s test
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Run coverage
|
|
121
|
+
|
|
122
|
+
```shell
|
|
123
|
+
npm run -s coverage
|
|
124
|
+
```
|
|
125
|
+
|
|
110
126
|
## Like this? Fund us!
|
|
111
127
|
|
|
112
128
|
[Small Technology Foundation](https://small-tech.org) is a tiny, independent not-for-profit.
|
package/index.js
CHANGED
|
@@ -12,34 +12,35 @@
|
|
|
12
12
|
//
|
|
13
13
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import ora from 'ora'
|
|
16
16
|
import chalk from 'chalk'
|
|
17
17
|
import { performance } from 'perf_hooks'
|
|
18
18
|
import tapOut from '@small-tech/tap-out'
|
|
19
|
-
|
|
20
|
-
let hasFailures = false
|
|
19
|
+
import os from 'os'
|
|
21
20
|
|
|
22
21
|
// The formatter has a --quiet option that stops status updates being
|
|
23
22
|
// printed until there is a failure or until the aggregate statistics is
|
|
24
23
|
// being shown. People using screen readers and other assistive technologies
|
|
25
24
|
// might want to use this if the number of status updates becomes overwhelming.
|
|
26
|
-
|
|
25
|
+
export const context = {
|
|
26
|
+
quiet: (process.argv.length === 3 && process.argv[2] === '--quiet')
|
|
27
|
+
}
|
|
27
28
|
|
|
28
29
|
// Due to the 300ms frame duration of the monkey animation, not every
|
|
29
30
|
// status update we receive about new test suites and test passes will be
|
|
30
31
|
// reflected in the spinner text and that’s ok. Failures, of course, are
|
|
31
32
|
// all output in full to the terminal.
|
|
32
33
|
const indentedMonkey = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
interval: 300,
|
|
35
|
+
frames: [
|
|
36
|
+
' 🙈 ',
|
|
37
|
+
' 🙈 ',
|
|
38
|
+
' 🙉 ',
|
|
39
|
+
' 🙊 '
|
|
39
40
|
]
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
const spinner =
|
|
43
|
+
const spinner = ora({
|
|
43
44
|
spinner: indentedMonkey,
|
|
44
45
|
discardStdin: false,
|
|
45
46
|
text: 'Running tests…'
|
|
@@ -54,23 +55,22 @@ let printingCoverage = false
|
|
|
54
55
|
let coverageBorderCount = 0
|
|
55
56
|
let currentTest = ''
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
currentTest = test.name
|
|
61
|
-
spinner.text = `Running ${chalk.underline(currentTest)} tests`
|
|
58
|
+
const passHandler = (assert => {
|
|
59
|
+
if (!context.quiet) {
|
|
60
|
+
spinner.text = `${chalk.green('✔')} ${assert.name}`
|
|
62
61
|
}
|
|
63
62
|
})
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const testHandler = (test => {
|
|
65
|
+
spinner.start()
|
|
66
|
+
if (!context.quiet) {
|
|
67
|
+
currentTest = test.name
|
|
68
|
+
spinner.text = `Running ${chalk.underline(currentTest)} tests`
|
|
68
69
|
}
|
|
69
70
|
})
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
const failHandler = (assert => {
|
|
72
73
|
// Stop the spinner and output failures in full.
|
|
73
|
-
hasFailures = true
|
|
74
74
|
spinner.stop()
|
|
75
75
|
|
|
76
76
|
const e = assert.error
|
|
@@ -80,18 +80,18 @@ parser.on('fail', assert => {
|
|
|
80
80
|
if (e.operator !== undefined) console.log(` operator:`, e.operator)
|
|
81
81
|
if (e.expected !== undefined) console.log(` ${chalk.green(`expected: ${e.expected}`)}`)
|
|
82
82
|
if (e.actual !== undefined) console.log(` ${chalk.red(`actual : ${e.actual}`)}`)
|
|
83
|
-
if (e.at !== undefined) console.log(` ${chalk.yellow(`at : ${e.at}`)}`)
|
|
83
|
+
if (e.at !== undefined) console.log(` ${chalk.yellow(`at : ${e.at.file.replace(os.homedir(), '~')}:${e.at.line}:${e.at.character}`)}`)
|
|
84
84
|
|
|
85
85
|
console.log()
|
|
86
86
|
|
|
87
87
|
e.stack.split('\n').forEach(line => {
|
|
88
|
-
console.log(' ', chalk.
|
|
88
|
+
console.log(' ', chalk.red(line))
|
|
89
89
|
})
|
|
90
90
|
|
|
91
91
|
spinner.start()
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
const bailOutHandler = (event => {
|
|
95
95
|
// If the test runner has emitted a bail out event, it has signaled
|
|
96
96
|
// that it cannot continue. So we notify the person and exit.
|
|
97
97
|
spinner.stop()
|
|
@@ -100,10 +100,10 @@ parser.on('bailOut', event => {
|
|
|
100
100
|
process.exit(1)
|
|
101
101
|
})
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
const commentHandler = (comment => {
|
|
104
104
|
spinner.stop()
|
|
105
105
|
let commentText = comment.raw
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
const isCoverageBorder = commentText.startsWith('----')
|
|
108
108
|
if (isCoverageBorder) { printingCoverage = true }
|
|
109
109
|
|
|
@@ -125,12 +125,12 @@ parser.on('comment', comment => {
|
|
|
125
125
|
} else {
|
|
126
126
|
// We aren’t printing coverage yet so this must be a regular TAP comment.
|
|
127
127
|
// Display it fully.
|
|
128
|
-
console.log(chalk.yellow(' 🢂 '),commentText.trim())
|
|
128
|
+
console.log(chalk.yellow(' 🢂 '), commentText.trim())
|
|
129
129
|
spinner.start()
|
|
130
130
|
}
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
const outputHandler = (results => {
|
|
134
134
|
const duration = ((performance.now() - startTime)/1000).toFixed(2)
|
|
135
135
|
spinner.stop()
|
|
136
136
|
|
|
@@ -138,7 +138,9 @@ parser.on('output', results => {
|
|
|
138
138
|
const passing = results.pass.length
|
|
139
139
|
const failing = results.fail.length
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
// TODO: Handle edge case of zero total tests.
|
|
142
|
+
|
|
143
|
+
if (failing > 0) {
|
|
142
144
|
console.log(` 🙊️ ${chalk.magenta('There are failed tests.')}`)
|
|
143
145
|
} else {
|
|
144
146
|
console.log(` 🍌️ ${chalk.green('All tests passing!')}`)
|
|
@@ -150,3 +152,13 @@ parser.on('output', results => {
|
|
|
150
152
|
console.log(chalk.red( ` Failing ${failing}`))
|
|
151
153
|
console.log(chalk.gray( ` Duration ${duration} secs`))
|
|
152
154
|
})
|
|
155
|
+
|
|
156
|
+
parser.on('test', testHandler)
|
|
157
|
+
parser.on('pass', passHandler)
|
|
158
|
+
parser.on('fail', failHandler)
|
|
159
|
+
parser.on('bailOut', bailOutHandler)
|
|
160
|
+
parser.on('comment', commentHandler)
|
|
161
|
+
parser.on('output', outputHandler)
|
|
162
|
+
|
|
163
|
+
export default { testHandler, passHandler, failHandler, bailOutHandler, commentHandler, outputHandler, parser, spinner }
|
|
164
|
+
|
package/jsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"checkJs": true,
|
|
4
|
+
"module": "nodenext",
|
|
5
|
+
"lib": ["es2024", "dom"],
|
|
6
|
+
"target": "es2024",
|
|
7
|
+
"moduleResolution": "nodenext",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"skipLibCheck": true
|
|
12
|
+
},
|
|
13
|
+
"exclude": ["node_modules"]
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@small-tech/tap-monkey",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A tap formatter that’s also a monkey.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tap",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"tap-monkey": "./index.js"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"test": "
|
|
22
|
+
"test": "tape tests/index.js | node index.js",
|
|
23
|
+
"coverage": "c8 tape tests/index.js | node index.js"
|
|
23
24
|
},
|
|
24
25
|
"author": {
|
|
25
26
|
"name": "Aral Balkan",
|
|
@@ -33,8 +34,13 @@
|
|
|
33
34
|
"url": "https://github.com/small-tech/tap-monkey.git"
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
|
-
"@small-tech/tap-out": "^3.
|
|
37
|
-
"chalk": "^
|
|
38
|
-
"ora": "^
|
|
37
|
+
"@small-tech/tap-out": "^3.3.0",
|
|
38
|
+
"chalk": "^5.6.2",
|
|
39
|
+
"ora": "^9.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"c8": "^10.1.3",
|
|
43
|
+
"strip-ansi": "^7.1.2",
|
|
44
|
+
"tape": "^5.9.0"
|
|
39
45
|
}
|
|
40
46
|
}
|
package/tests/index.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import test from 'tape'
|
|
2
|
+
import tapMonkey from '../index.js'
|
|
3
|
+
import { context } from '../index.js'
|
|
4
|
+
import strip from 'strip-ansi'
|
|
5
|
+
|
|
6
|
+
// Since Tap Monkey pipes stdin, this will leave a handle open.
|
|
7
|
+
// We have to destroy stdin when all tests are done for the
|
|
8
|
+
// runner to exit properly.
|
|
9
|
+
// See https://github.com/nodejs/node/issues/32291
|
|
10
|
+
|
|
11
|
+
test.onFinish(() => {
|
|
12
|
+
process.stdin.destroy()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
// Test handler and general tests.
|
|
17
|
+
//
|
|
18
|
+
|
|
19
|
+
test('test handler', t => {
|
|
20
|
+
context.quiet = false
|
|
21
|
+
tapMonkey.testHandler({name: 'mock'})
|
|
22
|
+
tapMonkey.spinner.stop()
|
|
23
|
+
|
|
24
|
+
t.strictEquals(tapMonkey.spinner.interval, 300, 'spinner interval is as expected')
|
|
25
|
+
t.strictEquals(tapMonkey.spinner.spinner.frames[0], ' 🙈 ', 'animation frame 1 is correct')
|
|
26
|
+
t.strictEquals(tapMonkey.spinner.spinner.frames[1], ' 🙈 ', 'animation frame 2 is correct')
|
|
27
|
+
t.strictEquals(tapMonkey.spinner.spinner.frames[2], ' 🙉 ', 'animation frame 3 is correct')
|
|
28
|
+
t.strictEquals(tapMonkey.spinner.spinner.frames[3], ' 🙊 ', 'animation frame 4 is correct')
|
|
29
|
+
|
|
30
|
+
t.true(strip(tapMonkey.spinner.text).includes('Running mock tests'), 'test name is displayed correctly')
|
|
31
|
+
|
|
32
|
+
context.quiet = true
|
|
33
|
+
tapMonkey.testHandler({name: 'quiet mock'})
|
|
34
|
+
tapMonkey.spinner.stop()
|
|
35
|
+
|
|
36
|
+
t.false(strip(tapMonkey.spinner.text).includes('Running quiet mock tests'), 'test name not displayed in quiet mode')
|
|
37
|
+
|
|
38
|
+
t.end()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
//
|
|
42
|
+
// Pass handler tests.
|
|
43
|
+
//
|
|
44
|
+
|
|
45
|
+
test('pass handler', t => {
|
|
46
|
+
// Quiet passes (the default)
|
|
47
|
+
context.quiet = true
|
|
48
|
+
const quietPass = 'a quiet pass'
|
|
49
|
+
tapMonkey.passHandler({ name: quietPass })
|
|
50
|
+
t.false(tapMonkey.spinner.text.includes(quietPass), 'quiet mode should not display passed tests')
|
|
51
|
+
|
|
52
|
+
// Loud passes.
|
|
53
|
+
context.quiet = false
|
|
54
|
+
const loudPass = 'a loud pass'
|
|
55
|
+
tapMonkey.passHandler({ name: loudPass })
|
|
56
|
+
t.true(tapMonkey.spinner.text.includes(loudPass), 'passed tests should display when quiet mode is off')
|
|
57
|
+
|
|
58
|
+
t.end()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
//
|
|
62
|
+
// Fail handler tests.
|
|
63
|
+
//
|
|
64
|
+
|
|
65
|
+
test('fail handler', t => {
|
|
66
|
+
// Capture console log temporarily.
|
|
67
|
+
const originalConsoleLog = console.log
|
|
68
|
+
let output = ''
|
|
69
|
+
const capturedConsoleLog = (...args) => output += args.join(' ')
|
|
70
|
+
console.log = capturedConsoleLog
|
|
71
|
+
|
|
72
|
+
const mockAssertionWithTypeError = {
|
|
73
|
+
type: 'assert',
|
|
74
|
+
raw: 'not ok 2 TypeError: Cannot convert undefined or null to object',
|
|
75
|
+
ok: false,
|
|
76
|
+
number: 2,
|
|
77
|
+
name: 'TypeError: Cannot convert undefined or null to object',
|
|
78
|
+
error: {
|
|
79
|
+
operator: 'error',
|
|
80
|
+
expected: undefined,
|
|
81
|
+
actual: undefined,
|
|
82
|
+
at: {
|
|
83
|
+
file: '/var/home/aral/Projects/nodekit/node_modules/tape-promise/node_modules/onetime/index.js',
|
|
84
|
+
line: '30',
|
|
85
|
+
character: '12'
|
|
86
|
+
},
|
|
87
|
+
stack: 'TypeError: Cannot convert undefined or null to object\n' +
|
|
88
|
+
'at Function.keys (<anonymous>)\n' +
|
|
89
|
+
'at sortResults (file:///var/home/aral/Projects/nodekit/tests/files.js:17:10)\n' +
|
|
90
|
+
'at file:///var/home/aral/Projects/nodekit/tests/files.js:101:58\n' +
|
|
91
|
+
'at processTicksAndRejections (node:internal/process/task_queues:96:5)\n',
|
|
92
|
+
raw: ' operator: error\n' +
|
|
93
|
+
' at: bound (/var/home/aral/Projects/nodekit/node_modules/tape-promise/node_modules/onetime/index.js:30:12)\n' +
|
|
94
|
+
' stack: |-\n' +
|
|
95
|
+
'TypeError: Cannot convert undefined or null to object\n' +
|
|
96
|
+
'at Function.keys (<anonymous>)\n' +
|
|
97
|
+
'at sortResults (file:///var/home/aral/Projects/nodekit/tests/files.js:17:10)\n' +
|
|
98
|
+
'at file:///var/home/aral/Projects/nodekit/tests/files.js:101:58\n' +
|
|
99
|
+
'at processTicksAndRejections (node:internal/process/task_queues:96:5)'
|
|
100
|
+
},
|
|
101
|
+
test: 10
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tapMonkey.failHandler(mockAssertionWithTypeError)
|
|
105
|
+
tapMonkey.spinner.stop()
|
|
106
|
+
console.log = originalConsoleLog
|
|
107
|
+
|
|
108
|
+
t.true(output.includes('TypeError: Cannot convert undefined or null to object'), 'output includes main error message')
|
|
109
|
+
t.true(output.includes('/var/home/aral/Projects/nodekit/node_modules/tape-promise/node_modules/onetime/index.js:30:12'), 'error location shown')
|
|
110
|
+
|
|
111
|
+
// Test a regular assertion failure.
|
|
112
|
+
|
|
113
|
+
output = ''
|
|
114
|
+
console.log = capturedConsoleLog
|
|
115
|
+
|
|
116
|
+
const regularFailedAssertion = {
|
|
117
|
+
type: 'assert',
|
|
118
|
+
raw: 'not ok 8 quiet mode should not display passed tests',
|
|
119
|
+
ok: false,
|
|
120
|
+
number: 8,
|
|
121
|
+
name: 'quiet mode should not display passed tests',
|
|
122
|
+
error: {
|
|
123
|
+
operator: 'ok',
|
|
124
|
+
expected: 'true',
|
|
125
|
+
actual: 'false',
|
|
126
|
+
at: undefined,
|
|
127
|
+
stack: 'Error: quiet mode should not display passed tests\n' +
|
|
128
|
+
'at Test.assert [as _assert] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:314:54)\n' +
|
|
129
|
+
'at Test.bound [as _assert] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
130
|
+
'at Test.assert (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:433:10)\n' +
|
|
131
|
+
'at Test.bound [as true] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
132
|
+
'at Test.<anonymous> (file:///var/home/aral/Projects/tap-monkey/tests/index.js:50:9)\n' +
|
|
133
|
+
'at Test.bound [as _cb] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
134
|
+
'at Test.run (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:117:31)\n' +
|
|
135
|
+
'at Test.bound [as run] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
136
|
+
'at Immediate.next [as _onImmediate] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/results.js:88:19)\n' +
|
|
137
|
+
'at processImmediate (node:internal/timers:466:21)\n',
|
|
138
|
+
raw: ' operator: ok\n' +
|
|
139
|
+
' expected: true\n' +
|
|
140
|
+
' actual: false\n' +
|
|
141
|
+
' stack: |-\n' +
|
|
142
|
+
'Error: quiet mode should not display passed tests\n' +
|
|
143
|
+
'at Test.assert [as _assert] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:314:54)\n' +
|
|
144
|
+
'at Test.bound [as _assert] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
145
|
+
'at Test.assert (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:433:10)\n' +
|
|
146
|
+
'at Test.bound [as true] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
147
|
+
'at Test.<anonymous> (file:///var/home/aral/Projects/tap-monkey/tests/index.js:50:9)\n' +
|
|
148
|
+
'at Test.bound [as _cb] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
149
|
+
'at Test.run (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:117:31)\n' +
|
|
150
|
+
'at Test.bound [as run] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/test.js:99:32)\n' +
|
|
151
|
+
'at Immediate.next [as _onImmediate] (/var/home/aral/Projects/tap-monkey/node_modules/tape/lib/results.js:88:19)\n' +
|
|
152
|
+
'at processImmediate (node:internal/timers:466:21)'
|
|
153
|
+
},
|
|
154
|
+
test: 2
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
tapMonkey.failHandler(regularFailedAssertion)
|
|
158
|
+
tapMonkey.spinner.stop()
|
|
159
|
+
console.log = originalConsoleLog
|
|
160
|
+
|
|
161
|
+
t.true(output.includes('operator: ok'), 'output should include operator')
|
|
162
|
+
t.true(output.includes('expected: true'), 'output should include expected field')
|
|
163
|
+
t.true(output.includes('actual : false'), 'output should include actual field')
|
|
164
|
+
|
|
165
|
+
t.end()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
//
|
|
169
|
+
// Bail out handler tests.
|
|
170
|
+
//
|
|
171
|
+
|
|
172
|
+
test('bailout handler', t => {
|
|
173
|
+
// Setup.
|
|
174
|
+
const _error = console.error
|
|
175
|
+
let output = ''
|
|
176
|
+
console.error = string => output += string
|
|
177
|
+
|
|
178
|
+
const _exit = process.exit
|
|
179
|
+
let exitCalledWithCorrectCode = false
|
|
180
|
+
process.exit = code => exitCalledWithCorrectCode = code === 1
|
|
181
|
+
|
|
182
|
+
// Test.
|
|
183
|
+
tapMonkey.spinner.start()
|
|
184
|
+
const mockRaw = 'mock raw event contents'
|
|
185
|
+
tapMonkey.bailOutHandler({ raw: mockRaw })
|
|
186
|
+
|
|
187
|
+
t.strictEquals(tapMonkey.spinner.isSpinning, false, 'spinner has stopped')
|
|
188
|
+
t.true(output.includes(mockRaw), 'output includes mock event raw string')
|
|
189
|
+
t.true(exitCalledWithCorrectCode, 'exit is called')
|
|
190
|
+
|
|
191
|
+
// Tear down.
|
|
192
|
+
console.error = _error
|
|
193
|
+
process.exit = _exit
|
|
194
|
+
|
|
195
|
+
t.end()
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
//
|
|
199
|
+
// Comment handler tests.
|
|
200
|
+
//
|
|
201
|
+
|
|
202
|
+
test('comment handler', t => {
|
|
203
|
+
// Setup.
|
|
204
|
+
const originalConsoleLog = console.log
|
|
205
|
+
const capturedConsoleLog = (...args) => output += args.join(' ')
|
|
206
|
+
|
|
207
|
+
console.log = capturedConsoleLog
|
|
208
|
+
let output = ''
|
|
209
|
+
|
|
210
|
+
// Test regular comment.
|
|
211
|
+
const regularCommentPrefix = ' 🢂 '
|
|
212
|
+
const regularComment = 'a regular comment'
|
|
213
|
+
|
|
214
|
+
tapMonkey.commentHandler({ raw: regularComment })
|
|
215
|
+
tapMonkey.spinner.stop()
|
|
216
|
+
console.log = originalConsoleLog
|
|
217
|
+
|
|
218
|
+
t.equals(output, `${regularCommentPrefix} ${regularComment}`, 'regular comment is formatted correctly')
|
|
219
|
+
|
|
220
|
+
// Test coverage comments.
|
|
221
|
+
output = ''
|
|
222
|
+
console.log = capturedConsoleLog
|
|
223
|
+
|
|
224
|
+
const coverageTap = [
|
|
225
|
+
'----------|---------|----------|---------|---------|-----------------------',
|
|
226
|
+
' File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ',
|
|
227
|
+
'----------|---------|----------|---------|---------|-----------------------',
|
|
228
|
+
'All files | 70.37 | 71.42 | 50 | 70.37 | ',
|
|
229
|
+
' index.js | 70.37 | 71.42 | 50 | 70.37 | 59-61,105-131,135-152 ',
|
|
230
|
+
'----------|---------|----------|---------|---------|-----------------------'
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
const expectedCoverageOutput = '╭───────────┬─────────┬──────────┬─────────┬─────────┬────────────────────────╮│ File │ % Stmts │ % Branch │ % Funcs │ % Lines │ Uncovered Line #s │├───────────┼─────────┼──────────┼─────────┼─────────┼────────────────────────┤│ All files │ 70.37 │ 71.42 │ 50 │ 70.37 │ ││ index.js │ 70.37 │ 71.42 │ 50 │ 70.37 │ 59─61,105─131,135─152 │╰───────────┴─────────┴──────────┴─────────┴─────────┴────────────────────────╯'
|
|
234
|
+
|
|
235
|
+
coverageTap.forEach(line => {
|
|
236
|
+
tapMonkey.commentHandler({ raw: line })
|
|
237
|
+
})
|
|
238
|
+
tapMonkey.spinner.stop()
|
|
239
|
+
console.log = originalConsoleLog
|
|
240
|
+
|
|
241
|
+
// Assertions.
|
|
242
|
+
t.equals(output.trim(), expectedCoverageOutput, 'formatted coverage output is correct')
|
|
243
|
+
|
|
244
|
+
// Test too many borders in coverage error.
|
|
245
|
+
t.throws(() => {
|
|
246
|
+
tapMonkey.commentHandler({ raw: coverageTap[0] })
|
|
247
|
+
}, 'too many borders in coverage output error should throw')
|
|
248
|
+
|
|
249
|
+
t.end()
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
//
|
|
253
|
+
// Output handler tests.
|
|
254
|
+
//
|
|
255
|
+
|
|
256
|
+
test ('output handler', t => {
|
|
257
|
+
const vacuumPack = string => string.replace(/\s/g, '')
|
|
258
|
+
const originalConsoleLog = console.log
|
|
259
|
+
const capturedConsoleLog = (...args) => output += args.join(' ')
|
|
260
|
+
|
|
261
|
+
console.log = capturedConsoleLog
|
|
262
|
+
let output = ''
|
|
263
|
+
|
|
264
|
+
// Test: all tests passing.
|
|
265
|
+
|
|
266
|
+
const mockAllTestsPassingResults = {
|
|
267
|
+
asserts: [1, 2, 3],
|
|
268
|
+
pass: [1, 2, 3],
|
|
269
|
+
fail: []
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
tapMonkey.outputHandler(mockAllTestsPassingResults)
|
|
273
|
+
console.log = originalConsoleLog
|
|
274
|
+
|
|
275
|
+
t.strictEquals(tapMonkey.spinner.isSpinning, false, 'spinner has stopped')
|
|
276
|
+
t.true(vacuumPack(output).includes('Alltestspassing!Total3Passing3Failing0'))
|
|
277
|
+
|
|
278
|
+
// Test: failing tests.
|
|
279
|
+
|
|
280
|
+
output = ''
|
|
281
|
+
console.log = capturedConsoleLog
|
|
282
|
+
|
|
283
|
+
const mockFailingTests = {
|
|
284
|
+
asserts: [1, 2, 3],
|
|
285
|
+
pass: [1],
|
|
286
|
+
fail: [2, 3]
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
tapMonkey.outputHandler(mockFailingTests)
|
|
290
|
+
console.log = originalConsoleLog
|
|
291
|
+
|
|
292
|
+
t.true(vacuumPack(output).includes('Therearefailedtests.Total3Passing1Failing2'))
|
|
293
|
+
t.end()
|
|
294
|
+
})
|
|
295
|
+
|