Skip to content

Commit dda76c2

Browse files
authored
chore: add missing test (#19)
Fixes: #18
1 parent 1c19129 commit dda76c2

3 files changed

Lines changed: 816 additions & 7 deletions

File tree

test/message.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,35 @@ function readLines (file) {
2121
})
2222
}
2323

24+
const stackTraceStartLine = /^\s+stack: \|-$/
25+
const stackTraceLine = /^\s+\*$/
26+
const stackTraceEndLine = /^\s+\.\.\.$/
27+
28+
const nodejs14NotEmittedWarn = /^# Warning:.*\breject/
29+
2430
// https://github.com/nodejs/node/blob/1aab13cad9c800f4121c1d35b554b78c1b17bdbd/test/message/testcfg.py#L53
2531
async function IsFailureOutput (self, output) {
2632
// Convert output lines to regexps that we can match
2733
const patterns = []
2834
for await (const line of readLines(self.expected)) {
29-
if (!line.trim()) continue
35+
// Our implementation outputs different stack traces than the Node.js implementation.
36+
if (stackTraceLine.test(line) && patterns[patterns.length - 1] === WAIT_FOR_ELLIPSIS) continue
37+
38+
// Node.js 14 doesn't emit some warnings
39+
if (process.version.startsWith('v14.') && nodejs14NotEmittedWarn.test(line)) continue
40+
41+
// Sometimes Node.js won't have any stack trace, but we would
42+
if (stackTraceEndLine.test(line) && patterns[patterns.length - 1].toString().endsWith("code: 'ERR_TEST_FAILURE'$")) {
43+
patterns.push(stackTraceStartLine, WAIT_FOR_ELLIPSIS)
44+
}
45+
3046
const pattern = line
31-
.trimEnd()
3247
.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
3348
.replace(/\\\*/g, '.*')
3449
patterns.push(`^${pattern}$`)
3550

36-
if (/^\s+stack: \|-$/.test(line)) {
37-
// Our implementation outputs more info in its stack trace than the Node.js implementation.
51+
if (stackTraceStartLine.test(line)) {
52+
// Our implementation outputs different stack traces than the Node.js implementation.
3853
patterns.push(WAIT_FOR_ELLIPSIS)
3954
}
4055
}
@@ -47,15 +62,15 @@ async function IsFailureOutput (self, output) {
4762
for (let i = 0; i < outlines.length; i++) {
4863
if (patterns[i] === WAIT_FOR_ELLIPSIS) {
4964
waitingForEllipsis = true
50-
} else if (!new RegExp(patterns[i]).test(outlines[i])) {
65+
} else if (!new RegExp(patterns[i]).test(outlines[i].trimEnd())) {
5166
if (waitingForEllipsis) {
5267
patterns.splice(i, 0, WAIT_FOR_ELLIPSIS)
5368
continue
5469
}
5570
console.log('match failed', { line: i + 1, expected: patterns[i], actual: outlines[i] })
56-
console.log(Array.from({ length: Math.min(patterns.length, outlines.length) }, (_, i) => ({ line: i + 1, expected: patterns[i], actual: outlines[i] })))
71+
console.log(Array.from({ length: Math.min(patterns.length, outlines.length) }, (_, i) => ({ line: i + 1, expected: patterns[i], actual: outlines[i] })).slice(Math.max(0, i - 5), i + 5))
5772
return true
58-
} else if (waitingForEllipsis && outlines[i].includes('...')) {
73+
} else if (waitingForEllipsis && stackTraceEndLine.test(outlines[i])) {
5974
waitingForEllipsis = false
6075
}
6176
}

test/message/test_runner_output.js

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
// https://github.com/nodejs/node/blob/1aab13cad9c800f4121c1d35b554b78c1b17bdbd/test/message/test_runner_output.js
2+
// Flags: --no-warnings
3+
'use strict'
4+
require('../common')
5+
const assert = require('node:assert')
6+
const test = require('#node:test')
7+
const util = require('util')
8+
9+
test('sync pass todo', (t) => {
10+
t.todo()
11+
})
12+
13+
test('sync pass todo with message', (t) => {
14+
t.todo('this is a passing todo')
15+
})
16+
17+
test('sync fail todo', (t) => {
18+
t.todo()
19+
throw new Error('thrown from sync fail todo')
20+
})
21+
22+
test('sync fail todo with message', (t) => {
23+
t.todo('this is a failing todo')
24+
throw new Error('thrown from sync fail todo with message')
25+
})
26+
27+
test('sync skip pass', (t) => {
28+
t.skip()
29+
})
30+
31+
test('sync skip pass with message', (t) => {
32+
t.skip('this is skipped')
33+
})
34+
35+
test('sync pass', (t) => {
36+
t.diagnostic('this test should pass')
37+
})
38+
39+
test('sync throw fail', () => {
40+
throw new Error('thrown from sync throw fail')
41+
})
42+
43+
test('async skip pass', async (t) => {
44+
t.skip()
45+
})
46+
47+
test('async pass', async () => {
48+
49+
})
50+
51+
test('async throw fail', async () => {
52+
throw new Error('thrown from async throw fail')
53+
})
54+
55+
test('async skip fail', async (t) => {
56+
t.skip()
57+
throw new Error('thrown from async throw fail')
58+
})
59+
60+
test('async assertion fail', async () => {
61+
// Make sure the assert module is handled.
62+
assert.strictEqual(true, false)
63+
})
64+
65+
test('resolve pass', () => {
66+
return Promise.resolve()
67+
})
68+
69+
test('reject fail', () => {
70+
return Promise.reject(new Error('rejected from reject fail'))
71+
})
72+
73+
test('unhandled rejection - passes but warns', () => {
74+
Promise.reject(new Error('rejected from unhandled rejection fail'))
75+
})
76+
77+
test('async unhandled rejection - passes but warns', async () => {
78+
Promise.reject(new Error('rejected from async unhandled rejection fail'))
79+
})
80+
81+
test('immediate throw - passes but warns', () => {
82+
setImmediate(() => {
83+
throw new Error('thrown from immediate throw fail')
84+
})
85+
})
86+
87+
test('immediate reject - passes but warns', () => {
88+
setImmediate(() => {
89+
Promise.reject(new Error('rejected from immediate reject fail'))
90+
})
91+
})
92+
93+
test('immediate resolve pass', () => {
94+
return new Promise((resolve) => {
95+
setImmediate(() => {
96+
resolve()
97+
})
98+
})
99+
})
100+
101+
test('subtest sync throw fail', async (t) => {
102+
await t.test('+sync throw fail', (t) => {
103+
t.diagnostic('this subtest should make its parent test fail')
104+
throw new Error('thrown from subtest sync throw fail')
105+
})
106+
})
107+
108+
test('sync throw non-error fail', async (t) => {
109+
throw Symbol('thrown symbol from sync throw non-error fail')
110+
})
111+
112+
test('level 0a', { concurrency: 4 }, async (t) => {
113+
t.test('level 1a', async (t) => {
114+
const p1a = new Promise((resolve) => {
115+
setTimeout(() => {
116+
resolve()
117+
}, 1000)
118+
})
119+
120+
return p1a
121+
})
122+
123+
t.test('level 1b', async (t) => {
124+
const p1b = new Promise((resolve) => {
125+
resolve()
126+
})
127+
128+
return p1b
129+
})
130+
131+
t.test('level 1c', async (t) => {
132+
const p1c = new Promise((resolve) => {
133+
setTimeout(() => {
134+
resolve()
135+
}, 2000)
136+
})
137+
138+
return p1c
139+
})
140+
141+
t.test('level 1d', async (t) => {
142+
const p1c = new Promise((resolve) => {
143+
setTimeout(() => {
144+
resolve()
145+
}, 1500)
146+
})
147+
148+
return p1c
149+
})
150+
151+
const p0a = new Promise((resolve) => {
152+
setTimeout(() => {
153+
resolve()
154+
}, 3000)
155+
})
156+
157+
return p0a
158+
})
159+
160+
test('top level', { concurrency: 2 }, async (t) => {
161+
t.test('+long running', async (t) => {
162+
return new Promise((resolve, reject) => {
163+
setTimeout(resolve, 3000).unref()
164+
})
165+
})
166+
167+
t.test('+short running', async (t) => {
168+
t.test('++short running', async (t) => {})
169+
})
170+
})
171+
172+
test('invalid subtest - pass but subtest fails', (t) => {
173+
setImmediate(() => {
174+
t.test('invalid subtest fail', () => {
175+
throw new Error('this should not be thrown')
176+
})
177+
})
178+
})
179+
180+
test('sync skip option', { skip: true }, (t) => {
181+
throw new Error('this should not be executed')
182+
})
183+
184+
test('sync skip option with message', { skip: 'this is skipped' }, (t) => {
185+
throw new Error('this should not be executed')
186+
})
187+
188+
test('sync skip option is false fail', { skip: false }, (t) => {
189+
throw new Error('this should be executed')
190+
})
191+
192+
// A test with no arguments provided.
193+
test()
194+
195+
// A test with only a named function provided.
196+
test(function functionOnly () {})
197+
198+
// A test with only an anonymous function provided.
199+
test(() => {})
200+
201+
// A test with only a name provided.
202+
test('test with only a name provided')
203+
204+
// A test with an empty string name.
205+
test('')
206+
207+
// A test with only options provided.
208+
test({ skip: true })
209+
210+
// A test with only a name and options provided.
211+
test('test with a name and options provided', { skip: true })
212+
213+
// A test with only options and a function provided.
214+
test({ skip: true }, function functionAndOptions () {})
215+
216+
// A test whose description needs to be escaped.
217+
test('escaped description \\ # \\#\\')
218+
219+
// A test whose skip message needs to be escaped.
220+
test('escaped skip message', { skip: '#skip' })
221+
222+
// A test whose todo message needs to be escaped.
223+
test('escaped todo message', { todo: '#todo' })
224+
225+
// A test with a diagnostic message that needs to be escaped.
226+
test('escaped diagnostic', (t) => {
227+
t.diagnostic('#diagnostic')
228+
})
229+
230+
test('callback pass', (t, done) => {
231+
setImmediate(done)
232+
})
233+
234+
test('callback fail', (t, done) => {
235+
setImmediate(() => {
236+
done(new Error('callback failure'))
237+
})
238+
})
239+
240+
test('sync t is this in test', function (t) {
241+
assert.strictEqual(this, t)
242+
})
243+
244+
test('async t is this in test', async function (t) {
245+
assert.strictEqual(this, t)
246+
})
247+
248+
test('callback t is this in test', function (t, done) {
249+
assert.strictEqual(this, t)
250+
done()
251+
})
252+
253+
test('callback also returns a Promise', async (t, done) => {
254+
throw new Error('thrown from callback also returns a Promise')
255+
})
256+
257+
test('callback throw', (t, done) => {
258+
throw new Error('thrown from callback throw')
259+
})
260+
261+
test('callback called twice', (t, done) => {
262+
done()
263+
done()
264+
})
265+
266+
test('callback called twice in different ticks', (t, done) => {
267+
setImmediate(done)
268+
done()
269+
})
270+
271+
test('callback called twice in future tick', (t, done) => {
272+
setImmediate(() => {
273+
done()
274+
done()
275+
})
276+
})
277+
278+
test('callback async throw', (t, done) => {
279+
setImmediate(() => {
280+
throw new Error('thrown from callback async throw')
281+
})
282+
})
283+
284+
test('callback async throw after done', (t, done) => {
285+
setImmediate(() => {
286+
throw new Error('thrown from callback async throw after done')
287+
})
288+
289+
done()
290+
})
291+
292+
test('only is set but not in only mode', { only: true }, async (t) => {
293+
// All of these subtests should run.
294+
await t.test('running subtest 1')
295+
t.runOnly(true)
296+
await t.test('running subtest 2')
297+
await t.test('running subtest 3', { only: true })
298+
t.runOnly(false)
299+
await t.test('running subtest 4')
300+
})
301+
302+
test('custom inspect symbol fail', () => {
303+
const obj = {
304+
[util.inspect.custom] () {
305+
return 'customized'
306+
},
307+
foo: 1
308+
}
309+
310+
throw obj
311+
})
312+
313+
test('custom inspect symbol that throws fail', () => {
314+
const obj = {
315+
[util.inspect.custom] () {
316+
throw new Error('bad-inspect')
317+
},
318+
foo: 1
319+
}
320+
321+
throw obj
322+
})

0 commit comments

Comments
 (0)