1 | var zora = (function () {
|
2 | 'use strict';
|
3 |
|
4 | const stringify = JSON.stringify;
|
5 | const printTestHeader = test => console.log(`# ${test.description} - ${test.executionTime}ms`);
|
6 | const printTestCase = (assertion, id) => {
|
7 | const pass = assertion.pass;
|
8 | const status = pass === true ? 'ok' : 'not ok';
|
9 | console.log(`${status} ${id} ${assertion.message}`);
|
10 | if (pass !== true) {
|
11 | console.log(` ---
|
12 | operator: ${assertion.operator}
|
13 | expected: ${stringify(assertion.expected)}
|
14 | actual: ${stringify(assertion.actual)}
|
15 | at: ${(assertion.at || '')}
|
16 | ...
|
17 | `);
|
18 | }
|
19 | };
|
20 | const printSummary = ({count, pass, skipped, fail}) => {
|
21 |
|
22 | console.log(`1..${count}`);
|
23 | console.log(`# tests ${count} (${skipped} skipped)`);
|
24 | console.log(`# pass ${pass}`);
|
25 | if (fail > 0) {
|
26 | console.log(`# fail ${fail}`);
|
27 | } else {
|
28 | console.log('# ok');
|
29 | }
|
30 | };
|
31 |
|
32 | var tap = ({displaySkipped = false} = {}) => function * () {
|
33 | let pass = 0;
|
34 | let fail = 0;
|
35 | let id = 0;
|
36 | let skipped = 0;
|
37 | console.log('TAP version 13');
|
38 | try {
|
39 |
|
40 | while (true) {
|
41 | const test = yield;
|
42 |
|
43 | if (test.items.length === 0) {
|
44 | skipped++;
|
45 | }
|
46 |
|
47 | if (test.items.length > 0 || displaySkipped === true) {
|
48 | printTestHeader(test);
|
49 | }
|
50 |
|
51 | for (const assertion of test.items) {
|
52 | id++;
|
53 | if (assertion.pass === true) {
|
54 | pass++;
|
55 | } else {
|
56 | fail++;
|
57 | }
|
58 | printTestCase(assertion, id);
|
59 | }
|
60 | }
|
61 |
|
62 | } catch (err) {
|
63 | console.log('Bail out! unhandled exception');
|
64 | throw err;
|
65 | } finally {
|
66 | printSummary({count: id, pass, skipped, fail});
|
67 | }
|
68 | };
|
69 |
|
70 | function createCommonjsModule(fn, module) {
|
71 | return module = { exports: {} }, fn(module, module.exports), module.exports;
|
72 | }
|
73 |
|
74 | var keys = createCommonjsModule(function (module, exports) {
|
75 | exports = module.exports = typeof Object.keys === 'function'
|
76 | ? Object.keys : shim;
|
77 |
|
78 | exports.shim = shim;
|
79 | function shim (obj) {
|
80 | var keys = [];
|
81 | for (var key in obj) keys.push(key);
|
82 | return keys;
|
83 | }
|
84 | });
|
85 |
|
86 | var keys_1 = keys.shim;
|
87 |
|
88 | var is_arguments = createCommonjsModule(function (module, exports) {
|
89 | var supportsArgumentsClass = (function(){
|
90 | return Object.prototype.toString.call(arguments)
|
91 | })() == '[object Arguments]';
|
92 |
|
93 | exports = module.exports = supportsArgumentsClass ? supported : unsupported;
|
94 |
|
95 | exports.supported = supported;
|
96 | function supported(object) {
|
97 | return Object.prototype.toString.call(object) == '[object Arguments]';
|
98 | }
|
99 |
|
100 | exports.unsupported = unsupported;
|
101 | function unsupported(object){
|
102 | return object &&
|
103 | typeof object == 'object' &&
|
104 | typeof object.length == 'number' &&
|
105 | Object.prototype.hasOwnProperty.call(object, 'callee') &&
|
106 | !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
|
107 | false;
|
108 | }
|
109 | });
|
110 |
|
111 | var is_arguments_1 = is_arguments.supported;
|
112 | var is_arguments_2 = is_arguments.unsupported;
|
113 |
|
114 | var deepEqual_1 = createCommonjsModule(function (module) {
|
115 | var pSlice = Array.prototype.slice;
|
116 |
|
117 |
|
118 |
|
119 | var deepEqual = module.exports = function (actual, expected, opts) {
|
120 | if (!opts) opts = {};
|
121 |
|
122 | if (actual === expected) {
|
123 | return true;
|
124 |
|
125 | } else if (actual instanceof Date && expected instanceof Date) {
|
126 | return actual.getTime() === expected.getTime();
|
127 |
|
128 |
|
129 |
|
130 | } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
|
131 | return opts.strict ? actual === expected : actual == expected;
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | } else {
|
140 | return objEquiv(actual, expected, opts);
|
141 | }
|
142 | };
|
143 |
|
144 | function isUndefinedOrNull(value) {
|
145 | return value === null || value === undefined;
|
146 | }
|
147 |
|
148 | function isBuffer (x) {
|
149 | if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
|
150 | if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
|
151 | return false;
|
152 | }
|
153 | if (x.length > 0 && typeof x[0] !== 'number') return false;
|
154 | return true;
|
155 | }
|
156 |
|
157 | function objEquiv(a, b, opts) {
|
158 | var i, key;
|
159 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
160 | return false;
|
161 |
|
162 | if (a.prototype !== b.prototype) return false;
|
163 |
|
164 |
|
165 | if (is_arguments(a)) {
|
166 | if (!is_arguments(b)) {
|
167 | return false;
|
168 | }
|
169 | a = pSlice.call(a);
|
170 | b = pSlice.call(b);
|
171 | return deepEqual(a, b, opts);
|
172 | }
|
173 | if (isBuffer(a)) {
|
174 | if (!isBuffer(b)) {
|
175 | return false;
|
176 | }
|
177 | if (a.length !== b.length) return false;
|
178 | for (i = 0; i < a.length; i++) {
|
179 | if (a[i] !== b[i]) return false;
|
180 | }
|
181 | return true;
|
182 | }
|
183 | try {
|
184 | var ka = keys(a),
|
185 | kb = keys(b);
|
186 | } catch (e) {
|
187 | return false;
|
188 | }
|
189 |
|
190 |
|
191 | if (ka.length != kb.length)
|
192 | return false;
|
193 |
|
194 | ka.sort();
|
195 | kb.sort();
|
196 |
|
197 | for (i = ka.length - 1; i >= 0; i--) {
|
198 | if (ka[i] != kb[i])
|
199 | return false;
|
200 | }
|
201 |
|
202 |
|
203 | for (i = ka.length - 1; i >= 0; i--) {
|
204 | key = ka[i];
|
205 | if (!deepEqual(a[key], b[key], opts)) return false;
|
206 | }
|
207 | return typeof a === typeof b;
|
208 | }
|
209 | });
|
210 |
|
211 | const getAssertionLocation = () => {
|
212 | const err = new Error();
|
213 | const stack = (err.stack || '').split('\n');
|
214 | return (stack[3] || '').trim().replace(/^at/i, '');
|
215 | };
|
216 | const assertMethodHook = fn => function (...args) {
|
217 | const assertResult = fn(...args);
|
218 |
|
219 | if (assertResult.pass === false) {
|
220 | assertResult.at = getAssertionLocation();
|
221 | }
|
222 |
|
223 | this.collect(assertResult);
|
224 | return assertResult;
|
225 | };
|
226 |
|
227 | const Assertion = {
|
228 | ok: assertMethodHook((val, message = 'should be truthy') => ({
|
229 | pass: Boolean(val),
|
230 | actual: val,
|
231 | expected: true,
|
232 | message,
|
233 | operator: 'ok'
|
234 | })),
|
235 | deepEqual: assertMethodHook((actual, expected, message = 'should be equivalent') => ({
|
236 | pass: deepEqual_1(actual, expected),
|
237 | actual,
|
238 | expected,
|
239 | message,
|
240 | operator: 'deepEqual'
|
241 | })),
|
242 | equal: assertMethodHook((actual, expected, message = 'should be equal') => ({
|
243 | pass: actual === expected,
|
244 | actual,
|
245 | expected,
|
246 | message,
|
247 | operator: 'equal'
|
248 | })),
|
249 | notOk: assertMethodHook((val, message = 'should not be truthy') => ({
|
250 | pass: !val,
|
251 | expected: false,
|
252 | actual: val,
|
253 | message,
|
254 | operator: 'notOk'
|
255 | })),
|
256 | notDeepEqual: assertMethodHook((actual, expected, message = 'should not be equivalent') => ({
|
257 | pass: !deepEqual_1(actual, expected),
|
258 | actual,
|
259 | expected,
|
260 | message,
|
261 | operator: 'notDeepEqual'
|
262 | })),
|
263 | notEqual: assertMethodHook((actual, expected, message = 'should not be equal') => ({
|
264 | pass: actual !== expected,
|
265 | actual,
|
266 | expected,
|
267 | message,
|
268 | operator: 'notEqual'
|
269 | })),
|
270 | throws: assertMethodHook((func, expected, message) => {
|
271 | let caught;
|
272 | let pass;
|
273 | let actual;
|
274 | if (typeof expected === 'string') {
|
275 | [expected, message] = [message, expected];
|
276 | }
|
277 | try {
|
278 | func();
|
279 | } catch (err) {
|
280 | caught = {error: err};
|
281 | }
|
282 | pass = caught !== undefined;
|
283 | actual = caught && caught.error;
|
284 | if (expected instanceof RegExp) {
|
285 | pass = expected.test(actual) || expected.test(actual && actual.message);
|
286 | expected = String(expected);
|
287 | } else if (typeof expected === 'function' && caught) {
|
288 | pass = actual instanceof expected;
|
289 | actual = actual.constructor;
|
290 | }
|
291 | return {
|
292 | pass,
|
293 | expected,
|
294 | actual,
|
295 | operator: 'throws',
|
296 | message: message || 'should throw'
|
297 | };
|
298 | }),
|
299 | doesNotThrow: assertMethodHook((func, expected, message) => {
|
300 | let caught;
|
301 | if (typeof expected === 'string') {
|
302 | [expected, message] = [message, expected];
|
303 | }
|
304 | try {
|
305 | func();
|
306 | } catch (err) {
|
307 | caught = {error: err};
|
308 | }
|
309 | return {
|
310 | pass: caught === undefined,
|
311 | expected: 'no thrown error',
|
312 | actual: caught && caught.error,
|
313 | operator: 'doesNotThrow',
|
314 | message: message || 'should not throw'
|
315 | };
|
316 | }),
|
317 | fail: assertMethodHook((message = 'fail called') => ({
|
318 | pass: false,
|
319 | actual: 'fail called',
|
320 | expected: 'fail not called',
|
321 | message,
|
322 | operator: 'fail'
|
323 | }))
|
324 | };
|
325 |
|
326 | var assert = collect => Object.create(Assertion, {collect: {value: collect}});
|
327 |
|
328 | const noop = () => {};
|
329 |
|
330 | const skip = description => test('SKIPPED - ' + description, noop);
|
331 |
|
332 | const Test = {
|
333 | async run() {
|
334 | const collect = assertion => this.items.push(assertion);
|
335 | const start = Date.now();
|
336 | await Promise.resolve(this.spec(assert(collect)));
|
337 | const executionTime = Date.now() - start;
|
338 | return Object.assign(this, {
|
339 | executionTime
|
340 | });
|
341 | },
|
342 | skip() {
|
343 | return skip(this.description);
|
344 | }
|
345 | };
|
346 |
|
347 | function test(description, spec, {only = false} = {}) {
|
348 | return Object.create(Test, {
|
349 | items: {value: []},
|
350 | only: {value: only},
|
351 | spec: {value: spec},
|
352 | description: {value: description}
|
353 | });
|
354 | }
|
355 |
|
356 |
|
357 | const onNextTick = val => new Promise(resolve => setTimeout(() => resolve(val), 0));
|
358 |
|
359 | const PlanProto = {
|
360 | [Symbol.iterator]() {
|
361 | return this.items[Symbol.iterator]();
|
362 | },
|
363 | test(description, spec, opts) {
|
364 | if (!spec && description.test) {
|
365 |
|
366 | this.items.push(...description);
|
367 | } else {
|
368 | this.items.push(test(description, spec, opts));
|
369 | }
|
370 | return this;
|
371 | },
|
372 | only(description, spec) {
|
373 | return this.test(description, spec, {only: true});
|
374 | },
|
375 | skip(description, spec) {
|
376 | if (!spec && description.test) {
|
377 |
|
378 | for (const t of description) {
|
379 | this.items.push(t.skip());
|
380 | }
|
381 | } else {
|
382 | this.items.push(skip(description));
|
383 | }
|
384 | return this;
|
385 | }
|
386 | };
|
387 |
|
388 | const runnify = fn => async function (sink = tap()) {
|
389 | const sinkIterator = typeof sink[Symbol.iterator] === 'function' ?
|
390 | sink[Symbol.iterator]() :
|
391 | sink();
|
392 | sinkIterator.next();
|
393 | try {
|
394 | const hasOnly = this.items.some(t => t.only);
|
395 | const tests = hasOnly ? this.items.map(t => t.only ? t : t.skip()) : this.items;
|
396 | await fn(tests, sinkIterator);
|
397 | } catch (err) {
|
398 | sinkIterator.throw(err);
|
399 | } finally {
|
400 | sinkIterator.return();
|
401 | }
|
402 | };
|
403 |
|
404 | function factory({sequence = false} = {sequence: false}) {
|
405 |
|
406 | const exec = sequence === true ? async (tests, sinkIterator) => {
|
407 | for (const t of tests) {
|
408 | const result = await onNextTick(t.run());
|
409 | sinkIterator.next(result);
|
410 | }
|
411 | } : async (tests, sinkIterator) => {
|
412 | const runningTests = tests.map(t => t.run());
|
413 | for (const r of runningTests) {
|
414 | const executedTest = await onNextTick(r);
|
415 | sinkIterator.next(executedTest);
|
416 | }
|
417 | };
|
418 |
|
419 |
|
420 | return Object.assign(Object.create(PlanProto, {
|
421 | items: {value: []}, length: {
|
422 | get() {
|
423 | return this.items.length;
|
424 | }
|
425 | }
|
426 | }), {
|
427 | run: runnify(exec)
|
428 | });
|
429 | }
|
430 |
|
431 | return factory;
|
432 |
|
433 | }());
|
434 |
|