@small-tech/tap-monkey 1.1.1 → 1.4.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 +28 -0
- package/README.md +48 -1
- package/index.js +60 -41
- package/package.json +19 -4
- package/tests/index.js +295 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,34 @@ 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.4.0] - 2022-05-24
|
|
8
|
+
|
|
9
|
+
Testy monkey.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- 100% code coverage. Now using tape and *drumroll* Tap Monkey itself for the tests.
|
|
14
|
+
|
|
15
|
+
## [1.3.0] - 2021-03-05
|
|
16
|
+
|
|
17
|
+
Debug monkey.
|
|
18
|
+
|
|
19
|
+
## Added
|
|
20
|
+
|
|
21
|
+
- Now displays console output from your app if there is any (useful for debugging).
|
|
22
|
+
|
|
23
|
+
## [1.2.0] - 2021-03-04
|
|
24
|
+
|
|
25
|
+
Bail-out monkey.
|
|
26
|
+
|
|
27
|
+
## Added
|
|
28
|
+
|
|
29
|
+
- Handles bail-out events.
|
|
30
|
+
|
|
31
|
+
## Updated
|
|
32
|
+
|
|
33
|
+
- tap-out: version 3.1.0 → 3.2.0
|
|
34
|
+
|
|
7
35
|
## [1.1.1] - 2021-03-03
|
|
8
36
|
|
|
9
37
|
Fix typos.
|
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ e.g., using [c8](https://github.com/bcoe/c8):
|
|
|
64
64
|
|
|
65
65
|
```json
|
|
66
66
|
"scripts" : {
|
|
67
|
-
"
|
|
67
|
+
"coverage": "c8 tape test/**/*js | tap-monkey"
|
|
68
68
|
}
|
|
69
69
|
```
|
|
70
70
|
|
|
@@ -76,6 +76,53 @@ While passing tests are displayed ephemerally in the status line so as not to fi
|
|
|
76
76
|
|
|
77
77
|
(When running tests, we don’t care about passing tests, only failing ones.)
|
|
78
78
|
|
|
79
|
+
## Debug output
|
|
80
|
+
|
|
81
|
+
Any console output that is generated by your program (e.g., from `console.log()` statements) is displayed in full and separate from the current test status line.
|
|
82
|
+
|
|
83
|
+
This is useful while debugging. (I like to have regular and debug test tasks in my code and use the latter when debugging an issue encountered in a test.)
|
|
84
|
+
|
|
85
|
+
e.g., my regular tests define an environment variable that silences console output but I have a separate debug test task that doesn’t include this.
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
"scripts" : {
|
|
89
|
+
"test": "QUIET=true tape test/**/*js | tap-monkey",
|
|
90
|
+
"test-debug": "tape test/**/*js | tap-monkey"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then, all you need is to use a conditional log function in your app that checks for that environment variable. e.g.,
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
// Conditionally log to console.
|
|
98
|
+
export default function log (...args) {
|
|
99
|
+
if (process.env.QUIET) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
console.log(...args)
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Error behaviour
|
|
107
|
+
|
|
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
|
+
|
|
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
|
+
|
|
79
126
|
## Like this? Fund us!
|
|
80
127
|
|
|
81
128
|
[Small Technology Foundation](https://small-tech.org) is a tiny, independent not-for-profit.
|
package/index.js
CHANGED
|
@@ -16,14 +16,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
|
|
@@ -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,50 +80,57 @@ 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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
printingCoverage = true
|
|
103
|
-
spinner.stop()
|
|
104
|
-
}
|
|
94
|
+
const bailOutHandler = (event => {
|
|
95
|
+
// If the test runner has emitted a bail out event, it has signaled
|
|
96
|
+
// that it cannot continue. So we notify the person and exit.
|
|
97
|
+
spinner.stop()
|
|
98
|
+
console.error(chalk.red(event.raw))
|
|
99
|
+
console.error()
|
|
100
|
+
process.exit(1)
|
|
101
|
+
})
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
commentText = `│ ${commentText} │`
|
|
115
|
-
}
|
|
103
|
+
const commentHandler = (comment => {
|
|
104
|
+
spinner.stop()
|
|
105
|
+
let commentText = comment.raw
|
|
106
|
+
|
|
107
|
+
const isCoverageBorder = commentText.startsWith('----')
|
|
108
|
+
if (isCoverageBorder) { printingCoverage = true }
|
|
116
109
|
|
|
117
110
|
if (printingCoverage) {
|
|
111
|
+
if (isCoverageBorder) {
|
|
112
|
+
coverageBorderCount++
|
|
113
|
+
switch(coverageBorderCount) {
|
|
114
|
+
case 1: commentText = `╭─${commentText.replace(/\-\|\-/g, '─┬─')}─╮`; break
|
|
115
|
+
case 2: commentText = `├─${commentText.replace(/\-\|\-/g, '─┼─')}─┤`; break
|
|
116
|
+
case 3: commentText = `╰─${commentText.replace(/\-\|\-/g, '─┴─')}─╯\n`; break
|
|
117
|
+
default: throw new Error('Too many borders found in coverage. Panic!')
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
// Printing coverage but this line isn’t a border, just surround it with vertical borders.
|
|
121
|
+
commentText = `│ ${commentText} │`
|
|
122
|
+
}
|
|
123
|
+
// Replace any inner borders that there might be with proper box-drawing characters.
|
|
118
124
|
console.log(commentText.replace(/\|/g, '│').replace(/\-/g, '─'))
|
|
119
125
|
} else {
|
|
120
|
-
// We
|
|
121
|
-
// Display it
|
|
122
|
-
|
|
126
|
+
// We aren’t printing coverage yet so this must be a regular TAP comment.
|
|
127
|
+
// Display it fully.
|
|
128
|
+
console.log(chalk.yellow(' 🢂 '), commentText.trim())
|
|
129
|
+
spinner.start()
|
|
123
130
|
}
|
|
124
131
|
})
|
|
125
132
|
|
|
126
|
-
|
|
133
|
+
const outputHandler = (results => {
|
|
127
134
|
const duration = ((performance.now() - startTime)/1000).toFixed(2)
|
|
128
135
|
spinner.stop()
|
|
129
136
|
|
|
@@ -131,7 +138,9 @@ parser.on('output', results => {
|
|
|
131
138
|
const passing = results.pass.length
|
|
132
139
|
const failing = results.fail.length
|
|
133
140
|
|
|
134
|
-
|
|
141
|
+
// TODO: Handle edge case of zero total tests.
|
|
142
|
+
|
|
143
|
+
if (failing > 0) {
|
|
135
144
|
console.log(` 🙊️ ${chalk.magenta('There are failed tests.')}`)
|
|
136
145
|
} else {
|
|
137
146
|
console.log(` 🍌️ ${chalk.green('All tests passing!')}`)
|
|
@@ -143,3 +152,13 @@ parser.on('output', results => {
|
|
|
143
152
|
console.log(chalk.red( ` Failing ${failing}`))
|
|
144
153
|
console.log(chalk.gray( ` Duration ${duration} secs`))
|
|
145
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/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@small-tech/tap-monkey",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A tap formatter that’s also a monkey.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tap",
|
|
7
|
+
"formatter",
|
|
8
|
+
"tape",
|
|
9
|
+
"nyc",
|
|
10
|
+
"c8",
|
|
11
|
+
"test anything protocol",
|
|
12
|
+
"accessible",
|
|
13
|
+
"a11y"
|
|
14
|
+
],
|
|
6
15
|
"license": "ISC",
|
|
7
16
|
"main": "index.js",
|
|
8
17
|
"type": "module",
|
|
@@ -10,7 +19,8 @@
|
|
|
10
19
|
"tap-monkey": "./index.js"
|
|
11
20
|
},
|
|
12
21
|
"scripts": {
|
|
13
|
-
"test": "
|
|
22
|
+
"test": "tape tests/index.js | node index.js",
|
|
23
|
+
"coverage": "c8 tape tests/index.js | node index.js"
|
|
14
24
|
},
|
|
15
25
|
"author": {
|
|
16
26
|
"name": "Aral Balkan",
|
|
@@ -24,8 +34,13 @@
|
|
|
24
34
|
"url": "https://github.com/small-tech/tap-monkey.git"
|
|
25
35
|
},
|
|
26
36
|
"dependencies": {
|
|
27
|
-
"@small-tech/tap-out": "^3.
|
|
37
|
+
"@small-tech/tap-out": "^3.2.0",
|
|
28
38
|
"chalk": "^4.1.0",
|
|
29
39
|
"ora": "^5.3.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"c8": "^7.11.3",
|
|
43
|
+
"strip-ansi": "^7.0.1",
|
|
44
|
+
"tape": "^5.5.3"
|
|
30
45
|
}
|
|
31
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._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('~/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
|
+
|