1 | 'use strict'
|
2 |
|
3 |
|
4 | if (Array.prototype.includes == null) {
|
5 |
|
6 | Array.prototype.includes = function (searchElement) {
|
7 | return this.indexOf(searchElement) !== -1
|
8 | }
|
9 | }
|
10 |
|
11 |
|
12 | import {
|
13 | ok as _ok,
|
14 | strictEqual as _strictEqual,
|
15 | deepStrictEqual as _deepStrictEqual,
|
16 | } from 'assert'
|
17 | import { inspect as _inspect } from 'util'
|
18 | import * as ansi from '@bevry/ansi'
|
19 | import Errlop from 'errlop'
|
20 | import { argv, env, stdout, stderr, versions } from 'process'
|
21 |
|
22 |
|
23 | type Errback = (error?: Error) => void
|
24 |
|
25 |
|
26 | export function wait(delay: number, fn: (...args: any[]) => void) {
|
27 |
|
28 | return setTimeout(fn, delay)
|
29 | }
|
30 |
|
31 |
|
32 | export function isNode(): boolean {
|
33 | return Boolean(versions && versions.node)
|
34 | }
|
35 |
|
36 |
|
37 | export function isTTY(): boolean {
|
38 | return (
|
39 | isNode() &&
|
40 | stdout &&
|
41 | stdout.isTTY === true &&
|
42 | stderr &&
|
43 | stderr.isTTY === true
|
44 | )
|
45 | }
|
46 |
|
47 |
|
48 | export function bool(value: any): boolean | null {
|
49 | if (value === 'no' || value === 'false' || value === 'n' || value === 'N') {
|
50 | return false
|
51 | }
|
52 | if (value == null || value === '' || value === 'null' || value === 'NULL')
|
53 | return null
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | if (value === '0') return null
|
59 | if (value === '1') return null
|
60 |
|
61 | return Boolean(value)
|
62 | }
|
63 |
|
64 |
|
65 | export function useColors(): boolean {
|
66 |
|
67 | if (!isNode()) return false
|
68 |
|
69 | if (argv.includes('--no-colors') || argv.includes('--no-color')) return false
|
70 |
|
71 | return bool(env.COLOR) ?? bool(env.COLORS) ?? isTTY()
|
72 | }
|
73 |
|
74 |
|
75 | export function color(value: any, color: Function): string {
|
76 | return useColors() ? color(value) : value
|
77 | }
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | function isObject(value: any): boolean {
|
84 |
|
85 | return value !== null && typeof value === 'object'
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | export function inspect(value: any, opts: any = {}): string {
|
94 |
|
95 | const colors = useColors()
|
96 | const depth = 50
|
97 |
|
98 |
|
99 | return _inspect(value, { colors, depth, ...opts })
|
100 | }
|
101 |
|
102 |
|
103 | export function log(...args: any): void {
|
104 | if (isNode() && env.ASSERT_SILENCE) return
|
105 | for (let i = 0; i < args.length; ++i) {
|
106 | console.log(inspect(args[i]))
|
107 | }
|
108 | }
|
109 |
|
110 |
|
111 | export function logComparison(
|
112 | actual: any,
|
113 | expected: any,
|
114 | error: Error | string | any
|
115 | ): void {
|
116 | if (isNode() && env.ASSERT_SILENCE) return
|
117 |
|
118 | const lines = [
|
119 | '------------------------------------',
|
120 | 'Comparison Error:',
|
121 | color(error.stack || error.message || error, ansi.green),
|
122 | '',
|
123 | ]
|
124 |
|
125 | lines.push(
|
126 | 'Comparison Actual:',
|
127 | inspect(actual),
|
128 | '',
|
129 | 'Comparison Expected:',
|
130 | inspect(expected),
|
131 | '------------------------------------'
|
132 | )
|
133 |
|
134 |
|
135 | if (isNode() && stderr) {
|
136 | stderr.write(lines.join('\n') + '\n')
|
137 | }
|
138 |
|
139 | else {
|
140 | console.log(lines.join('\n'))
|
141 | }
|
142 | }
|
143 |
|
144 |
|
145 | export function equal(
|
146 | actual: any,
|
147 | expected: any,
|
148 | testName = 'equal assertion',
|
149 | next?: Errback
|
150 | ): void | never {
|
151 | try {
|
152 | _strictEqual(actual, expected, testName)
|
153 | } catch (checkError) {
|
154 | logComparison(actual, expected, checkError)
|
155 | if (next) {
|
156 | next(checkError)
|
157 | return
|
158 | } else {
|
159 | throw checkError
|
160 | }
|
161 | }
|
162 | if (next) next()
|
163 | }
|
164 |
|
165 |
|
166 | export function gte(
|
167 | actual: any,
|
168 | expected: any,
|
169 | testName = 'is greater than or equal to assertion',
|
170 | next?: Errback
|
171 | ): void | never {
|
172 | try {
|
173 | _strictEqual(actual >= expected, true, testName)
|
174 | } catch (checkError) {
|
175 | logComparison(actual, expected, checkError)
|
176 | if (next) {
|
177 | next(checkError)
|
178 | return
|
179 | } else {
|
180 | throw checkError
|
181 | }
|
182 | }
|
183 | if (next) next()
|
184 | }
|
185 |
|
186 |
|
187 | export function lte(
|
188 | actual: any,
|
189 | expected: any,
|
190 | testName = 'is less than or equal to assertion',
|
191 | next?: Errback
|
192 | ): void | never {
|
193 | try {
|
194 | _strictEqual(actual <= expected, true, testName)
|
195 | } catch (checkError) {
|
196 | logComparison(actual, expected, checkError)
|
197 | if (next) {
|
198 | next(checkError)
|
199 | return
|
200 | } else {
|
201 | throw checkError
|
202 | }
|
203 | }
|
204 | if (next) next()
|
205 | }
|
206 |
|
207 |
|
208 | export function gt(
|
209 | actual: any,
|
210 | expected: any,
|
211 | testName = 'is greater than assertion',
|
212 | next?: Errback
|
213 | ): void | never {
|
214 | try {
|
215 | _strictEqual(actual > expected, true, testName)
|
216 | } catch (checkError) {
|
217 | logComparison(actual, expected, checkError)
|
218 | if (next) {
|
219 | next(checkError)
|
220 | return
|
221 | } else {
|
222 | throw checkError
|
223 | }
|
224 | }
|
225 | if (next) next()
|
226 | }
|
227 |
|
228 |
|
229 | export function lt(
|
230 | actual: any,
|
231 | expected: any,
|
232 | testName = 'is less than assertion',
|
233 | next?: Errback
|
234 | ): void | never {
|
235 | try {
|
236 | _strictEqual(actual < expected, true, testName)
|
237 | } catch (checkError) {
|
238 | logComparison(actual, expected, checkError)
|
239 | if (next) {
|
240 | next(checkError)
|
241 | return
|
242 | } else {
|
243 | throw checkError
|
244 | }
|
245 | }
|
246 | if (next) next()
|
247 | }
|
248 |
|
249 |
|
250 | export function undef(
|
251 | actual: any,
|
252 | testName = 'undef assertion',
|
253 | next?: Errback
|
254 | ) {
|
255 | try {
|
256 | _strictEqual(typeof actual, 'undefined', testName)
|
257 | } catch (checkError) {
|
258 | logComparison(actual, 'undefined', checkError)
|
259 | if (next) {
|
260 | next(checkError)
|
261 | return
|
262 | } else {
|
263 | throw checkError
|
264 | }
|
265 | }
|
266 | if (next) next()
|
267 | }
|
268 |
|
269 |
|
270 | export function nullish(
|
271 | actual: any,
|
272 | testName = 'nullish assertion',
|
273 | next?: Errback
|
274 | ) {
|
275 | try {
|
276 | _strictEqual(typeof actual, 'undefined', testName)
|
277 | } catch (e1) {
|
278 | try {
|
279 | _strictEqual(actual, null, testName)
|
280 | } catch (e2) {
|
281 | const error = new Errlop(e2, e1)
|
282 | logComparison(actual, 'nullish', error)
|
283 | if (next) {
|
284 | next(error)
|
285 | return
|
286 | } else {
|
287 | throw error
|
288 | }
|
289 | }
|
290 | }
|
291 | if (next) next()
|
292 | }
|
293 |
|
294 |
|
295 | export function deepEqual(
|
296 | actual: any,
|
297 | expected: any,
|
298 | testName = 'deep equal assertion',
|
299 | next?: Errback
|
300 | ): void | never {
|
301 | try {
|
302 | _deepStrictEqual(actual, expected, testName)
|
303 | } catch (checkError) {
|
304 | logComparison(actual, expected, checkError)
|
305 | if (next) {
|
306 | next(checkError)
|
307 | return
|
308 | } else {
|
309 | throw checkError
|
310 | }
|
311 | }
|
312 | if (next) next()
|
313 | }
|
314 |
|
315 |
|
316 | export function contains(
|
317 | actual: any,
|
318 | expected: any,
|
319 | testName = 'contains assertion',
|
320 | next?: Errback
|
321 | ): void | never {
|
322 | if (testName == null)
|
323 | testName = `Expected [${actual}] to contain [${expected}]`
|
324 | try {
|
325 | _ok(actual.indexOf(expected) !== -1, testName)
|
326 | } catch (checkError) {
|
327 | if (next) {
|
328 | next(checkError)
|
329 | return
|
330 | } else {
|
331 | throw checkError
|
332 | }
|
333 | }
|
334 | if (next) next()
|
335 | }
|
336 |
|
337 |
|
338 | export function errorEqual(
|
339 | actualError: any,
|
340 | expectedError: any,
|
341 | testName = 'error equal assertion',
|
342 | next?: Errback
|
343 | ): void | never {
|
344 | let expectedErrorMessage, actualErrorMessage
|
345 |
|
346 | if (expectedError) {
|
347 | if (expectedError instanceof Error) {
|
348 | expectedErrorMessage = expectedError.message
|
349 | } else {
|
350 | expectedErrorMessage = expectedError
|
351 | expectedError = new Error(expectedErrorMessage)
|
352 | }
|
353 | }
|
354 |
|
355 | if (actualError) {
|
356 | if (actualError instanceof Error) {
|
357 | actualErrorMessage = actualError.message
|
358 | } else {
|
359 | actualErrorMessage = actualError
|
360 | actualError = new Error(actualErrorMessage)
|
361 | }
|
362 | }
|
363 |
|
364 | try {
|
365 | if (actualErrorMessage && expectedErrorMessage) {
|
366 | contains(actualErrorMessage, expectedErrorMessage, testName)
|
367 | } else {
|
368 | equal(actualError, expectedError || null, testName)
|
369 | }
|
370 | } catch (checkError) {
|
371 | logComparison(
|
372 | actualError && (actualError.stack || actualError.message || actualError),
|
373 | expectedErrorMessage,
|
374 | checkError
|
375 | )
|
376 | if (next) {
|
377 | next(checkError)
|
378 | return
|
379 | } else {
|
380 | throw checkError
|
381 | }
|
382 | }
|
383 | if (next) next()
|
384 | }
|
385 |
|
386 |
|
387 | export function returnViaCallback(value: any): () => typeof value {
|
388 | return function () {
|
389 | return value
|
390 | }
|
391 | }
|
392 |
|
393 |
|
394 |
|
395 | export function completeViaCallback(value: any, delay = 100) {
|
396 | return function (
|
397 | complete: (error: null, result: typeof value) => void
|
398 | ): void {
|
399 | wait(delay, function () {
|
400 | complete(null, value)
|
401 | })
|
402 | }
|
403 | }
|
404 |
|
405 |
|
406 |
|
407 | export function errorViaCallback(error: Error | string, delay = 100) {
|
408 | return function (complete: (error: Error | string) => void): void {
|
409 | wait(delay, function () {
|
410 | complete(error)
|
411 | })
|
412 | }
|
413 | }
|
414 |
|
415 | export function returnErrorViaCallback(
|
416 | error: Error | string = 'an error occured'
|
417 | ) {
|
418 | return function (): Error {
|
419 | if (error instanceof Error) {
|
420 | return error
|
421 | } else {
|
422 | return new Error(error)
|
423 | }
|
424 | }
|
425 | }
|
426 |
|
427 |
|
428 | export function throwErrorViaCallback(
|
429 | error: Error | string = 'an error occured'
|
430 | ) {
|
431 | return function (): never {
|
432 | if (error instanceof Error) {
|
433 | throw error
|
434 | } else {
|
435 | throw new Error(error)
|
436 | }
|
437 | }
|
438 | }
|
439 |
|
440 |
|
441 | export function expectViaCallback(...expected: any) {
|
442 | return (...actual: any) => deepEqual(actual, expected)
|
443 | }
|
444 |
|
445 |
|
446 |
|
447 |
|
448 | export function expectErrorViaCallback(
|
449 | expected: Error | string,
|
450 | testName = 'expect error via callback assertion',
|
451 | next?: Errback
|
452 | ) {
|
453 | return (actual: Error | string) =>
|
454 | errorEqual(actual, expected, testName, next)
|
455 | }
|
456 |
|
457 |
|
458 | export function expectThrowViaFunction(
|
459 | expected: Error | string,
|
460 | fn: () => never,
|
461 | testName = 'expect error via function assertion',
|
462 | next?: Errback
|
463 | ) {
|
464 | let actual = null
|
465 | try {
|
466 | fn()
|
467 | } catch (error) {
|
468 | actual = error
|
469 | }
|
470 | errorEqual(actual, expected, testName, next)
|
471 | }
|
472 |
|
473 |
|
474 | export function expectErrorViaFunction(): never {
|
475 | throw new Error(
|
476 | 'expectErrorViaFunction has been deprecated, use expectThrowViaFunction instead'
|
477 | )
|
478 | }
|
479 |
|
480 |
|
481 | export function expectFunctionToThrow(): never {
|
482 | throw new Error(
|
483 | 'expectFunctionToThrow has been deprecated, use expectThrowViaFunction instead'
|
484 | )
|
485 | }
|