UNPKG

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