-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathassert.js
More file actions
140 lines (122 loc) · 4.44 KB
/
assert.js
File metadata and controls
140 lines (122 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright Titanium I.T. LLC. For license, see "README" or "LICENSE" file.
// A small modification to Chai. Why? Just to demonstrate how you can customize an assertion library
// without writing it all yourself. And because Chai isn't perfect.
import { assert as chai } from "chai";
const exports = chai;
export default exports;
/**
* Assert that 'actual' strictly equals 'expected'.
* @param actual The actual value.
* @param expected The expected value.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.equal = chai.strictEqual; // By default, Chai's assert.equal does type conversions. DO. NOT. WANT.
/**
* Assert that 'actual' and its recursive contents equals 'expected'.
* @param actual The actual value.
* @param expected The expected value.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.deepEqual = chai.deepEqual; // Re-exported for documentation reasons
/**
* Assert that 'actual.includes(expected)' is true.
* @param actual The actual value.
* @param expected The expected value.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.includes = function(actual, expected, message) {
checkExpected(expected);
if (!actual.includes(expected)) {
fail(message, `'${actual}' should include '${expected}'`);
}
};
/**
* Assert that 'actual.includes(expected)' is false.
* @param actual The actual value.
* @param expected The expected value.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.notIncludes = function(actual, expected, message) {
checkExpected(expected);
if (actual.includes(expected)) {
fail(message, `'${actual}' should not include '${expected}'`);
}
};
/**
* Assert that a function throws an exception.
* @param fnAsync The function to run.
* @param [expectedRegexOrExactString] The exception message to check for (optional).
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.throwsAsync = async function(fnAsync, expectedRegexOrExactString, message) {
try {
await fnAsync();
}
catch (err) {
if (expectedRegexOrExactString === undefined) return;
if (typeof expectedRegexOrExactString === "string") {
exports.equal(err.message, expectedRegexOrExactString, message);
}
else {
exports.match(err.message, expectedRegexOrExactString, message);
}
return;
}
fail(message, "Expected exception");
};
/**
* Assert that a function does not throw an exception.
* @param fnAsync The function to run.
* @throws Throws error if assertion fails.
*/
exports.doesNotThrowAsync = async function(fnAsync) {
await fnAsync();
};
/**
* Assert that a promise resolves. Requires the promise to resolve immediately.
* @param promise The promise to check.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.promiseResolvesAsync = async function(promise, message) {
const promiseResolves = await doesPromiseResolve(promise);
if (!promiseResolves) fail(message, "Expected promise to resolve, but it didn't");
};
/**
* Assert that a promise doesn't resolve. Assumes the promise would have resolved immediately.
* @param promise The promise to check.
* @param [message] An optional message to display if the assertion fails.
* @throws Throws error if assertion fails.
*/
exports.promiseDoesNotResolveAsync = async function(promise, message) {
const promiseResolves = await doesPromiseResolve(promise);
if (promiseResolves) fail(message, "Expected promise to not resolve, but it did");
};
async function doesPromiseResolve(promise) {
let promiseResolved = false;
promise.then(() => {
promiseResolved = true;
});
await drainEventLoopAsync();
return promiseResolved;
}
async function drainEventLoopAsync() {
await new Promise((resolve, reject) => {
// We call setImmediate() twice because some callbacks are executed after setImmediate.
setImmediate(() => {
setImmediate(resolve);
});
});
}
function fail(userMessage, assertionMessage) {
userMessage = userMessage ? `${userMessage}: ` : "";
chai.fail(`${userMessage}${assertionMessage}`);
}
function checkExpected(expected) {
if (expected === undefined) chai.fail("'undefined' provided as expected value in assertion");
}