UNPKG

81.9 kBJavaScriptView Raw
1/* global setTimeout */
2var utils = require('./utils');
3var arrayChanges = require('array-changes');
4var arrayChangesAsync = require('array-changes-async');
5var throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
6var objectIs = utils.objectIs;
7var extend = utils.extend;
8
9module.exports = function (expect) {
10 expect.addAssertion('<any> [not] to be (ok|truthy)', function (expect, subject) {
11 var not = !!expect.flags.not;
12 var condition = !!subject;
13 if (condition === not) {
14 expect.fail();
15 }
16 });
17
18 expect.addAssertion(
19 '<any> [not] to be (ok|truthy) <string>',
20 function (expect, subject, message) {
21 var not = !!expect.flags.not;
22 var condition = !!subject;
23 if (condition === not) {
24 expect.fail({
25 errorMode: 'bubble',
26 message: message
27 });
28 }
29 }
30 );
31
32 expect.addAssertion('<any> [not] to be <any>', function (expect, subject, value) {
33 if (objectIs(subject, value) === expect.flags.not) {
34 expect.fail({
35 label: 'should be'
36 });
37 }
38 });
39
40 expect.addAssertion(
41 '<string> [not] to be <string>',
42 function (expect, subject, value) {
43 expect(subject, '[not] to equal', value);
44 }
45 );
46
47 expect.addAssertion('<boolean> [not] to be true', function (expect, subject) {
48 expect(subject, '[not] to be', true);
49 });
50
51 expect.addAssertion('<boolean> [not] to be false', function (expect, subject) {
52 expect(subject, '[not] to be', false);
53 });
54
55 expect.addAssertion('<any> [not] to be falsy', function (expect, subject) {
56 expect(subject, '[!not] to be truthy');
57 });
58
59 expect.addAssertion(
60 '<any> [not] to be falsy <string>',
61 function (expect, subject, message) {
62 var not = !!expect.flags.not;
63 var condition = !!subject;
64 if (condition !== not) {
65 expect.fail({
66 errorMode: 'bubble',
67 message: message
68 });
69 }
70 }
71 );
72
73 expect.addAssertion('<any> [not] to be null', function (expect, subject) {
74 expect(subject, '[not] to be', null);
75 });
76
77 expect.addAssertion('<any> [not] to be undefined', function (expect, subject) {
78 expect(typeof subject === 'undefined', '[not] to be truthy');
79 });
80
81 expect.addAssertion('<any> to be defined', function (expect, subject) {
82 expect(subject, 'not to be undefined');
83 });
84
85 expect.addAssertion('<number|NaN> [not] to be NaN', function (expect, subject) {
86 expect(isNaN(subject), '[not] to be truthy');
87 });
88
89 expect.addAssertion(
90 '<number> [not] to be close to <number> <number?>',
91 function (expect, subject, value, epsilon) {
92 expect.errorMode = 'bubble';
93 if (typeof epsilon !== 'number') {
94 epsilon = 1e-9;
95 }
96
97 expect.withError(
98 function () {
99 expect(
100 Math.abs(subject - value),
101 '[not] to be less than or equal to',
102 epsilon
103 );
104 },
105 function (e) {
106 expect.fail(function (output) {
107 output
108 .error('expected ')
109 .appendInspected(subject)
110 .sp()
111 .error(expect.testDescription)
112 .sp()
113 .appendInspected(value)
114 .sp()
115 .text('(epsilon: ')
116 .jsNumber(epsilon.toExponential())
117 .text(')');
118 });
119 }
120 );
121 }
122 );
123
124 expect.addAssertion(
125 '<any> [not] to be (a|an) <type>',
126 function (expect, subject, type) {
127 expect.argsOutput[0] = function (output) {
128 output.text(type.name);
129 };
130 expect(type.identify(subject), '[not] to be true');
131 }
132 );
133
134 expect.addAssertion(
135 '<any> [not] to be (a|an) <string>',
136 function (expect, subject, typeName) {
137 typeName = /^reg(?:exp?|ular expression)$/.test(typeName)
138 ? 'regexp'
139 : typeName;
140 expect.argsOutput[0] = function (output) {
141 output.jsString(typeName);
142 };
143 if (!expect.getType(typeName)) {
144 expect.errorMode = 'nested';
145 expect.fail(function (output) {
146 output
147 .error('Unknown type:')
148 .sp()
149 .jsString(typeName);
150 });
151 }
152 expect(expect.subjectType.is(typeName), '[not] to be truthy');
153 }
154 );
155
156 expect.addAssertion(
157 '<any> [not] to be (a|an) <function>',
158 function (expect, subject, Constructor) {
159 var className = utils.getFunctionName(Constructor);
160 if (className) {
161 expect.argsOutput[0] = function (output) {
162 output.text(className);
163 };
164 }
165 expect(subject instanceof Constructor, '[not] to be truthy');
166 }
167 );
168
169 expect.addAssertion(
170 '<any> [not] to be one of <array>',
171 function (expect, subject, superset) {
172 var found = false;
173
174 for (var i = 0; i < superset.length; i += 1) {
175 found = found || objectIs(subject, superset[i]);
176 }
177
178 if (found === expect.flags.not) {
179 expect.fail();
180 }
181 }
182 );
183
184 // Alias for common '[not] to be (a|an)' assertions
185 expect.addAssertion(
186 '<any> [not] to be an (object|array)',
187 function (expect, subject) {
188 expect(subject, '[not] to be an', expect.alternations[0]);
189 }
190 );
191
192 expect.addAssertion(
193 '<any> [not] to be a (boolean|number|string|function|regexp|regex|regular expression|date)',
194 function (expect, subject) {
195 expect(subject, '[not] to be a', expect.alternations[0]);
196 }
197 );
198
199 expect.addAssertion(
200 '<string> to be (the empty|an empty|a non-empty) string',
201 function (expect, subject) {
202 expect(
203 subject,
204 expect.alternations[0] === 'a non-empty'
205 ? 'not to be empty'
206 : 'to be empty'
207 );
208 }
209 );
210
211 expect.addAssertion(
212 '<array-like> to be (the empty|an empty|a non-empty) array',
213 function (expect, subject) {
214 expect(
215 subject,
216 expect.alternations[0] === 'a non-empty'
217 ? 'not to be empty'
218 : 'to be empty'
219 );
220 }
221 );
222
223 expect.addAssertion('<string> to match <regexp>', function (expect, subject, regexp) { return expect.withError(
224 function () {
225 var captures = subject.match(regexp);
226 expect(captures, 'to be truthy');
227 return captures;
228 },
229 function (e) {
230 e.label = 'should match';
231 expect.fail(e);
232 }
233 ); }
234 );
235
236 expect.addAssertion(
237 '<string> not to match <regexp>',
238 function (expect, subject, regexp) { return expect.withError(
239 function () {
240 expect(regexp.test(subject), 'to be false');
241 },
242 function (e) {
243 expect.fail({
244 label: 'should not match',
245 diff: function diff(output) {
246 output.inline = false;
247 var lastIndex = 0;
248 function flushUntilIndex(i) {
249 if (i > lastIndex) {
250 output.text(subject.substring(lastIndex, i));
251 lastIndex = i;
252 }
253 }
254 subject.replace(new RegExp(regexp.source, 'g'), function ($0, index) {
255 flushUntilIndex(index);
256 lastIndex += $0.length;
257 output.removedHighlight($0);
258 });
259 flushUntilIndex(subject.length);
260 return output;
261 }
262 });
263 }
264 ); }
265 );
266
267 expect.addAssertion(
268 '<object> [not] to have own property <string>',
269 function (expect, subject, key) {
270 expect(subject.hasOwnProperty(key), '[not] to be truthy');
271 return subject[key];
272 }
273 );
274
275 expect.addAssertion(
276 '<object> [not] to have (enumerable|configurable|writable) property <string>',
277 function (expect, subject, key) {
278 var descriptor = expect.alternations[0];
279 expect(
280 Object.getOwnPropertyDescriptor(subject, key)[descriptor],
281 '[not] to be truthy'
282 );
283 return subject[key];
284 }
285 );
286
287 expect.addAssertion(
288 '<object> [not] to have property <string>',
289 function (expect, subject, key) {
290 var subjectType = expect.findTypeOf(subject);
291 var subjectKey = subjectType.is('function')
292 ? subject[key]
293 : subjectType.valueForKey(subject, key);
294 expect(subjectKey, '[!not] to be undefined');
295 return subjectKey;
296 }
297 );
298
299 expect.addAssertion(
300 '<object> to have [own] property <string> <any>',
301 function (expect, subject, key, expectedPropertyValue) { return expect(subject, 'to have [own] property', key).then(
302 function (actualPropertyValue) {
303 expect.argsOutput = function() {
304 this.appendInspected(key)
305 .sp()
306 .error('with a value of')
307 .sp()
308 .appendInspected(expectedPropertyValue);
309 };
310 expect(actualPropertyValue, 'to equal', expectedPropertyValue);
311 return actualPropertyValue;
312 }
313 ); }
314 );
315
316 expect.addAssertion(
317 '<object> [not] to have [own] properties <array>',
318 function (expect, subject, propertyNames) {
319 var unsupportedPropertyNames = [];
320 propertyNames.forEach(function (propertyName) {
321 if (
322 typeof propertyName !== 'string' &&
323 typeof propertyName !== 'number'
324 ) {
325 unsupportedPropertyNames.push(propertyName);
326 }
327 });
328 if (unsupportedPropertyNames.length > 0) {
329 expect.errorMode = 'nested';
330 expect.fail(function() {
331 this.error(
332 'All expected properties must be passed as strings or numbers, but these are not:'
333 ).indentLines();
334 unsupportedPropertyNames.forEach(function(propertyName) {
335 this.nl()
336 .i()
337 .appendInspected(propertyName);
338 }, this);
339 this.outdentLines();
340 });
341 }
342 propertyNames.forEach(function (propertyName) {
343 expect(subject, '[not] to have [own] property', String(propertyName));
344 });
345 }
346 );
347
348 expect.addAssertion(
349 '<object> to have [own] properties <object>',
350 function (expect, subject, properties) {
351 expect.withError(
352 function () {
353 Object.keys(properties).forEach(function (property) {
354 var value = properties[property];
355 if (typeof value === 'undefined') {
356 expect(subject, 'not to have [own] property', property);
357 } else {
358 expect(subject, 'to have [own] property', property, value);
359 }
360 });
361 },
362 function (e) {
363 expect.fail({
364 diff: function diff(output, diff$1) {
365 output.inline = false;
366 var expected = extend({}, properties);
367 var actual = {};
368 var propertyNames = expect.findTypeOf(subject).getKeys(subject);
369 // Might put duplicates into propertyNames, but that does not matter:
370 for (var propertyName in subject) {
371 if (!subject.hasOwnProperty(propertyName)) {
372 propertyNames.push(propertyName);
373 }
374 }
375 propertyNames.forEach(function (propertyName) {
376 if (
377 (!expect.flags.own || subject.hasOwnProperty(propertyName)) &&
378 !(propertyName in properties)
379 ) {
380 expected[propertyName] = subject[propertyName];
381 }
382 if (
383 (!expect.flags.own || subject.hasOwnProperty(propertyName)) &&
384 !(propertyName in actual)
385 ) {
386 actual[propertyName] = subject[propertyName];
387 }
388 });
389 return utils.wrapConstructorNameAroundOutput(
390 diff$1(actual, expected),
391 subject
392 );
393 }
394 });
395 }
396 );
397 }
398 );
399
400 expect.addAssertion(
401 '<string|array-like> [not] to have length <number>',
402 function (expect, subject, length) {
403 if (!expect.flags.not) {
404 expect.errorMode = 'nested';
405 }
406 expect(subject.length, '[not] to be', length);
407 }
408 );
409
410 expect.addAssertion(
411 '<string|array-like> [not] to be empty',
412 function (expect, subject) {
413 expect(subject, '[not] to have length', 0);
414 }
415 );
416
417 expect.addAssertion(
418 '<string|array-like|object> to be non-empty',
419 function (expect, subject) {
420 expect(subject, 'not to be empty');
421 }
422 );
423
424 expect.addAssertion(
425 '<object> to [not] [only] have keys <array>',
426 function (expect, subject, keys) {
427 var keysInSubject = {};
428 var subjectType = expect.findTypeOf(subject);
429 var subjectKeys = subjectType.getKeys(subject);
430 subjectKeys.forEach(function (key) {
431 keysInSubject[key] = true;
432 });
433
434 if (expect.flags.not && keys.length === 0) {
435 return;
436 }
437
438 var hasKeys = keys.every(function (key) { return keysInSubject[key]; });
439
440 if (expect.flags.only) {
441 expect(hasKeys, 'to be truthy');
442 expect.withError(
443 function () {
444 expect(subjectKeys.length === keys.length, '[not] to be truthy');
445 },
446 function () {
447 expect.fail({
448 diff:
449 !expect.flags.not &&
450 (function (output, diff, inspect, equal) {
451 output.inline = true;
452 var keyInValue = {};
453 keys.forEach(function (key) {
454 keyInValue[key] = true;
455 });
456 var subjectIsArrayLike = subjectType.is('array-like');
457
458 subjectType.prefix(output, subject);
459 output.nl().indentLines();
460
461 subjectKeys.forEach(function (key, index) {
462 var propertyOutput = subjectType.property(
463 output.clone(),
464 key,
465 inspect(subjectType.valueForKey(subject, key)),
466 subjectIsArrayLike
467 );
468 var delimiterOutput = subjectType.delimiter(
469 output.clone(),
470 index,
471 subjectKeys.length
472 );
473
474 output
475 .i()
476 .block(function() {
477 this.append(propertyOutput).amend(delimiterOutput);
478 if (!keyInValue[key]) {
479 this.sp().annotationBlock(function() {
480 this.error('should be removed');
481 });
482 }
483 })
484 .nl();
485 });
486
487 output.outdentLines();
488 subjectType.suffix(output, subject);
489
490 return output;
491 })
492 });
493 }
494 );
495 } else {
496 expect(hasKeys, '[not] to be truthy');
497 }
498 }
499 );
500
501 expect.addAssertion('<object> [not] to be empty', function (expect, subject) {
502 if (
503 expect.flags.not &&
504 !expect.findTypeOf(subject).getKeys(subject).length
505 ) {
506 return expect.fail();
507 }
508 expect(subject, 'to [not] only have keys', []);
509 });
510
511 expect.addAssertion(
512 '<object> not to have keys <array>',
513 function (expect, subject, keys) {
514 expect(subject, 'to not have keys', keys);
515 }
516 );
517
518 expect.addAssertion(
519 '<object> not to have key <string>',
520 function (expect, subject, value) {
521 expect(subject, 'to not have keys', [value]);
522 }
523 );
524
525 expect.addAssertion('<object> not to have keys <string+>', function(
526 expect,
527 subject,
528 value
529 ) {
530 expect(
531 subject,
532 'to not have keys',
533 Array.prototype.slice.call(arguments, 2)
534 );
535 });
536
537 expect.addAssertion(
538 '<object> to [not] [only] have key <string>',
539 function (expect, subject, value) {
540 expect(subject, 'to [not] [only] have keys', [value]);
541 }
542 );
543
544 expect.addAssertion('<object> to [not] [only] have keys <string+>', function(
545 expect,
546 subject
547 ) {
548 expect(
549 subject,
550 'to [not] [only] have keys',
551 Array.prototype.slice.call(arguments, 2)
552 );
553 });
554
555 expect.addAssertion('<string> [not] to contain <string+>', function(
556 expect,
557 subject
558 ) {
559 var args = Array.prototype.slice.call(arguments, 2);
560 args.forEach(function (arg) {
561 if (arg === '') {
562 throw new Error(
563 ("The '" + (expect.testDescription) + "' assertion does not support the empty string")
564 );
565 }
566 });
567 expect.withError(
568 function () {
569 args.forEach(function (arg) {
570 expect(subject.indexOf(arg) !== -1, '[not] to be truthy');
571 });
572 },
573 function (e) {
574 expect.fail({
575 diff: function diff(output) {
576 output.inline = false;
577 var lastIndex = 0;
578 function flushUntilIndex(i) {
579 if (i > lastIndex) {
580 output.text(subject.substring(lastIndex, i));
581 lastIndex = i;
582 }
583 }
584 if (expect.flags.not) {
585 subject.replace(
586 new RegExp(
587 args.map(function (arg) { return utils.escapeRegExpMetaChars(arg); }).join('|'),
588 'g'
589 ),
590 function ($0, index) {
591 flushUntilIndex(index);
592 lastIndex += $0.length;
593 output.removedHighlight($0);
594 }
595 );
596 flushUntilIndex(subject.length);
597 } else {
598 var ranges = [];
599 args.forEach(function (arg) {
600 var needle = arg;
601 var partial = false;
602 while (needle.length > 1) {
603 var found = false;
604 lastIndex = -1;
605 var index = (void 0);
606 do {
607 index = subject.indexOf(needle, lastIndex + 1);
608 if (index !== -1) {
609 found = true;
610 ranges.push({
611 startIndex: index,
612 endIndex: index + needle.length,
613 partial: partial
614 });
615 }
616 lastIndex = index;
617 } while (lastIndex !== -1);
618 if (found) {
619 break;
620 }
621 needle = arg.substr(0, needle.length - 1);
622 partial = true;
623 }
624 });
625 lastIndex = 0;
626 ranges
627 .sort(function (a, b) { return a.startIndex - b.startIndex; })
628 .forEach(function (ref) {
629 var startIndex = ref.startIndex;
630 var endIndex = ref.endIndex;
631 var partial = ref.partial;
632
633 flushUntilIndex(startIndex);
634 var firstUncoveredIndex = Math.max(startIndex, lastIndex);
635 if (endIndex > firstUncoveredIndex) {
636 if (partial) {
637 output.partialMatch(
638 subject.substring(firstUncoveredIndex, endIndex)
639 );
640 } else {
641 output.match(
642 subject.substring(firstUncoveredIndex, endIndex)
643 );
644 }
645 lastIndex = endIndex;
646 }
647 });
648 flushUntilIndex(subject.length);
649 }
650 return output;
651 }
652 });
653 }
654 );
655 });
656
657 expect.addAssertion('<array-like> [not] to contain <any+>', function(
658 expect,
659 subject
660 ) {
661 var args = Array.prototype.slice.call(arguments, 2);
662 expect.withError(
663 function () {
664 args.forEach(function (arg) {
665 expect(
666 subject &&
667 Array.prototype.some.call(subject, function (item) { return expect.equal(item, arg); }
668 ),
669 '[not] to be truthy'
670 );
671 });
672 },
673 function (e) {
674 expect.fail({
675 diff:
676 expect.flags.not &&
677 (function (output, diff, inspect, equal) { return diff(
678 subject,
679 Array.prototype.filter.call(
680 subject,
681 function (item) { return !args.some(function (arg) { return equal(item, arg); }); }
682 )
683 ); })
684 });
685 }
686 );
687 });
688
689 expect.addAssertion(
690 [
691 '<string> [not] to begin with <string>',
692 '<string> [not] to start with <string>'
693 ],
694 function (expect, subject, value) {
695 if (value === '') {
696 throw new Error(
697 ("The '" + (expect.testDescription) + "' assertion does not support a prefix of the empty string")
698 );
699 }
700 var isTruncated = false;
701 var outputSubject = utils.truncateSubjectStringForBegin(subject, value);
702 if (outputSubject === null) {
703 outputSubject = subject;
704 } else {
705 isTruncated = true;
706 }
707 expect.subjectOutput = function (output) {
708 output = output.jsString(
709 "'" + outputSubject.replace(/\n/g, '\\n') + "'"
710 );
711 if (isTruncated) {
712 output.jsComment('...');
713 }
714 };
715 expect.withError(
716 function () {
717 expect(subject.substr(0, value.length), '[not] to equal', value);
718 },
719 function () {
720 expect.fail({
721 diff: function diff(output) {
722 output.inline = false;
723 if (expect.flags.not) {
724 output
725 .removedHighlight(value)
726 .text(subject.substr(value.length));
727 } else {
728 var i = 0;
729 while (subject[i] === value[i]) {
730 i += 1;
731 }
732 if (i === 0) {
733 // No common prefix, omit diff
734 return null;
735 } else {
736 output
737 .partialMatch(subject.substr(0, i))
738 .text(outputSubject.substr(i))
739 .jsComment(isTruncated ? '...' : '');
740 }
741 }
742 return output;
743 }
744 });
745 }
746 );
747 }
748 );
749
750 expect.addAssertion(
751 '<string> [not] to end with <string>',
752 function (expect, subject, value) {
753 if (value === '') {
754 throw new Error(
755 ("The '" + (expect.testDescription) + "' assertion does not support a suffix of the empty string")
756 );
757 }
758 var isTruncated = false;
759 var outputSubject = utils.truncateSubjectStringForEnd(subject, value);
760 if (outputSubject === null) {
761 outputSubject = subject;
762 } else {
763 isTruncated = true;
764 }
765 expect.subjectOutput = function (output) {
766 if (isTruncated) {
767 output = output.jsComment('...');
768 }
769 output.jsString("'" + outputSubject.replace(/\n/g, '\\n') + "'");
770 };
771 expect.withError(
772 function () {
773 expect(subject.substr(-value.length), '[not] to equal', value);
774 },
775 function () {
776 expect.fail({
777 diff: function diff(output) {
778 output.inline = false;
779 if (expect.flags.not) {
780 output
781 .text(subject.substr(0, subject.length - value.length))
782 .removedHighlight(value);
783 } else {
784 var i = 0;
785 while (
786 outputSubject[outputSubject.length - 1 - i] ===
787 value[value.length - 1 - i]
788 ) {
789 i += 1;
790 }
791 if (i === 0) {
792 // No common suffix, omit diff
793 return null;
794 }
795 output
796 .jsComment(isTruncated ? '...' : '')
797 .text(outputSubject.substr(0, outputSubject.length - i))
798 .partialMatch(
799 outputSubject.substr(
800 outputSubject.length - i,
801 outputSubject.length
802 )
803 );
804 }
805 return output;
806 }
807 });
808 }
809 );
810 }
811 );
812
813 expect.addAssertion('<number> [not] to be finite', function (expect, subject) {
814 expect(isFinite(subject), '[not] to be truthy');
815 });
816
817 expect.addAssertion('<number> [not] to be infinite', function (expect, subject) {
818 expect(!isNaN(subject) && !isFinite(subject), '[not] to be truthy');
819 });
820
821 expect.addAssertion(
822 '<number> [not] to be within <number> <number>',
823 function (expect, subject, start, finish) {
824 expect.argsOutput = function (output) {
825 output
826 .appendInspected(start)
827 .text('..')
828 .appendInspected(finish);
829 };
830 expect(subject >= start && subject <= finish, '[not] to be truthy');
831 }
832 );
833
834 expect.addAssertion(
835 '<string> [not] to be within <string> <string>',
836 function (expect, subject, start, finish) {
837 expect.argsOutput = function (output) {
838 output
839 .appendInspected(start)
840 .text('..')
841 .appendInspected(finish);
842 };
843 expect(subject >= start && subject <= finish, '[not] to be truthy');
844 }
845 );
846
847 expect.addAssertion(
848 '<number> [not] to be (less than|below) <number>',
849 function (expect, subject, value) {
850 expect(subject < value, '[not] to be truthy');
851 }
852 );
853
854 expect.addAssertion(
855 '<string> [not] to be (less than|below) <string>',
856 function (expect, subject, value) {
857 expect(subject < value, '[not] to be truthy');
858 }
859 );
860
861 expect.addAssertion(
862 '<number> [not] to be less than or equal to <number>',
863 function (expect, subject, value) {
864 expect(subject <= value, '[not] to be truthy');
865 }
866 );
867
868 expect.addAssertion(
869 '<string> [not] to be less than or equal to <string>',
870 function (expect, subject, value) {
871 expect(subject <= value, '[not] to be truthy');
872 }
873 );
874
875 expect.addAssertion(
876 '<number> [not] to be (greater than|above) <number>',
877 function (expect, subject, value) {
878 expect(subject > value, '[not] to be truthy');
879 }
880 );
881
882 expect.addAssertion(
883 '<string> [not] to be (greater than|above) <string>',
884 function (expect, subject, value) {
885 expect(subject > value, '[not] to be truthy');
886 }
887 );
888
889 expect.addAssertion(
890 '<number> [not] to be greater than or equal to <number>',
891 function (expect, subject, value) {
892 expect(subject >= value, '[not] to be truthy');
893 }
894 );
895
896 expect.addAssertion(
897 '<string> [not] to be greater than or equal to <string>',
898 function (expect, subject, value) {
899 expect(subject >= value, '[not] to be truthy');
900 }
901 );
902
903 expect.addAssertion('<number> [not] to be positive', function (expect, subject) {
904 expect(subject, '[not] to be greater than', 0);
905 });
906
907 expect.addAssertion('<number> [not] to be negative', function (expect, subject) {
908 expect(subject, '[not] to be less than', 0);
909 });
910
911 expect.addAssertion('<any> to equal <any>', function (expect, subject, value) {
912 expect.withError(
913 function () {
914 expect(expect.equal(value, subject), 'to be truthy');
915 },
916 function (e) {
917 expect.fail({
918 label: 'should equal',
919 diff: function diff(output, diff$1) {
920 return diff$1(subject, value);
921 }
922 });
923 }
924 );
925 });
926
927 expect.addAssertion('<any> not to equal <any>', function (expect, subject, value) {
928 expect(expect.equal(value, subject), 'to be falsy');
929 });
930
931 expect.addAssertion('<function> to error', function (expect, subject) { return expect
932 .promise(function () { return subject(); })
933 .then(
934 function () {
935 expect.fail();
936 },
937 function (error) { return error; }
938 ); }
939 );
940
941 expect.addAssertion(
942 '<function> to error [with] <any>',
943 function (expect, subject, arg) { return expect(subject, 'to error').then(function (error) {
944 expect.errorMode = 'nested';
945 return expect.withError(
946 function () {
947 return expect(error, 'to satisfy', arg);
948 },
949 function (e) {
950 e.originalError = error;
951 throw e;
952 }
953 );
954 }); }
955 );
956
957 expect.addAssertion('<function> not to error', function (expect, subject) {
958 var threw = false;
959 return expect
960 .promise(function () {
961 try {
962 return subject();
963 } catch (e) {
964 threw = true;
965 throw e;
966 }
967 })
968 .caught(function (error) {
969 expect.errorMode = 'nested';
970 expect.fail({
971 output: function output(output$1) {
972 output$1
973 .error(threw ? 'threw' : 'returned promise rejected with')
974 .error(': ')
975 .appendErrorMessage(error);
976 },
977 originalError: error
978 });
979 });
980 });
981
982 expect.addAssertion('<function> not to throw', function (expect, subject) {
983 var threw = false;
984 var error;
985
986 try {
987 subject();
988 } catch (e) {
989 error = e;
990 threw = true;
991 }
992
993 if (threw) {
994 expect.errorMode = 'nested';
995 expect.fail({
996 output: function output(output$1) {
997 output$1.error('threw: ').appendErrorMessage(error);
998 },
999 originalError: error
1000 });
1001 }
1002 });
1003
1004 expect.addAssertion(
1005 '<function> to (throw|throw error|throw exception)',
1006 function (expect, subject) {
1007 try {
1008 subject();
1009 } catch (e) {
1010 return e;
1011 }
1012 expect.errorMode = 'nested';
1013 expect.fail('did not throw');
1014 }
1015 );
1016
1017 expect.addAssertion('<object> to satisfy <function>', function (expect) { return expect.fail(); }
1018 );
1019
1020 expect.addAssertion(
1021 '<function> to throw (a|an) <function>',
1022 function (expect, subject, value) {
1023 var constructorName = utils.getFunctionName(value);
1024 if (constructorName) {
1025 expect.argsOutput[0] = function (output) {
1026 output.jsFunctionName(constructorName);
1027 };
1028 }
1029 expect.errorMode = 'nested';
1030 return expect(subject, 'to throw').tap(function (error) {
1031 expect(error, 'to be a', value);
1032 });
1033 }
1034 );
1035
1036 expect.addAssertion(
1037 '<function> to (throw|throw error|throw exception) <any>',
1038 function (expect, subject, arg) {
1039 expect.errorMode = 'nested';
1040 return expect(subject, 'to throw').then(function (error) {
1041 // in the presence of a matcher an error must have been thrown.
1042
1043 expect.errorMode = 'nested';
1044 return expect.withError(
1045 function () {
1046 return expect(error, 'to satisfy', arg);
1047 },
1048 function (err) {
1049 err.originalError = error;
1050 throw err;
1051 }
1052 );
1053 });
1054 }
1055 );
1056
1057 expect.addAssertion(
1058 '<function> to have arity <number>',
1059 function (expect, ref, value) {
1060 var length = ref.length;
1061
1062 expect(length, 'to equal', value);
1063 }
1064 );
1065
1066 expect.addAssertion(
1067 [
1068 '<object> to have values [exhaustively] satisfying <any>',
1069 '<object> to have values [exhaustively] satisfying <assertion>',
1070 '<object> to be (a map|a hash|an object) whose values [exhaustively] satisfy <any>',
1071 '<object> to be (a map|a hash|an object) whose values [exhaustively] satisfy <assertion>'
1072 ],
1073 function (expect, subject, nextArg) {
1074 expect.errorMode = 'nested';
1075 expect(subject, 'not to be empty');
1076 expect.errorMode = 'bubble';
1077
1078 var keys = expect.subjectType.getKeys(subject);
1079 var expected = {};
1080 keys.forEach(function (key) {
1081 if (typeof nextArg === 'string') {
1082 expected[key] = expect.it(function (s) { return expect.shift(s); });
1083 } else {
1084 expected[key] = nextArg;
1085 }
1086 });
1087 return expect.withError(
1088 function () { return expect(subject, 'to [exhaustively] satisfy', expected); },
1089 function (err) {
1090 expect.fail({
1091 message: function message(output) {
1092 output.append(
1093 expect.standardErrorMessage(output.clone(), {
1094 compact: err && err._isUnexpected && err.hasDiff()
1095 })
1096 );
1097 },
1098 diff: function diff(output) {
1099 var diff = err.getDiff({ output: output });
1100 diff.inline = true;
1101 return diff;
1102 }
1103 });
1104 }
1105 );
1106 }
1107 );
1108
1109 expect.addAssertion(
1110 [
1111 '<array-like> to have items [exhaustively] satisfying <any>',
1112 '<array-like> to have items [exhaustively] satisfying <assertion>',
1113 '<array-like> to be an array whose items [exhaustively] satisfy <any>',
1114 '<array-like> to be an array whose items [exhaustively] satisfy <assertion>'
1115 ],
1116 function (expect, subject) {
1117 var rest = [], len = arguments.length - 2;
1118 while ( len-- > 0 ) rest[ len ] = arguments[ len + 2 ];
1119
1120 // ...
1121 expect.errorMode = 'nested';
1122 expect(subject, 'not to be empty');
1123 expect.errorMode = 'bubble';
1124
1125 return expect.withError(
1126 function () { return expect.apply(void 0, [ subject, 'to have values [exhaustively] satisfying' ].concat( rest )); },
1127 function (err) {
1128 expect.fail({
1129 message: function message(output) {
1130 output.append(
1131 expect.standardErrorMessage(output.clone(), {
1132 compact: err && err._isUnexpected && err.hasDiff()
1133 })
1134 );
1135 },
1136 diff: function diff(output) {
1137 var diff = err.getDiff({ output: output });
1138 diff.inline = true;
1139 return diff;
1140 }
1141 });
1142 }
1143 );
1144 }
1145 );
1146
1147 expect.addAssertion(
1148 [
1149 '<object> to have keys satisfying <any>',
1150 '<object> to have keys satisfying <assertion>',
1151 '<object> to be (a map|a hash|an object) whose (keys|properties) satisfy <any>',
1152 '<object> to be (a map|a hash|an object) whose (keys|properties) satisfy <assertion>'
1153 ],
1154 function (expect, subject) {
1155 var rest = [], len = arguments.length - 2;
1156 while ( len-- > 0 ) rest[ len ] = arguments[ len + 2 ];
1157
1158 expect.errorMode = 'nested';
1159 expect(subject, 'not to be empty');
1160 expect.errorMode = 'default';
1161
1162 var keys = expect.subjectType.getKeys(subject);
1163 return expect.apply(void 0, [ keys, 'to have items satisfying' ].concat( rest ));
1164 }
1165 );
1166
1167 expect.addAssertion(
1168 [
1169 '<object> [not] to have a value [exhaustively] satisfying <any>',
1170 '<object> [not] to have a value [exhaustively] satisfying <assertion>'
1171 ],
1172 function (expect, subject, nextArg) {
1173 expect.errorMode = 'nested';
1174 expect(subject, 'not to be empty');
1175 expect.errorMode = 'bubble';
1176
1177 var subjectType = expect.findTypeOf(subject);
1178 var keys = subjectType.getKeys(subject);
1179 var not = !!expect.flags.not;
1180
1181 var keyResults = new Array(keys.length);
1182
1183 expect.withError(
1184 function () { return expect.promise[not ? 'all' : 'any'](
1185 keys.map(function (key) {
1186 var expected;
1187 if (typeof nextArg === 'string') {
1188 expected = expect.it(function (s) { return expect.shift(s); });
1189 } else {
1190 expected = nextArg;
1191 }
1192
1193 keyResults[key] = expect.promise(function () { return expect(
1194 subjectType.valueForKey(subject, key),
1195 '[not] to [exhaustively] satisfy',
1196 expected
1197 ); }
1198 );
1199 return keyResults[key];
1200 })
1201 ); },
1202 function (err) {
1203 expect.fail({
1204 message: function message(output) {
1205 output.append(
1206 expect.standardErrorMessage(output.clone(), {
1207 compact: err && err._isUnexpected && err.hasDiff()
1208 })
1209 );
1210 },
1211 diff:
1212 expect.flags.not &&
1213 (function (output, diff, inspect, equal) {
1214 var expectedObject = subjectType.is('array-like') ? [] : {};
1215 keys.forEach(function (key) {
1216 if (keyResults[key].isFulfilled()) {
1217 expectedObject[key] = subjectType.valueForKey(subject, key);
1218 }
1219 });
1220
1221 return diff(subject, expectedObject);
1222 })
1223 });
1224 }
1225 );
1226 }
1227 );
1228
1229 expect.addAssertion(
1230 [
1231 '<array-like> [not] to have an item [exhaustively] satisfying <any>',
1232 '<array-like> [not] to have an item [exhaustively] satisfying <assertion>'
1233 ],
1234 function (expect, subject) {
1235 var rest = [], len = arguments.length - 2;
1236 while ( len-- > 0 ) rest[ len ] = arguments[ len + 2 ];
1237
1238 expect.errorMode = 'nested';
1239 expect(subject, 'not to be empty');
1240 expect.errorMode = 'default';
1241
1242 return expect.apply(
1243 void 0, [ subject,
1244 '[not] to have a value [exhaustively] satisfying' ].concat( rest )
1245 );
1246 }
1247 );
1248
1249 expect.addAssertion('<object> to be canonical', function (expect, subject) {
1250 var stack = [];
1251
1252 (function traverse(obj) {
1253 var i;
1254 for (i = 0; i < stack.length; i += 1) {
1255 if (stack[i] === obj) {
1256 return;
1257 }
1258 }
1259 if (obj && typeof obj === 'object') {
1260 var keys = Object.keys(obj);
1261 for (i = 0; i < keys.length - 1; i += 1) {
1262 expect(keys[i], 'to be less than', keys[i + 1]);
1263 }
1264 stack.push(obj);
1265 keys.forEach(function (key) {
1266 traverse(obj[key]);
1267 });
1268 stack.pop();
1269 }
1270 })(subject);
1271 });
1272
1273 expect.addAssertion(
1274 '<Error> to have message <any>',
1275 function (expect, subject, value) {
1276 expect.errorMode = 'nested';
1277 return expect(
1278 subject.isUnexpected
1279 ? subject.getErrorMessage('text').toString()
1280 : subject.message,
1281 'to satisfy',
1282 value
1283 );
1284 }
1285 );
1286
1287 expect.addAssertion(
1288 '<Error> to [exhaustively] satisfy <Error>',
1289 function (expect, subject, value) {
1290 expect(subject.constructor, 'to be', value.constructor);
1291
1292 var unwrappedValue = expect.argTypes[0].unwrap(value);
1293 return expect.withError(
1294 function () { return expect(subject, 'to [exhaustively] satisfy', unwrappedValue); },
1295 function (e) {
1296 expect.fail({
1297 diff: function diff(output, diff$1) {
1298 output.inline = false;
1299 var unwrappedSubject = expect.subjectType.unwrap(subject);
1300 return utils.wrapConstructorNameAroundOutput(
1301 diff$1(unwrappedSubject, unwrappedValue),
1302 subject
1303 );
1304 }
1305 });
1306 }
1307 );
1308 }
1309 );
1310
1311 expect.addAssertion(
1312 '<Error> to [exhaustively] satisfy <object>',
1313 function (expect, subject, value) {
1314 var valueType = expect.argTypes[0];
1315 var subjectKeys = expect.subjectType.getKeys(subject);
1316 var valueKeys = valueType.getKeys(value);
1317 var convertedSubject = {};
1318 subjectKeys.concat(valueKeys).forEach(function (key) {
1319 convertedSubject[key] = subject[key];
1320 });
1321 return expect(convertedSubject, 'to [exhaustively] satisfy', value);
1322 }
1323 );
1324
1325 expect.addAssertion(
1326 '<Error> to [exhaustively] satisfy <regexp|string|any>',
1327 function (expect, ref, value) {
1328 var message = ref.message;
1329
1330 return expect(message, 'to [exhaustively] satisfy', value);
1331 }
1332 );
1333
1334 expect.addAssertion(
1335 '<UnexpectedError> to [exhaustively] satisfy <regexp|string>',
1336 function (expect, error, value) {
1337 expect.errorMode = 'bubble';
1338 return expect(error, 'to have message', value);
1339 }
1340 );
1341
1342 expect.addAssertion(
1343 '<binaryArray> to [exhaustively] satisfy <expect.it>',
1344 function (expect, subject, value) { return expect.withError(
1345 function () { return value(subject, expect.context); },
1346 function (e) {
1347 expect.fail({
1348 diff: function diff(output, diff$1, inspect, equal) {
1349 output.inline = false;
1350 return output.appendErrorMessage(e);
1351 }
1352 });
1353 }
1354 ); }
1355 );
1356
1357 expect.addAssertion(
1358 '<any|Error> to [exhaustively] satisfy <expect.it>',
1359 function (expect, subject, value) { return expect.promise(function () { return value(subject); }); }
1360 );
1361
1362 if (typeof Buffer !== 'undefined') {
1363 expect.addAssertion(
1364 '<Buffer> [when] decoded as <string> <assertion?>',
1365 function (expect, subject, value) { return expect.shift(subject.toString(value)); }
1366 );
1367 }
1368
1369 expect.addAssertion(
1370 '<any> not to [exhaustively] satisfy [assertion] <any>',
1371 function (expect, subject, value) { return expect.promise(function (resolve, reject) { return expect
1372 .promise(function () { return expect(subject, 'to [exhaustively] satisfy [assertion]', value); }
1373 )
1374 .then(function () {
1375 try {
1376 expect.fail();
1377 } catch (e) {
1378 reject(e);
1379 }
1380 })
1381 .caught(function (e) {
1382 if (!e || !e._isUnexpected) {
1383 reject(e);
1384 } else {
1385 resolve();
1386 }
1387 }); }
1388 ); }
1389 );
1390
1391 expect.addAssertion(
1392 '<any> to [exhaustively] satisfy assertion <any>',
1393 function (expect, subject, value) {
1394 expect.errorMode = 'bubble'; // to satisfy assertion 'to be a number' => to be a number
1395 return expect(subject, 'to [exhaustively] satisfy', value);
1396 }
1397 );
1398
1399 expect.addAssertion(
1400 '<any> to [exhaustively] satisfy assertion <assertion>',
1401 function (expect, subject) {
1402 expect.errorMode = 'bubble'; // to satisfy assertion 'to be a number' => to be a number
1403 return expect.shift();
1404 }
1405 );
1406
1407 expect.addAssertion(
1408 '<any|object> to [exhaustively] satisfy [assertion] <expect.it>',
1409 function (expect, subject, value) { return expect.withError(
1410 function () { return value(subject, expect.context); },
1411 function (e) {
1412 expect.fail({
1413 diff: function diff(output) {
1414 output.inline = false;
1415 return output.appendErrorMessage(e);
1416 }
1417 });
1418 }
1419 ); }
1420 );
1421
1422 expect.addAssertion(
1423 '<regexp> to [exhaustively] satisfy <regexp>',
1424 function (expect, subject, value) {
1425 expect(subject, 'to equal', value);
1426 }
1427 );
1428
1429 expect.addAssertion(
1430 '<string> to [exhaustively] satisfy <regexp>',
1431 function (expect, subject, value) {
1432 expect.errorMode = 'bubble';
1433 return expect(subject, 'to match', value);
1434 }
1435 );
1436
1437 expect.addAssertion(
1438 '<function> to [exhaustively] satisfy <function>',
1439 function (expect, subject, value) {
1440 expect.errorMode = 'bubble';
1441 expect(subject, 'to be', value);
1442 }
1443 );
1444
1445 expect.addAssertion(
1446 '<binaryArray> to [exhaustively] satisfy <binaryArray>',
1447 function (expect, subject, value) {
1448 expect.errorMode = 'bubble';
1449 expect(subject, 'to equal', value);
1450 }
1451 );
1452
1453 expect.addAssertion(
1454 '<any> to [exhaustively] satisfy <any>',
1455 function (expect, subject, value) {
1456 expect.errorMode = 'bubble';
1457 expect(subject, 'to equal', value);
1458 }
1459 );
1460
1461 expect.addAssertion(
1462 '<array-like> to [exhaustively] satisfy <array-like>',
1463 function (expect, subject, value) {
1464 expect.errorMode = 'bubble';
1465 var subjectType = expect.subjectType;
1466 var subjectKeys = subjectType.getKeys(subject);
1467 var valueType = expect.argTypes[0];
1468 var valueKeys = valueType.getKeys(value).filter(
1469 function (key) { return utils.numericalRegExp.test(key) ||
1470 typeof key === 'symbol' ||
1471 // include keys whose value is not undefined on either LHS or RHS
1472 typeof valueType.valueForKey(value, key) !== 'undefined' ||
1473 typeof subjectType.valueForKey(subject, key) !== 'undefined'; }
1474 );
1475 var keyPromises = {};
1476 valueKeys.forEach(function(keyInValue) {
1477 keyPromises[keyInValue] = expect.promise(function() {
1478 var subjectKey = subjectType.valueForKey(subject, keyInValue);
1479 var valueKey = valueType.valueForKey(value, keyInValue);
1480 var valueKeyType = expect.findTypeOf(valueKey);
1481
1482 if (valueKeyType.is('expect.it')) {
1483 expect.context.thisObject = subject;
1484 return valueKey(subjectKey, expect.context);
1485 } else {
1486 return expect(subjectKey, 'to [exhaustively] satisfy', valueKey);
1487 }
1488 });
1489 });
1490 return expect.promise
1491 .all([
1492 expect.promise(function () {
1493 // create subject key presence object
1494 var remainingKeysInSubject = {};
1495 subjectKeys.forEach(function (key) {
1496 remainingKeysInSubject[key] = 1; // present in subject
1497 });
1498 // discard or mark missing each previously seen value key
1499 valueKeys.forEach(function (key) {
1500 if (
1501 !remainingKeysInSubject[key] &&
1502 (utils.numericalRegExp.test(key) || expect.flags.exhaustively)
1503 ) {
1504 remainingKeysInSubject[key] = 2; // present in value
1505 } else {
1506 delete remainingKeysInSubject[key];
1507 }
1508 });
1509 // check whether there are any outstanding keys we cannot account for
1510 var outstandingKeys = Object.keys(remainingKeysInSubject).filter(
1511 function (key) { return utils.numericalRegExp.test(key) ||
1512 typeof key === 'symbol' ||
1513 (typeof subjectType.valueForKey(subject, key) !== 'undefined' &&
1514 // key was only in the value
1515 remainingKeysInSubject[key] === 2); }
1516 );
1517 // key checking succeeds with no outstanding keys
1518 expect(outstandingKeys.length === 0, 'to be truthy');
1519 }),
1520 expect.promise.all(keyPromises)
1521 ])
1522 .caught(function () {
1523 var i = 0;
1524 return expect.promise.settle(keyPromises).then(function () {
1525 var toSatisfyMatrix = new Array(subject.length);
1526 for (i = 0; i < subject.length; i += 1) {
1527 toSatisfyMatrix[i] = new Array(value.length);
1528 if (i < value.length) {
1529 toSatisfyMatrix[i][i] =
1530 keyPromises[i].isFulfilled() || keyPromises[i].reason();
1531 }
1532 }
1533 if (subject.length > 10 || value.length > 10) {
1534 var indexByIndexChanges = [];
1535 for (i = 0; i < subject.length; i += 1) {
1536 var promise = keyPromises[i];
1537 if (i < value.length) {
1538 indexByIndexChanges.push({
1539 type: promise.isFulfilled() ? 'equal' : 'similar',
1540 value: subject[i],
1541 expected: value[i],
1542 actualIndex: i,
1543 expectedIndex: i,
1544 last: i === Math.max(subject.length, value.length) - 1
1545 });
1546 } else {
1547 indexByIndexChanges.push({
1548 type: 'remove',
1549 value: subject[i],
1550 actualIndex: i,
1551 last: i === subject.length - 1
1552 });
1553 }
1554 }
1555 for (i = subject.length; i < value.length; i += 1) {
1556 indexByIndexChanges.push({
1557 type: 'insert',
1558 value: value[i],
1559 expectedIndex: i
1560 });
1561 }
1562 return failWithChanges(indexByIndexChanges);
1563 }
1564
1565 var isAsync = false;
1566 var subjectElements = utils.duplicateArrayLikeUsingType(
1567 subject,
1568 subjectType
1569 );
1570 var valueElements = utils.duplicateArrayLikeUsingType(
1571 value,
1572 valueType
1573 );
1574 var nonNumericalKeysAndSymbols =
1575 !subjectType.numericalPropertiesOnly &&
1576 utils.uniqueNonNumericalStringsAndSymbols(subjectKeys, valueKeys);
1577
1578 var changes = arrayChanges(
1579 subjectElements,
1580 valueElements,
1581 function equal(a, b, aIndex, bIndex) {
1582 toSatisfyMatrix[aIndex] = toSatisfyMatrix[aIndex] || [];
1583 var existingResult = toSatisfyMatrix[aIndex][bIndex];
1584 if (typeof existingResult !== 'undefined') {
1585 return existingResult === true;
1586 }
1587 var result;
1588 try {
1589 result = expect(a, 'to [exhaustively] satisfy', b);
1590 } catch (err) {
1591 throwIfNonUnexpectedError(err);
1592 toSatisfyMatrix[aIndex][bIndex] = err;
1593 return false;
1594 }
1595 result.then(function () {}, function () {});
1596 if (result.isPending()) {
1597 isAsync = true;
1598 return false;
1599 }
1600 toSatisfyMatrix[aIndex][bIndex] = true;
1601 return true;
1602 },
1603 function (a, b) { return subjectType.similar(a, b); },
1604 {
1605 includeNonNumericalProperties: nonNumericalKeysAndSymbols
1606 }
1607 );
1608 if (isAsync) {
1609 return expect
1610 .promise(function (resolve, reject) {
1611 arrayChangesAsync(
1612 subject,
1613 value,
1614 function equal(a, b, aIndex, bIndex, fn) {
1615 toSatisfyMatrix[aIndex] = toSatisfyMatrix[aIndex] || [];
1616 var existingResult = toSatisfyMatrix[aIndex][bIndex];
1617 if (typeof existingResult !== 'undefined') {
1618 return fn(existingResult === true);
1619 }
1620 expect
1621 .promise(function () { return expect(a, 'to [exhaustively] satisfy', b); }
1622 )
1623 .then(
1624 function () {
1625 toSatisfyMatrix[aIndex][bIndex] = true;
1626 fn(true);
1627 },
1628 function (err) {
1629 toSatisfyMatrix[aIndex][bIndex] = err;
1630 fn(false);
1631 }
1632 );
1633 },
1634 function (a, b, aIndex, bIndex, fn) {
1635 fn(subjectType.similar(a, b));
1636 },
1637 nonNumericalKeysAndSymbols,
1638 resolve
1639 );
1640 })
1641 .then(failWithChanges);
1642 } else {
1643 return failWithChanges(changes);
1644 }
1645
1646 function failWithChanges(changes) {
1647 expect.errorMode = 'default';
1648 expect.fail({
1649 diff: function diff(output, diff$1, inspect, equal) {
1650 output.inline = true;
1651 var indexOfLastNonInsert = changes.reduce(
1652 function (previousValue, ref, index) {
1653 var type = ref.type;
1654
1655 return type === 'insert' ? previousValue : index;
1656 },
1657 -1
1658 );
1659 var prefixOutput = subjectType.prefix(
1660 output.clone(),
1661 subject
1662 );
1663 output
1664 .append(prefixOutput)
1665 .nl(prefixOutput.isEmpty() ? 0 : 1);
1666
1667 if (subjectType.indent) {
1668 output.indentLines();
1669 }
1670 var packing = utils.packArrows(changes); // NOTE: Will have side effects in changes if the packing results in too many arrow lanes
1671 output.arrowsAlongsideChangeOutputs(
1672 packing,
1673 changes.map(function (diffItem, index) {
1674 var delimiterOutput = subjectType.delimiter(
1675 output.clone(),
1676 index,
1677 indexOfLastNonInsert + 1
1678 );
1679 var type = diffItem.type;
1680 if (type === 'moveTarget') {
1681 return output.clone();
1682 } else {
1683 return output.clone().block(function() {
1684 if (type === 'moveSource') {
1685 var propertyOutput = subjectType.property(
1686 output.clone(),
1687 diffItem.actualIndex,
1688 inspect(diffItem.value),
1689 true
1690 );
1691
1692 this.append(propertyOutput)
1693 .amend(delimiterOutput)
1694 .sp()
1695 .error('// should be moved');
1696 } else if (type === 'insert') {
1697 this.annotationBlock(function() {
1698 if (
1699 expect
1700 .findTypeOf(diffItem.value)
1701 .is('expect.it')
1702 ) {
1703 this.error('missing: ').block(function() {
1704 this.omitSubject = undefined;
1705 var promise =
1706 keyPromises[diffItem.expectedIndex];
1707 if (promise.isRejected()) {
1708 this.appendErrorMessage(promise.reason());
1709 } else {
1710 this.appendInspected(diffItem.value);
1711 }
1712 });
1713 } else {
1714 var index =
1715 typeof diffItem.actualIndex !== 'undefined'
1716 ? diffItem.actualIndex
1717 : diffItem.expectedIndex;
1718 var propertyOutput = subjectType.property(
1719 output.clone(),
1720 index,
1721 inspect(diffItem.value),
1722 true
1723 );
1724 this.error('missing ').append(propertyOutput);
1725 }
1726 });
1727 } else {
1728 var propertyOutput$1 = subjectType.property(
1729 output.clone(),
1730 diffItem.actualIndex,
1731 inspect(diffItem.value),
1732 true
1733 );
1734
1735 this.block(function() {
1736 if (type === 'remove') {
1737 this.append(propertyOutput$1)
1738 .amend(delimiterOutput)
1739 .sp()
1740 .error('// should be removed');
1741 } else if (type === 'equal') {
1742 this.append(propertyOutput$1).amend(
1743 delimiterOutput
1744 );
1745 } else {
1746 var toSatisfyResult =
1747 toSatisfyMatrix[diffItem.actualIndex][
1748 diffItem.expectedIndex
1749 ];
1750 var valueDiff =
1751 toSatisfyResult &&
1752 toSatisfyResult !== true &&
1753 toSatisfyResult.getDiff({
1754 output: output.clone()
1755 });
1756 if (valueDiff && valueDiff.inline) {
1757 this.append(valueDiff).amend(delimiterOutput);
1758 } else {
1759 this.append(propertyOutput$1)
1760 .amend(delimiterOutput)
1761 .sp()
1762 .annotationBlock(function() {
1763 this.omitSubject = diffItem.value;
1764 var label = toSatisfyResult.getLabel();
1765 if (label) {
1766 this.error(label)
1767 .sp()
1768 .block(inspect(diffItem.expected));
1769 if (valueDiff) {
1770 this.nl(2).append(valueDiff);
1771 }
1772 } else {
1773 this.appendErrorMessage(
1774 toSatisfyResult
1775 );
1776 }
1777 });
1778 }
1779 }
1780 });
1781 }
1782 });
1783 }
1784 })
1785 );
1786
1787 if (subjectType.indent) {
1788 output.outdentLines();
1789 }
1790 var suffixOutput = subjectType.suffix(
1791 output.clone(),
1792 subject
1793 );
1794 output
1795 .nl(suffixOutput.isEmpty() ? 0 : 1)
1796 .append(suffixOutput);
1797
1798 return output;
1799 }
1800 });
1801 }
1802 });
1803 });
1804 }
1805 );
1806
1807 expect.addAssertion(
1808 '<object> to [exhaustively] satisfy <object>',
1809 function (expect, subject, value) {
1810 var valueType = expect.argTypes[0];
1811 var subjectType = expect.subjectType;
1812 var subjectIsArrayLike = subjectType.is('array-like');
1813 if (subject === value) {
1814 return;
1815 }
1816 if (valueType.is('array-like') && !subjectIsArrayLike) {
1817 expect.fail();
1818 }
1819
1820 var subjectKeys = subjectType.getKeys(subject);
1821 var valueKeys = valueType.getKeys(value);
1822 // calculate the unique keys early given enumerability no
1823 // longer affects what is included in the list of keys
1824 var uniqueKeys = subjectType.uniqueKeys(subjectKeys, valueKeys);
1825
1826 var promiseByKey = {};
1827 var forceExhaustivelyComparison = false;
1828 uniqueKeys.forEach(function (key, index) {
1829 var subjectHasKey = subjectType.hasKey(subject, key);
1830 var valueKey = valueType.hasKey(value, key, true)
1831 ? valueType.valueForKey(value, key)
1832 : undefined;
1833 var valueKeyType = expect.findTypeOf(valueKey);
1834 if (expect.flags.exhaustively) {
1835 if (valueKeyType.is('expect.it') && !subjectHasKey) {
1836 // ensure value only expect.it key is marked missing
1837 forceExhaustivelyComparison = true;
1838 }
1839 } else if (subjectHasKey && typeof valueKey === 'undefined') {
1840 // ignore subject only keys unless we are being exhaustive
1841 return;
1842 }
1843 var subjectKey = subjectHasKey
1844 ? subjectType.valueForKey(subject, key)
1845 : undefined;
1846
1847 promiseByKey[key] = expect.promise(function () {
1848 if (valueKeyType.is('expect.it')) {
1849 expect.context.thisObject = subject;
1850 return valueKey(subjectKey, expect.context);
1851 } else {
1852 return expect(subjectKey, 'to [exhaustively] satisfy', valueKey);
1853 }
1854 });
1855 });
1856
1857 return expect.promise
1858 .all([
1859 expect.promise(function () {
1860 if (forceExhaustivelyComparison) {
1861 throw new Error('exhaustive comparison failure');
1862 }
1863 }),
1864 expect.promise.all(promiseByKey)
1865 ])
1866 .caught(function () { return expect.promise.settle(promiseByKey).then(function () {
1867 expect.fail({
1868 diff: function diff(output, diff$1, inspect, equal) {
1869 output.inline = true;
1870 var subjectIsArrayLike = subjectType.is('array-like');
1871 // Skip missing keys expected to be missing so they don't get rendered in the diff
1872 var keys = uniqueKeys.filter(function (key) {
1873 return (
1874 subjectType.hasKey(subject, key) ||
1875 typeof valueType.valueForKey(value, key) !== 'undefined'
1876 );
1877 });
1878 var prefixOutput = subjectType.prefix(
1879 output.clone(),
1880 subject
1881 );
1882 output.append(prefixOutput).nl(prefixOutput.isEmpty() ? 0 : 1);
1883
1884 if (subjectType.indent) {
1885 output.indentLines();
1886 }
1887 keys.forEach(function (key, index) {
1888 var subjectKey = subjectType.valueForKey(subject, key);
1889 var valueKey = valueType.valueForKey(value, key);
1890 output
1891 .nl(index > 0 ? 1 : 0)
1892 .i()
1893 .block(function() {
1894 var valueOutput;
1895 var annotation = output.clone();
1896 var conflicting;
1897
1898 if (
1899 Object.prototype.hasOwnProperty.call(
1900 promiseByKey,
1901 key
1902 ) &&
1903 promiseByKey[key].isRejected()
1904 ) {
1905 conflicting = promiseByKey[key].reason();
1906 }
1907
1908 var missingArrayIndex =
1909 subjectType.is('array-like') &&
1910 !subjectType.hasKey(subject, key);
1911
1912 var isInlineDiff = true;
1913
1914 output.omitSubject = subjectKey;
1915 if (!valueType.hasKey(value, key)) {
1916 if (expect.flags.exhaustively) {
1917 annotation.error('should be removed');
1918 } else {
1919 conflicting = null;
1920 }
1921 } else if (!subjectType.hasKey(subject, key)) {
1922 if (expect.findTypeOf(valueKey).is('expect.it')) {
1923 if (promiseByKey[key].isRejected()) {
1924 output.error('// missing:').sp();
1925 valueOutput = output
1926 .clone()
1927 .appendErrorMessage(promiseByKey[key].reason());
1928 } else {
1929 output.error('// missing').sp();
1930 valueOutput = output
1931 .clone()
1932 .error('should satisfy')
1933 .sp()
1934 .block(inspect(value[key]));
1935 }
1936 } else {
1937 output.error('// missing').sp();
1938 valueOutput = inspect(valueKey);
1939 }
1940 } else if (conflicting || missingArrayIndex) {
1941 var keyDiff =
1942 conflicting && conflicting.getDiff({ output: output });
1943 isInlineDiff = !keyDiff || keyDiff.inline;
1944 if (missingArrayIndex) {
1945 output.error('// missing').sp();
1946 }
1947 if (keyDiff && keyDiff.inline) {
1948 valueOutput = keyDiff;
1949 } else if (
1950 expect.findTypeOf(valueKey).is('expect.it')
1951 ) {
1952 isInlineDiff = false;
1953 annotation.appendErrorMessage(conflicting);
1954 } else if (!keyDiff || (keyDiff && !keyDiff.inline)) {
1955 annotation
1956 .error(
1957 (conflicting && conflicting.getLabel()) ||
1958 'should satisfy'
1959 )
1960 .sp()
1961 .block(inspect(valueKey));
1962
1963 if (keyDiff) {
1964 annotation.nl(2).append(keyDiff);
1965 }
1966 } else {
1967 valueOutput = keyDiff;
1968 }
1969 }
1970
1971 if (!valueOutput) {
1972 if (
1973 missingArrayIndex ||
1974 !subjectType.hasKey(subject, key)
1975 ) {
1976 valueOutput = output.clone();
1977 } else {
1978 valueOutput = inspect(subjectKey);
1979 }
1980 }
1981
1982 var omitDelimiter =
1983 missingArrayIndex || index >= subjectKeys.length - 1;
1984
1985 if (!omitDelimiter) {
1986 var delimiterOutput = subjectType.delimiter(
1987 output.clone(),
1988 index,
1989 keys.length
1990 );
1991 valueOutput.amend(delimiterOutput);
1992 }
1993
1994 var annotationOnNextLine =
1995 !isInlineDiff &&
1996 output.preferredWidth <
1997 this.size().width +
1998 valueOutput.size().width +
1999 annotation.size().width;
2000
2001 if (!annotation.isEmpty()) {
2002 if (!valueOutput.isEmpty()) {
2003 if (annotationOnNextLine) {
2004 valueOutput.nl();
2005 } else {
2006 valueOutput.sp();
2007 }
2008 }
2009
2010 valueOutput.annotationBlock(function() {
2011 this.append(annotation);
2012 });
2013 }
2014
2015 if (!isInlineDiff) {
2016 valueOutput = output.clone().block(valueOutput);
2017 }
2018
2019 var propertyOutput = subjectType.property(
2020 output.clone(),
2021 key,
2022 valueOutput,
2023 subjectIsArrayLike
2024 );
2025
2026 this.append(propertyOutput);
2027 });
2028 });
2029
2030 if (subjectType.indent) {
2031 output.outdentLines();
2032 }
2033 var suffixOutput = subjectType.suffix(
2034 output.clone(),
2035 subject
2036 );
2037 return output
2038 .nl(suffixOutput.isEmpty() ? 0 : 1)
2039 .append(suffixOutput);
2040 }
2041 });
2042 }); }
2043 );
2044 }
2045 );
2046
2047 function wrapDiffWithTypePrefixAndSuffix(e, type, subject) {
2048 var createDiff = e.getDiffMethod();
2049 if (createDiff) {
2050 return function(output) {
2051 var rest = [], len = arguments.length - 1;
2052 while ( len-- > 0 ) rest[ len ] = arguments[ len + 1 ];
2053
2054 type.prefix(output, subject);
2055 var result = createDiff.call.apply(createDiff, [ this, output ].concat( rest ));
2056 type.suffix(output, subject);
2057 return result;
2058 };
2059 }
2060 }
2061
2062 expect.addAssertion(
2063 '<wrapperObject> to [exhaustively] satisfy <wrapperObject>',
2064 function (expect, subject, value) {
2065 var type = expect.findCommonType(subject, value);
2066 expect(type.is('wrapperObject'), 'to be truthy');
2067 return expect.withError(
2068 function () { return expect(
2069 type.unwrap(subject),
2070 'to [exhaustively] satisfy',
2071 type.unwrap(value)
2072 ); },
2073 function (e) {
2074 expect.fail({
2075 label: e.getLabel(),
2076 diff: wrapDiffWithTypePrefixAndSuffix(e, type, subject)
2077 });
2078 }
2079 );
2080 }
2081 );
2082
2083 expect.addAssertion(
2084 '<wrapperObject> to [exhaustively] satisfy <any>',
2085 function (expect, subject, value) {
2086 var subjectType = expect.subjectType;
2087
2088 return expect.withError(
2089 function () { return expect(
2090 subjectType.unwrap(subject),
2091 'to [exhaustively] satisfy',
2092 value
2093 ); },
2094 function (e) {
2095 expect.fail({
2096 label: e.getLabel(),
2097 diff: wrapDiffWithTypePrefixAndSuffix(e, subjectType, subject)
2098 });
2099 }
2100 );
2101 }
2102 );
2103
2104 expect.addAssertion(
2105 '<function> [when] called with <array-like> <assertion?>',
2106 function (expect, subject, args) {
2107 // ...
2108 expect.errorMode = 'nested';
2109 expect.argsOutput[0] = function (output) {
2110 output.appendItems(args, ', ');
2111 };
2112
2113 var thisObject = expect.context.thisObject || null;
2114
2115 return expect.shift(subject.apply(thisObject, args));
2116 }
2117 );
2118
2119 expect.addAssertion(
2120 '<function> [when] called <assertion?>',
2121 function (expect, subject) {
2122 expect.errorMode = 'nested';
2123
2124 var thisObject = expect.context.thisObject || null;
2125
2126 return expect.shift(subject.call(thisObject));
2127 }
2128 );
2129
2130 function instantiate(Constructor, args) {
2131 function ProxyConstructor() {
2132 return Constructor.apply(this, args);
2133 }
2134 ProxyConstructor.prototype = Constructor.prototype;
2135 return new ProxyConstructor();
2136 }
2137
2138 expect.addAssertion(
2139 [
2140 '<array-like> [when] passed as parameters to [async] <function> <assertion?>',
2141 '<array-like> [when] passed as parameters to [constructor] <function> <assertion?>'
2142 ],
2143 function (expect, subject, fn) {
2144 // ...
2145 expect.errorMode = 'nested';
2146 var args = subject;
2147 if (expect.flags.async) {
2148 return expect.promise(function (run) {
2149 args = args.concat( [run(function (err, result) {
2150 expect(err, 'to be falsy');
2151 return expect.shift(result);
2152 })]
2153 );
2154 fn.apply(void 0, args);
2155 });
2156 } else {
2157 return expect.shift(
2158 expect.flags.constructor ? instantiate(fn, args) : fn.apply(void 0, args)
2159 );
2160 }
2161 }
2162 );
2163
2164 expect.addAssertion(
2165 [
2166 '<any> [when] passed as parameter to [async] <function> <assertion?>',
2167 '<any> [when] passed as parameter to [constructor] <function> <assertion?>'
2168 ],
2169 function (expect, subject, fn) {
2170 // ...
2171 expect.errorMode = 'nested';
2172 var args = [subject];
2173 if (expect.flags.async) {
2174 return expect.promise(function (run) {
2175 args = args.concat( [run(function (err, result) {
2176 expect(err, 'to be falsy');
2177 return expect.shift(result);
2178 })]
2179 );
2180 fn.apply(void 0, args);
2181 });
2182 } else {
2183 return expect.shift(
2184 expect.flags.constructor ? instantiate(fn, args) : fn.apply(void 0, args)
2185 );
2186 }
2187 }
2188 );
2189
2190 expect.addAssertion(
2191 [
2192 '<array-like> [when] sorted [numerically] <assertion?>',
2193 '<array-like> [when] sorted by <function> <assertion?>'
2194 ],
2195 function (expect, subject, compareFunction) {
2196 if (expect.flags.numerically) {
2197 compareFunction = function (a, b) { return a - b; };
2198 }
2199 return expect.shift(
2200 Array.prototype.slice
2201 .call(subject)
2202 .sort(
2203 typeof compareFunction === 'function' ? compareFunction : undefined
2204 )
2205 );
2206 }
2207 );
2208
2209 expect.addAssertion('<Promise> to be rejected', function (expect, subject) {
2210 expect.errorMode = 'nested';
2211 return expect
2212 .promise(function () { return subject; })
2213 .then(
2214 function (obj) {
2215 expect.fail(function (output) {
2216 output
2217 .appendInspected(subject)
2218 .sp()
2219 .text('unexpectedly fulfilled');
2220 if (typeof obj !== 'undefined') {
2221 output
2222 .sp()
2223 .text('with')
2224 .sp()
2225 .appendInspected(obj);
2226 }
2227 });
2228 },
2229 function (err) { return err; }
2230 );
2231 });
2232
2233 expect.addAssertion('<function> to be rejected', function (expect, subject) {
2234 expect.errorMode = 'nested';
2235 return expect(expect.promise(function () { return subject(); }), 'to be rejected');
2236 });
2237
2238 expect.addAssertion(
2239 [
2240 '<Promise> to be rejected with <any>',
2241 '<Promise> to be rejected with error [exhaustively] satisfying <any>'
2242 ],
2243 function (expect, subject, value) {
2244 expect.errorMode = 'nested';
2245 return expect(subject, 'to be rejected').tap(function (err) { return expect.withError(
2246 function () { return expect(err, 'to [exhaustively] satisfy', value); },
2247 function (e) {
2248 e.originalError = err;
2249 throw e;
2250 }
2251 ); }
2252 );
2253 }
2254 );
2255
2256 expect.addAssertion(
2257 [
2258 '<function> to be rejected with <any>',
2259 '<function> to be rejected with error [exhaustively] satisfying <any>'
2260 ],
2261 function (expect, subject, value) {
2262 expect.errorMode = 'nested';
2263 return expect(
2264 expect.promise(function () { return subject(); }),
2265 'to be rejected with error [exhaustively] satisfying',
2266 value
2267 );
2268 }
2269 );
2270
2271 expect.addAssertion('<Promise> to be fulfilled', function (expect, subject) {
2272 expect.errorMode = 'nested';
2273 return expect
2274 .promise(function () { return subject; })
2275 .caught(function (err) {
2276 expect.fail({
2277 output: function output(output$1) {
2278 output$1
2279 .appendInspected(subject)
2280 .sp()
2281 .text('unexpectedly rejected');
2282 if (typeof err !== 'undefined') {
2283 output$1
2284 .sp()
2285 .text('with')
2286 .sp()
2287 .appendInspected(err);
2288 }
2289 },
2290 originalError: err
2291 });
2292 });
2293 });
2294
2295 expect.addAssertion('<function> to be fulfilled', function (expect, subject) {
2296 expect.errorMode = 'nested';
2297 return expect(expect.promise(function () { return subject(); }), 'to be fulfilled');
2298 });
2299
2300 expect.addAssertion(
2301 [
2302 '<Promise> to be fulfilled with <any>',
2303 '<Promise> to be fulfilled with value [exhaustively] satisfying <any>'
2304 ],
2305 function (expect, subject, value) {
2306 expect.errorMode = 'nested';
2307 return expect(subject, 'to be fulfilled').tap(function (fulfillmentValue) { return expect(fulfillmentValue, 'to [exhaustively] satisfy', value); }
2308 );
2309 }
2310 );
2311
2312 expect.addAssertion(
2313 [
2314 '<function> to be fulfilled with <any>',
2315 '<function> to be fulfilled with value [exhaustively] satisfying <any>'
2316 ],
2317 function (expect, subject, value) {
2318 expect.errorMode = 'nested';
2319 return expect(
2320 expect.promise(function () { return subject(); }),
2321 'to be fulfilled with value [exhaustively] satisfying',
2322 value
2323 );
2324 }
2325 );
2326
2327 expect.addAssertion(
2328 '<Promise> when rejected <assertion>',
2329 function (expect, subject, nextAssertion) {
2330 expect.errorMode = 'nested';
2331 return expect
2332 .promise(function () { return subject; })
2333 .then(
2334 function (fulfillmentValue) {
2335 if (typeof nextAssertion === 'string') {
2336 expect.argsOutput = function (output) {
2337 output.error(nextAssertion);
2338 var rest = expect.args.slice(1);
2339 if (rest.length > 0) {
2340 output.sp().appendItems(rest, ', ');
2341 }
2342 };
2343 }
2344 expect.fail(function (output) {
2345 output
2346 .appendInspected(subject)
2347 .sp()
2348 .text('unexpectedly fulfilled');
2349 if (typeof fulfillmentValue !== 'undefined') {
2350 output
2351 .sp()
2352 .text('with')
2353 .sp()
2354 .appendInspected(fulfillmentValue);
2355 }
2356 });
2357 },
2358 function (err) {
2359 if (
2360 err.isOperational &&
2361 !err.propertyIsEnumerable('isOperational')
2362 ) {
2363 delete err.isOperational;
2364 }
2365
2366 expect.withError(
2367 function () { return expect.shift(err); },
2368 function (e) {
2369 e.originalError = err;
2370 throw e;
2371 }
2372 );
2373 }
2374 );
2375 }
2376 );
2377
2378 expect.addAssertion(
2379 '<function> when rejected <assertion>',
2380 function (expect, subject) {
2381 var rest = [], len = arguments.length - 2;
2382 while ( len-- > 0 ) rest[ len ] = arguments[ len + 2 ];
2383
2384 expect.errorMode = 'nested';
2385 return expect.apply(void 0, [ expect.promise(function () { return subject(); }), 'when rejected' ].concat( rest ));
2386 }
2387 );
2388
2389 expect.addAssertion(
2390 '<Promise> when fulfilled <assertion>',
2391 function (expect, subject, nextAssertion) {
2392 expect.errorMode = 'nested';
2393 return expect
2394 .promise(function () { return subject; })
2395 .then(
2396 function (fulfillmentValue) { return expect.shift(fulfillmentValue); },
2397 function (err) {
2398 // typeof nextAssertion === 'string' because expect.it is handled by the above (and shift only supports those two):
2399 expect.argsOutput = function (output) {
2400 output.error(nextAssertion);
2401 var rest = expect.args.slice(1);
2402 if (rest.length > 0) {
2403 output.sp().appendItems(rest, ', ');
2404 }
2405 };
2406 expect.fail({
2407 output: function output(output$1) {
2408 output$1
2409 .appendInspected(subject)
2410 .sp()
2411 .text('unexpectedly rejected');
2412 if (typeof err !== 'undefined') {
2413 output$1
2414 .sp()
2415 .text('with')
2416 .sp()
2417 .appendInspected(err);
2418 }
2419 },
2420 originalError: err
2421 });
2422 }
2423 );
2424 }
2425 );
2426
2427 expect.addAssertion(
2428 '<function> when fulfilled <assertion>',
2429 function (expect, subject) {
2430 var rest = [], len = arguments.length - 2;
2431 while ( len-- > 0 ) rest[ len ] = arguments[ len + 2 ];
2432
2433 expect.errorMode = 'nested';
2434 return expect.apply(void 0, [ expect.promise(function () { return subject(); }), 'when fulfilled' ].concat( rest ));
2435 }
2436 );
2437
2438 expect.addAssertion('<function> to call the callback', function (expect, subject) {
2439 expect.errorMode = 'nested';
2440 return expect.promise(function (run) {
2441 var async = false;
2442 var calledTwice = false;
2443 var callbackArgs;
2444 function cb() {
2445 var args = [], len = arguments.length;
2446 while ( len-- ) args[ len ] = arguments[ len ];
2447
2448 if (callbackArgs) {
2449 calledTwice = true;
2450 } else {
2451 callbackArgs = Array.prototype.slice.call(args);
2452 }
2453 if (async) {
2454 setTimeout(assert, 0);
2455 }
2456 }
2457
2458 var assert = run(function () {
2459 if (calledTwice) {
2460 expect.fail(function() {
2461 this.error('The callback was called twice');
2462 });
2463 }
2464 return callbackArgs;
2465 });
2466
2467 subject(cb);
2468 async = true;
2469 if (callbackArgs) {
2470 return assert();
2471 }
2472 });
2473 });
2474
2475 expect.addAssertion(
2476 '<function> to call the callback without error',
2477 function (expect, subject) { return expect(subject, 'to call the callback').then(function (callbackArgs) {
2478 var err = callbackArgs[0];
2479 if (err) {
2480 expect.errorMode = 'nested';
2481 expect.fail({
2482 message: function message(output) {
2483 output.error('called the callback with: ');
2484 if (err.getErrorMessage) {
2485 output.appendErrorMessage(err);
2486 } else {
2487 output.appendInspected(err);
2488 }
2489 }
2490 });
2491 } else {
2492 return callbackArgs.slice(1);
2493 }
2494 }); }
2495 );
2496
2497 expect.addAssertion(
2498 '<function> to call the callback with error',
2499 function (expect, subject) { return expect(subject, 'to call the callback').spread(function (err) {
2500 expect(err, 'to be truthy');
2501 return err;
2502 }); }
2503 );
2504
2505 expect.addAssertion(
2506 '<function> to call the callback with error <any>',
2507 function (expect, subject, value) { return expect(subject, 'to call the callback with error').tap(function (err) {
2508 expect.errorMode = 'nested';
2509 expect(err, 'to satisfy', value);
2510 }); }
2511 );
2512};