UNPKG

14.8 kBJavaScriptView Raw
1function createCommonjsModule(fn, module) {
2 return module = { exports: {} }, fn(module, module.exports), module.exports;
3}
4
5var keys = createCommonjsModule(function (module, exports) {
6exports = module.exports = typeof Object.keys === 'function'
7 ? Object.keys : shim;
8
9exports.shim = shim;
10function shim (obj) {
11 var keys = [];
12 for (var key in obj) keys.push(key);
13 return keys;
14}
15});
16
17var keys_1 = keys.shim;
18
19var is_arguments = createCommonjsModule(function (module, exports) {
20var supportsArgumentsClass = (function(){
21 return Object.prototype.toString.call(arguments)
22})() == '[object Arguments]';
23
24exports = module.exports = supportsArgumentsClass ? supported : unsupported;
25
26exports.supported = supported;
27function supported(object) {
28 return Object.prototype.toString.call(object) == '[object Arguments]';
29}
30
31exports.unsupported = unsupported;
32function unsupported(object){
33 return object &&
34 typeof object == 'object' &&
35 typeof object.length == 'number' &&
36 Object.prototype.hasOwnProperty.call(object, 'callee') &&
37 !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
38 false;
39}
40});
41
42var is_arguments_1 = is_arguments.supported;
43var is_arguments_2 = is_arguments.unsupported;
44
45var deepEqual_1 = createCommonjsModule(function (module) {
46var pSlice = Array.prototype.slice;
47
48
49
50var deepEqual = module.exports = function (actual, expected, opts) {
51 if (!opts) opts = {};
52 // 7.1. All identical values are equivalent, as determined by ===.
53 if (actual === expected) {
54 return true;
55
56 } else if (actual instanceof Date && expected instanceof Date) {
57 return actual.getTime() === expected.getTime();
58
59 // 7.3. Other pairs that do not both pass typeof value == 'object',
60 // equivalence is determined by ==.
61 } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
62 return opts.strict ? actual === expected : actual == expected;
63
64 // 7.4. For all other Object pairs, including Array objects, equivalence is
65 // determined by having the same number of owned properties (as verified
66 // with Object.prototype.hasOwnProperty.call), the same set of keys
67 // (although not necessarily the same order), equivalent values for every
68 // corresponding key, and an identical 'prototype' property. Note: this
69 // accounts for both named and indexed properties on Arrays.
70 } else {
71 return objEquiv(actual, expected, opts);
72 }
73};
74
75function isUndefinedOrNull(value) {
76 return value === null || value === undefined;
77}
78
79function isBuffer (x) {
80 if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
81 if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
82 return false;
83 }
84 if (x.length > 0 && typeof x[0] !== 'number') return false;
85 return true;
86}
87
88function objEquiv(a, b, opts) {
89 var i, key;
90 if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
91 return false;
92 // an identical 'prototype' property.
93 if (a.prototype !== b.prototype) return false;
94 //~~~I've managed to break Object.keys through screwy arguments passing.
95 // Converting to array solves the problem.
96 if (is_arguments(a)) {
97 if (!is_arguments(b)) {
98 return false;
99 }
100 a = pSlice.call(a);
101 b = pSlice.call(b);
102 return deepEqual(a, b, opts);
103 }
104 if (isBuffer(a)) {
105 if (!isBuffer(b)) {
106 return false;
107 }
108 if (a.length !== b.length) return false;
109 for (i = 0; i < a.length; i++) {
110 if (a[i] !== b[i]) return false;
111 }
112 return true;
113 }
114 try {
115 var ka = keys(a),
116 kb = keys(b);
117 } catch (e) {//happens when one is a string literal and the other isn't
118 return false;
119 }
120 // having the same number of owned properties (keys incorporates
121 // hasOwnProperty)
122 if (ka.length != kb.length)
123 return false;
124 //the same set of keys (although not necessarily the same order),
125 ka.sort();
126 kb.sort();
127 //~~~cheap key test
128 for (i = ka.length - 1; i >= 0; i--) {
129 if (ka[i] != kb[i])
130 return false;
131 }
132 //equivalent values for every corresponding key, and
133 //~~~possibly expensive deep test
134 for (i = ka.length - 1; i >= 0; i--) {
135 key = ka[i];
136 if (!deepEqual(a[key], b[key], opts)) return false;
137 }
138 return typeof a === typeof b;
139}
140});
141
142const getAssertionLocation = () => {
143 const err = new Error();
144 const stack = (err.stack || '').split('\n');
145 return (stack[3] || '').trim().replace(/^at/i, '');
146};
147
148const assertMethodHook = fn => function (...args) {
149 const assertResult = fn(...args);
150
151 if (assertResult.pass === false) {
152 assertResult.at = getAssertionLocation();
153 }
154
155 this.collect(assertResult);
156 return assertResult;
157};
158
159const Assertion = {
160 ok: assertMethodHook((val, description = 'should be truthy') => ({
161 pass: Boolean(val),
162 actual: val,
163 expected: true,
164 description,
165 operator: 'ok'
166 })),
167 deepEqual: assertMethodHook((actual, expected, description = 'should be equivalent') => ({
168 pass: deepEqual_1(actual, expected),
169 actual,
170 expected,
171 description,
172 operator: 'deepEqual'
173 })),
174 equal: assertMethodHook((actual, expected, description = 'should be equal') => ({
175 pass: actual === expected,
176 actual,
177 expected,
178 description,
179 operator: 'equal'
180 })),
181 notOk: assertMethodHook((val, description = 'should not be truthy') => ({
182 pass: !val,
183 expected: false,
184 actual: val,
185 description,
186 operator: 'notOk'
187 })),
188 notDeepEqual: assertMethodHook((actual, expected, description = 'should not be equivalent') => ({
189 pass: !deepEqual_1(actual, expected),
190 actual,
191 expected,
192 description,
193 operator: 'notDeepEqual'
194 })),
195 notEqual: assertMethodHook((actual, expected, description = 'should not be equal') => ({
196 pass: actual !== expected,
197 actual,
198 expected,
199 description,
200 operator: 'notEqual'
201 })),
202 throws: assertMethodHook((func, expected, description) => {
203 let caught;
204 let pass;
205 let actual;
206 if (typeof expected === 'string') {
207 [expected, description] = [description, expected];
208 }
209 try {
210 func();
211 } catch (err) {
212 caught = {error: err};
213 }
214 pass = caught !== undefined;
215 actual = caught && caught.error;
216 if (expected instanceof RegExp) {
217 pass = expected.test(actual) || expected.test(actual && actual.message);
218 expected = String(expected);
219 } else if (typeof expected === 'function' && caught) {
220 pass = actual instanceof expected;
221 actual = actual.constructor;
222 }
223 return {
224 pass,
225 expected,
226 actual,
227 operator: 'throws',
228 description: description || 'should throw'
229 };
230 }),
231 doesNotThrow: assertMethodHook((func, expected, description) => {
232 let caught;
233 if (typeof expected === 'string') {
234 [expected, description] = [description, expected];
235 }
236 try {
237 func();
238 } catch (err) {
239 caught = {error: err};
240 }
241 return {
242 pass: caught === undefined,
243 expected: 'no thrown error',
244 actual: caught && caught.error,
245 operator: 'doesNotThrow',
246 description: description || 'should not throw'
247 };
248 }),
249 fail: assertMethodHook((description = 'fail called') => ({
250 pass: false,
251 actual: 'fail called',
252 expected: 'fail not called',
253 description,
254 operator: 'fail'
255 }))
256};
257
258var assert = (collect, test) => Object.assign(
259 Object.create(Assertion, {collect: {value: collect}}), {
260 async test(description, spec) {
261 // Note: we return the task so the caller can control whether he wants to wait for the sub test to complete or not
262 return test(description, spec).task;
263 }
264 });
265
266const tester = (collect, {offset = 0} = {}) => (description, spec) => {
267 const buffer = [{type: 'title', data: description, offset}];
268 const result = {count: 0, pass: true, description, spec};
269 let done = false;
270
271 const createAssertion = item => {
272 result.pass = result.pass && item.pass;
273 return {type: 'assert', data: item, offset};
274 };
275
276 const collector = item => {
277 result.count++;
278 item.id = result.count;
279 if (item[Symbol.asyncIterator] === undefined) {
280 // Assertion
281 buffer.push(createAssertion(item));
282 } else {
283 // Sub test
284 buffer.push(item);
285 }
286 };
287
288 const handleDelegate = async delegate => {
289 const {value, done} = await delegate.next();
290
291 // Delegate is exhausted: create a summary test point in the stream and throw the delegate
292 if (done === true) {
293 const {executionTime, pass, description} = value;
294 const subTestAssertion = Object.assign(createAssertion({
295 pass,
296 description,
297 id: delegate.id,
298 executionTime
299 }), {type: 'testAssert'});
300 buffer.shift();
301 buffer.unshift(subTestAssertion);
302 return instance.next();
303 }
304 return {value, done};
305 };
306
307 const subTest = tester(collector, {offset: offset + 1});
308
309 const start = Date.now();
310 // Execute the test collecting assertions
311 const assertFn = assert(collector, subTest);
312 const task = new Promise(resolve => resolve(spec(assertFn)))
313 .then(() => {
314 // Always report a plan and summary: the calling test will know how to deal with it
315 result.executionTime = Date.now() - start;
316 buffer.push({type: 'plan', data: {start: 1, end: result.count}, offset});
317 buffer.push({type: 'time', data: result.executionTime, offset});
318 done = true;
319 return result;
320 })
321 .catch(err => {
322 // We report a failing test before bail out ... while unhandled promise rejection is still allowed by nodejs...
323 buffer.push({type: 'assert', data: {pass: false, description}});
324 buffer.push({type: 'comment', data: 'Unhandled exception'});
325 buffer.push({type: 'bailout', data: err, offset});
326 done = true;
327 });
328
329 const instance = {
330 test: subTest,
331 task,
332 [Symbol.asyncIterator]() {
333 return this;
334 },
335 async next() {
336 if (buffer.length === 0) {
337 if (done === true) {
338 return {done: true, value: result};
339 }
340 // Flush
341 await task;
342 return this.next();
343 }
344
345 const next = buffer[0];
346
347 // Delegate if sub test
348 if (next[Symbol.asyncIterator] !== undefined) {
349 return handleDelegate(next);
350 }
351
352 return {value: buffer.shift(), done: false};
353 }
354 };
355
356 // Collection by the calling test
357 collect(instance);
358
359 return instance;
360};
361
362const print = (message, offset = 0) => {
363 console.log(message.padStart(message.length + (offset * 4))); // 4 white space used as indent (see tap-parser)
364};
365
366const toYaml = print => (obj, offset = 0) => {
367 for (const [prop, value] of Object.entries(obj)) {
368 print(`${prop}: ${JSON.stringify(value)}`, offset + 0.5);
369 }
370};
371
372const tap = print => {
373 const yaml = toYaml(print);
374 return {
375 version(version = 13) {
376 print(`TAP version ${version}`);
377 },
378 title(value, offset = 0) {
379 const message = offset > 0 ? `Subtest: ${value}` : value;
380 this.comment(message, offset);
381 },
382 assert(value, offset = 0) {
383 const {pass, description, id, executionTime, expected = '', actual = '', at = '', operator = ''} = value;
384 const label = pass === true ? 'ok' : 'not ok';
385 print(`${label} ${id} - ${description}${executionTime ? ` # time=${executionTime}ms` : ''}`, offset);
386 if (pass === false && value.operator) {
387 print('---', offset + 0.5);
388 yaml({expected, actual, at, operator}, offset);
389 print('...', offset + 0.5);
390 }
391 },
392 plan(value, offset = 0) {
393 print(`1..${value.end}`, offset);
394 },
395 time(value, offset = 0) {
396 this.comment(`time=${value}ms`, offset);
397 },
398 comment(value, offset = 0) {
399 print(`# ${value}`, offset);
400 },
401 bailout(value = 'Unhandled exception') {
402 print(`Bail out! ${value}`);
403 },
404 testAssert(value, offset = 0) {
405 return this.assert(value, offset);
406 }
407 };
408};
409
410var tap$1 = (printFn = print) => {
411 const reporter = tap(printFn);
412 return (toPrint = {}) => {
413 const {data, type, offset = 0} = toPrint;
414 if (typeof reporter[type] === 'function') {
415 reporter[type](data, offset);
416 }
417 // Else ignore (unknown message type)
418 };
419};
420
421// Some combinators for asynchronous iterators: this will be way more easier when
422// Async generator are widely supported
423
424const asyncIterator = behavior => Object.assign({
425 [Symbol.asyncIterator]() {
426 return this;
427 }
428}, behavior);
429
430const filter = predicate => iterator => asyncIterator({
431 async next() {
432 const {done, value} = await iterator.next();
433
434 if (done === true) {
435 return {done};
436 }
437
438 if (!predicate(value)) {
439 return this.next();
440 }
441
442 return {done, value};
443 }
444});
445
446const map = mapFn => iterator => asyncIterator({
447 [Symbol.asyncIterator]() {
448 return this;
449 },
450 async next() {
451 const {done, value} = await iterator.next();
452 if (done === true) {
453 return {done};
454 }
455 return {done, value: mapFn(value)};
456 }
457});
458
459const stream = asyncIterator => Object.assign(asyncIterator, {
460 map(fn) {
461 return stream(map(fn)(asyncIterator));
462 },
463 filter(fn) {
464 return stream(filter(fn)(asyncIterator));
465 }
466});
467
468const combine = (...iterators) => {
469 const [...pending] = iterators;
470 let current = pending.shift();
471
472 return asyncIterator({
473 async next() {
474 if (current === undefined) {
475 return {done: true};
476 }
477
478 const {done, value} = await current.next();
479
480 if (done === true) {
481 current = pending.shift();
482 return this.next();
483 }
484
485 return {done, value};
486 }
487 });
488};
489
490let flatten = true;
491const tests = [];
492const test = tester(t => tests.push(t));
493
494// Provide a root context for BSD style test suite
495const subTest = (test('Root', () => {})).test;
496test.test = (description, spec) => {
497 flatten = false; // Turn reporter into BSD style
498 return subTest(description, spec);
499};
500
501const start = async ({reporter = tap$1()} = {}) => {
502 let count = 0;
503 let failure = 0;
504 reporter({type: 'version', data: 13});
505
506 // Remove the irrelevant root title
507 await tests[0].next();
508
509 let outputStream = stream(combine(...tests));
510 outputStream = flatten ? outputStream
511 .filter(({type}) => type !== 'testAssert')
512 .map(item => Object.assign(item, {offset: 0})) :
513 outputStream;
514
515 const filterOutAtRootLevel = ['plan', 'time'];
516 outputStream = outputStream
517 .filter(item => item.offset > 0 || !filterOutAtRootLevel.includes(item.type))
518 .map(item => {
519 if (item.offset > 0 || (item.type !== 'assert' && item.type !== 'testAssert')) {
520 return item;
521 }
522
523 count++;
524 item.data.id = count;
525 failure += item.data.pass ? 0 : 1;
526 return item;
527 });
528
529 // One day with for await loops ... :) !
530 while (true) {
531 const {done, value} = await outputStream.next();
532
533 if (done === true) {
534 break;
535 }
536
537 reporter(value);
538
539 if (value.type === 'bailout') {
540 throw value.data; // Rethrow but with Nodejs we keep getting the deprecation warning (unhandled promise) and the process exists with 0 exit code...
541 }
542 }
543
544 reporter({type: 'plan', data: {start: 1, end: count}});
545 reporter({type: 'comment', data: failure > 0 ? `failed ${failure} of ${count} tests` : 'ok'});
546};
547
548// Auto bootstrap following async env vs sync env (browser vs node)
549if (typeof window === 'undefined') {
550 setTimeout(start, 0);
551} else {
552 window.addEventListener('load', start);
553}
554
555export default test;
556//# sourceMappingURL=zora.es.js.map