1 | const utils = require('./utils');
|
2 | const isRegExp = utils.isRegExp;
|
3 | const leftPad = utils.leftPad;
|
4 | const arrayChanges = require('array-changes');
|
5 | const ukkonen = require('ukkonen');
|
6 | const detectIndent = require('detect-indent');
|
7 | const defaultDepth = require('./defaultDepth');
|
8 | const AssertionString = require('./AssertionString');
|
9 |
|
10 | module.exports = function(expect) {
|
11 | expect.addType({
|
12 | name: 'wrapperObject',
|
13 | identify: false,
|
14 | equal(a, b, equal) {
|
15 | return a === b || equal(this.unwrap(a), this.unwrap(b));
|
16 | },
|
17 | inspect(value, depth, output, inspect) {
|
18 | output.append(this.prefix(output.clone(), value));
|
19 | output.append(inspect(this.unwrap(value), depth));
|
20 | output.append(this.suffix(output.clone(), value));
|
21 | return output;
|
22 | },
|
23 | diff(actual, expected, output, diff, inspect) {
|
24 | output.inline = true;
|
25 | actual = this.unwrap(actual);
|
26 | expected = this.unwrap(expected);
|
27 | const comparison = diff(actual, expected);
|
28 | const prefixOutput = this.prefix(output.clone(), actual);
|
29 | const suffixOutput = this.suffix(output.clone(), actual);
|
30 | if (comparison && comparison.inline) {
|
31 | return output
|
32 | .append(prefixOutput)
|
33 | .append(comparison)
|
34 | .append(suffixOutput);
|
35 | } else {
|
36 | return output
|
37 | .append(prefixOutput)
|
38 | .nl()
|
39 | .indentLines()
|
40 | .i()
|
41 | .block(function() {
|
42 | this.append(inspect(actual))
|
43 | .sp()
|
44 | .annotationBlock(function() {
|
45 | this.shouldEqualError(expected, inspect);
|
46 | if (comparison) {
|
47 | this.nl(2).append(comparison);
|
48 | }
|
49 | });
|
50 | })
|
51 | .nl()
|
52 | .outdentLines()
|
53 | .append(suffixOutput);
|
54 | }
|
55 | }
|
56 | });
|
57 |
|
58 | expect.addType({
|
59 | name: 'Symbol',
|
60 | identify(obj) {
|
61 | return typeof obj === 'symbol';
|
62 | },
|
63 | inspect(obj, depth, output, inspect) {
|
64 | return output
|
65 | .jsKeyword('Symbol')
|
66 | .text('(')
|
67 | .singleQuotedString(obj.toString().replace(/^Symbol\(|\)$/g, ''))
|
68 | .text(')');
|
69 | }
|
70 | });
|
71 |
|
72 | expect.addType({
|
73 | name: 'object',
|
74 | indent: true,
|
75 | forceMultipleLines: false,
|
76 | identify(obj) {
|
77 | return obj && typeof obj === 'object';
|
78 | },
|
79 | prefix(output, obj) {
|
80 | const constructor = obj.constructor;
|
81 | const constructorName =
|
82 | constructor &&
|
83 | typeof constructor === 'function' &&
|
84 | constructor !== Object &&
|
85 | utils.getFunctionName(constructor);
|
86 | if (constructorName && constructorName !== 'Object') {
|
87 | output.text(`${constructorName}(`);
|
88 | }
|
89 | return output.text('{');
|
90 | },
|
91 | property(output, key, inspectedValue, isArrayLike) {
|
92 | return output.propertyForObject(key, inspectedValue, isArrayLike);
|
93 | },
|
94 | suffix(output, obj) {
|
95 | output.text('}');
|
96 | const constructor = obj.constructor;
|
97 | const constructorName =
|
98 | constructor &&
|
99 | typeof constructor === 'function' &&
|
100 | constructor !== Object &&
|
101 | utils.getFunctionName(constructor);
|
102 | if (constructorName && constructorName !== 'Object') {
|
103 | output.text(')');
|
104 | }
|
105 | return output;
|
106 | },
|
107 | delimiter(output, i, length) {
|
108 | if (i < length - 1) {
|
109 | output.text(',');
|
110 | }
|
111 | return output;
|
112 | },
|
113 | getKeys: Object.getOwnPropertySymbols
|
114 | ? obj => {
|
115 | const keys = Object.getOwnPropertyNames(obj);
|
116 | const symbols = Object.getOwnPropertySymbols(obj);
|
117 | if (symbols.length > 0) {
|
118 | return keys.concat(symbols);
|
119 | } else {
|
120 | return keys;
|
121 | }
|
122 | }
|
123 | : Object.getOwnPropertyNames,
|
124 |
|
125 |
|
126 | keyComparator:
|
127 | typeof Symbol === 'function'
|
128 | ? (a, b) => {
|
129 | let aString = a;
|
130 | let bString = b;
|
131 | const aIsSymbol = typeof a === 'symbol';
|
132 | const bIsSymbol = typeof b === 'symbol';
|
133 | if (aIsSymbol) {
|
134 | if (bIsSymbol) {
|
135 | aString = a.toString();
|
136 | bString = b.toString();
|
137 | } else {
|
138 | return 1;
|
139 | }
|
140 | } else if (bIsSymbol) {
|
141 | return -1;
|
142 | }
|
143 |
|
144 | if (aString < bString) {
|
145 | return -1;
|
146 | } else if (aString > bString) {
|
147 | return 1;
|
148 | }
|
149 |
|
150 | return 0;
|
151 | }
|
152 | : undefined,
|
153 | equal(a, b, equal) {
|
154 | return utils.checkObjectEqualityUsingType(a, b, this, equal);
|
155 | },
|
156 | hasKey(obj, key, own) {
|
157 | if (own) {
|
158 | return Object.prototype.hasOwnProperty.call(obj, key);
|
159 | } else {
|
160 | return key in obj;
|
161 | }
|
162 | },
|
163 | inspect(obj, depth, output, inspect) {
|
164 | const keys = this.getKeys(obj);
|
165 | if (keys.length === 0) {
|
166 | this.prefix(output, obj);
|
167 | this.suffix(output, obj);
|
168 | return output;
|
169 | }
|
170 | const type = this;
|
171 | const inspectedItems = keys.map((key, index) => {
|
172 | const propertyDescriptor =
|
173 | Object.getOwnPropertyDescriptor &&
|
174 | Object.getOwnPropertyDescriptor(obj, key);
|
175 | const hasGetter = propertyDescriptor && propertyDescriptor.get;
|
176 | const hasSetter = propertyDescriptor && propertyDescriptor.set;
|
177 | const propertyOutput = output.clone();
|
178 | if (hasSetter && !hasGetter) {
|
179 | propertyOutput.text('set').sp();
|
180 | }
|
181 |
|
182 | let value;
|
183 | if (hasSetter && !hasGetter) {
|
184 | value = hasSetter;
|
185 | } else {
|
186 | value = type.valueForKey(obj, key);
|
187 | }
|
188 |
|
189 | let inspectedValue = inspect(value);
|
190 | if (value && value._expectIt) {
|
191 | inspectedValue = output.clone().block(inspectedValue);
|
192 | }
|
193 | type.property(propertyOutput, key, inspectedValue);
|
194 |
|
195 | propertyOutput.amend(
|
196 | type.delimiter(output.clone(), index, keys.length)
|
197 | );
|
198 |
|
199 | if (hasGetter && hasSetter) {
|
200 | propertyOutput.sp().jsComment('/* getter/setter */');
|
201 | } else if (hasGetter) {
|
202 | propertyOutput.sp().jsComment('/* getter */');
|
203 | }
|
204 |
|
205 | return propertyOutput;
|
206 | });
|
207 |
|
208 | const maxLineLength =
|
209 | output.preferredWidth - (depth === Infinity ? 0 : depth) * 2 - 2;
|
210 | let width = 0;
|
211 | const compact =
|
212 | inspectedItems.length > 5 ||
|
213 | inspectedItems.every(inspectedItem => {
|
214 | if (inspectedItem.isMultiline()) {
|
215 | return false;
|
216 | }
|
217 | width += inspectedItem.size().width;
|
218 | return width < maxLineLength;
|
219 | });
|
220 |
|
221 | const itemsOutput = output.clone();
|
222 | if (compact) {
|
223 | let currentLineLength = 0;
|
224 | inspectedItems.forEach((inspectedItem, index) => {
|
225 | const size = inspectedItem.size();
|
226 | currentLineLength += size.width + 1;
|
227 | if (index > 0) {
|
228 | if (size.height === 1 && currentLineLength < maxLineLength) {
|
229 | itemsOutput.sp();
|
230 | } else {
|
231 | itemsOutput.nl();
|
232 | currentLineLength = size.width;
|
233 | }
|
234 |
|
235 | if (size.height > 1) {
|
236 |
|
237 | currentLineLength = maxLineLength;
|
238 | }
|
239 | }
|
240 | itemsOutput.append(inspectedItem);
|
241 | });
|
242 | } else {
|
243 | inspectedItems.forEach((inspectedItem, index) => {
|
244 | if (index > 0) {
|
245 | itemsOutput.nl();
|
246 | }
|
247 | itemsOutput.append(inspectedItem);
|
248 | });
|
249 | }
|
250 |
|
251 | const prefixOutput = this.prefix(output.clone(), obj);
|
252 | const suffixOutput = this.suffix(output.clone(), obj);
|
253 | output.append(prefixOutput);
|
254 | if (this.forceMultipleLines || itemsOutput.isMultiline()) {
|
255 | if (!prefixOutput.isEmpty()) {
|
256 | output.nl();
|
257 | }
|
258 | if (this.indent) {
|
259 | output.indentLines().i();
|
260 | }
|
261 | output.block(itemsOutput);
|
262 | if (this.indent) {
|
263 | output.outdentLines();
|
264 | }
|
265 | if (!suffixOutput.isEmpty()) {
|
266 | output.nl();
|
267 | }
|
268 | } else {
|
269 | output
|
270 | .sp(prefixOutput.isEmpty() ? 0 : 1)
|
271 | .append(itemsOutput)
|
272 | .sp(suffixOutput.isEmpty() ? 0 : 1);
|
273 | }
|
274 | return output.append(suffixOutput);
|
275 | },
|
276 | diff(actual, expected, output, diff, inspect, equal) {
|
277 | if (actual.constructor !== expected.constructor) {
|
278 | return output
|
279 | .text('Mismatching constructors ')
|
280 | .text(
|
281 | (actual.constructor && utils.getFunctionName(actual.constructor)) ||
|
282 | actual.constructor
|
283 | )
|
284 | .text(' should be ')
|
285 | .text(
|
286 | (expected.constructor &&
|
287 | utils.getFunctionName(expected.constructor)) ||
|
288 | expected.constructor
|
289 | );
|
290 | }
|
291 |
|
292 | output.inline = true;
|
293 | const actualKeys = this.getKeys(actual);
|
294 | const expectedKeys = this.getKeys(expected);
|
295 | const keys = this.uniqueKeys(actualKeys, expectedKeys);
|
296 | const prefixOutput = this.prefix(output.clone(), actual);
|
297 | output.append(prefixOutput).nl(prefixOutput.isEmpty() ? 0 : 1);
|
298 |
|
299 | if (this.indent) {
|
300 | output.indentLines();
|
301 | }
|
302 | const type = this;
|
303 | keys.forEach((key, index) => {
|
304 | output
|
305 | .nl(index > 0 ? 1 : 0)
|
306 | .i()
|
307 | .block(function() {
|
308 | const valueActual = type.valueForKey(actual, key);
|
309 | const valueExpected = type.valueForKey(expected, key);
|
310 | const annotation = output.clone();
|
311 | const conflicting = !equal(valueActual, valueExpected);
|
312 | let isInlineDiff = false;
|
313 | let valueOutput;
|
314 | if (conflicting) {
|
315 | if (!type.hasKey(expected, key)) {
|
316 | annotation.error('should be removed');
|
317 | isInlineDiff = true;
|
318 | } else if (!type.hasKey(actual, key)) {
|
319 | this.error('// missing').sp();
|
320 | valueOutput = output.clone().appendInspected(valueExpected);
|
321 | isInlineDiff = true;
|
322 | } else {
|
323 | const keyDiff = diff(valueActual, valueExpected);
|
324 | if (!keyDiff || (keyDiff && !keyDiff.inline)) {
|
325 | annotation.shouldEqualError(valueExpected);
|
326 | if (keyDiff) {
|
327 | annotation.nl(2).append(keyDiff);
|
328 | }
|
329 | } else {
|
330 | isInlineDiff = true;
|
331 | valueOutput = keyDiff;
|
332 | }
|
333 | }
|
334 | } else {
|
335 | isInlineDiff = true;
|
336 | }
|
337 |
|
338 | if (!valueOutput) {
|
339 | valueOutput = inspect(valueActual, conflicting ? Infinity : null);
|
340 | }
|
341 |
|
342 | valueOutput.amend(
|
343 | type.delimiter(output.clone(), index, actualKeys.length)
|
344 | );
|
345 | if (!isInlineDiff) {
|
346 | valueOutput = output.clone().block(valueOutput);
|
347 | }
|
348 | type.property(this, key, valueOutput);
|
349 | if (!annotation.isEmpty()) {
|
350 | this.sp().annotationBlock(annotation);
|
351 | }
|
352 | });
|
353 | });
|
354 |
|
355 | if (this.indent) {
|
356 | output.outdentLines();
|
357 | }
|
358 | const suffixOutput = this.suffix(output.clone(), actual);
|
359 | return output.nl(suffixOutput.isEmpty() ? 0 : 1).append(suffixOutput);
|
360 | },
|
361 | similar(a, b) {
|
362 | if (a === null || b === null) {
|
363 | return false;
|
364 | }
|
365 |
|
366 | const typeA = typeof a;
|
367 | const typeB = typeof b;
|
368 |
|
369 | if (typeA !== typeB) {
|
370 | return false;
|
371 | }
|
372 |
|
373 | if (typeA === 'string') {
|
374 | return ukkonen(a, b) < a.length / 2;
|
375 | }
|
376 |
|
377 | if (typeA !== 'object' || !a) {
|
378 | return false;
|
379 | }
|
380 |
|
381 | if (utils.isArray(a) && utils.isArray(b)) {
|
382 | return true;
|
383 | }
|
384 |
|
385 | const aKeys = this.getKeys(a);
|
386 | const bKeys = this.getKeys(b);
|
387 | let numberOfSimilarKeys = 0;
|
388 | const requiredSimilarKeys = Math.round(
|
389 | Math.max(aKeys.length, bKeys.length) / 2
|
390 | );
|
391 | return aKeys.concat(bKeys).some(key => {
|
392 | if (this.hasKey(a, key) && this.hasKey(b, key)) {
|
393 | numberOfSimilarKeys += 1;
|
394 | }
|
395 | return numberOfSimilarKeys >= requiredSimilarKeys;
|
396 | });
|
397 | },
|
398 | uniqueKeys: utils.uniqueStringsAndSymbols,
|
399 | valueForKey(obj, key) {
|
400 | return obj[key];
|
401 | }
|
402 | });
|
403 |
|
404 | expect.addType({
|
405 | name: 'type',
|
406 | base: 'object',
|
407 | identify(value) {
|
408 | return value && value._unexpectedType;
|
409 | },
|
410 | inspect({ name }, depth, output) {
|
411 | return output.text('type: ').jsKeyword(name);
|
412 | }
|
413 | });
|
414 |
|
415 | expect.addType({
|
416 | name: 'array-like',
|
417 | base: 'object',
|
418 | identify: false,
|
419 | numericalPropertiesOnly: true,
|
420 | getKeys(obj) {
|
421 | const keys = new Array(obj.length);
|
422 | for (let i = 0; i < obj.length; i += 1) {
|
423 | keys[i] = i;
|
424 | }
|
425 | if (!this.numericalPropertiesOnly) {
|
426 | keys.push(...this.getKeysNonNumerical(obj));
|
427 | }
|
428 | return keys;
|
429 | },
|
430 | getKeysNonNumerical: Object.getOwnPropertySymbols
|
431 | ? obj => {
|
432 | const keys = [];
|
433 | Object.keys(obj).forEach(key => {
|
434 | if (!utils.numericalRegExp.test(key)) {
|
435 | keys.push(key);
|
436 | }
|
437 | });
|
438 | const symbols = Object.getOwnPropertySymbols(obj);
|
439 | if (symbols.length > 0) {
|
440 | keys.push(...symbols);
|
441 | }
|
442 | return keys;
|
443 | }
|
444 | : obj => {
|
445 | const keys = [];
|
446 | Object.keys(obj).forEach(key => {
|
447 | if (!utils.numericalRegExp.test(key)) {
|
448 | keys.push(key);
|
449 | }
|
450 | });
|
451 | return keys;
|
452 | },
|
453 | equal(a, b, equal) {
|
454 | if (a === b) {
|
455 | return true;
|
456 | } else if (a.constructor === b.constructor && a.length === b.length) {
|
457 | let i;
|
458 |
|
459 |
|
460 | for (i = 0; i < a.length; i += 1) {
|
461 | if (!equal(this.valueForKey(a, i), this.valueForKey(b, i))) {
|
462 | return false;
|
463 | }
|
464 | }
|
465 |
|
466 |
|
467 | if (!this.numericalPropertiesOnly) {
|
468 | const aKeys = this.getKeysNonNumerical(a).filter(key => {
|
469 |
|
470 | return typeof this.valueForKey(a, key) !== 'undefined';
|
471 | });
|
472 | const bKeys = this.getKeysNonNumerical(b).filter(key => {
|
473 |
|
474 | return (
|
475 | typeof this.valueForKey(b, key) !== 'undefined' ||
|
476 | typeof this.valueForKey(a, key) !== 'undefined'
|
477 | );
|
478 | });
|
479 |
|
480 | if (aKeys.length !== bKeys.length) {
|
481 | return false;
|
482 | }
|
483 |
|
484 | for (i = 0; i < aKeys.length; i += 1) {
|
485 | if (
|
486 | !equal(
|
487 | this.valueForKey(a, aKeys[i]),
|
488 | this.valueForKey(b, bKeys[i])
|
489 | )
|
490 | ) {
|
491 | return false;
|
492 | }
|
493 | }
|
494 | }
|
495 |
|
496 | return true;
|
497 | } else {
|
498 | return false;
|
499 | }
|
500 | },
|
501 | prefix(output) {
|
502 | return output.text('[');
|
503 | },
|
504 | suffix(output) {
|
505 | return output.text(']');
|
506 | },
|
507 | inspect(arr, depth, output, inspect) {
|
508 | const prefixOutput = this.prefix(output.clone(), arr);
|
509 | const suffixOutput = this.suffix(output.clone(), arr);
|
510 | const keys = this.getKeys(arr);
|
511 | if (keys.length === 0) {
|
512 | return output.append(prefixOutput).append(suffixOutput);
|
513 | }
|
514 |
|
515 | if (depth === 1 && arr.length > 10) {
|
516 | return output
|
517 | .append(prefixOutput)
|
518 | .text('...')
|
519 | .append(suffixOutput);
|
520 | }
|
521 |
|
522 | const inspectedItems = keys.map(key => {
|
523 | let inspectedValue;
|
524 | if (this.hasKey(arr, key)) {
|
525 | inspectedValue = inspect(this.valueForKey(arr, key));
|
526 | } else if (utils.numericalRegExp.test(key)) {
|
527 |
|
528 | inspectedValue = output.clone();
|
529 | } else {
|
530 |
|
531 | inspectedValue = inspect(undefined);
|
532 | }
|
533 | return this.property(output.clone(), key, inspectedValue, true);
|
534 | });
|
535 |
|
536 | const currentDepth = defaultDepth - Math.min(defaultDepth, depth);
|
537 | const maxLineLength =
|
538 | output.preferredWidth - 20 - currentDepth * output.indentationWidth - 2;
|
539 | let width = 0;
|
540 | const multipleLines =
|
541 | this.forceMultipleLines ||
|
542 | inspectedItems.some(o => {
|
543 | if (o.isMultiline()) {
|
544 | return true;
|
545 | }
|
546 |
|
547 | const size = o.size();
|
548 | width += size.width;
|
549 | return width > maxLineLength;
|
550 | });
|
551 | inspectedItems.forEach((inspectedItem, index) => {
|
552 | inspectedItem.amend(this.delimiter(output.clone(), index, keys.length));
|
553 | });
|
554 | if (multipleLines) {
|
555 | output.append(prefixOutput);
|
556 | if (!prefixOutput.isEmpty()) {
|
557 | output.nl();
|
558 | }
|
559 | if (this.indent) {
|
560 | output.indentLines();
|
561 | }
|
562 | inspectedItems.forEach((inspectedItem, index) => {
|
563 | output
|
564 | .nl(index > 0 ? 1 : 0)
|
565 | .i()
|
566 | .block(inspectedItem);
|
567 | });
|
568 |
|
569 | if (this.indent) {
|
570 | output.outdentLines();
|
571 | }
|
572 |
|
573 | if (!suffixOutput.isEmpty()) {
|
574 | output.nl();
|
575 | }
|
576 |
|
577 | return output.append(suffixOutput);
|
578 | } else {
|
579 | output.append(prefixOutput).sp(prefixOutput.isEmpty() ? 0 : 1);
|
580 | inspectedItems.forEach((inspectedItem, index) => {
|
581 | output.append(inspectedItem);
|
582 | const lastIndex = index === inspectedItems.length - 1;
|
583 | if (!lastIndex) {
|
584 | output.sp();
|
585 | }
|
586 | });
|
587 | return output.sp(suffixOutput.isEmpty() ? 0 : 1).append(suffixOutput);
|
588 | }
|
589 | },
|
590 | diffLimit: 512,
|
591 | diff(actual, expected, output, diff, inspect, equal) {
|
592 | output.inline = true;
|
593 |
|
594 | if (Math.max(actual.length, expected.length) > this.diffLimit) {
|
595 | output.jsComment(`Diff suppressed due to size > ${this.diffLimit}`);
|
596 | return output;
|
597 | }
|
598 |
|
599 | if (actual.constructor !== expected.constructor) {
|
600 | return this.baseType.diff(actual, expected, output);
|
601 | }
|
602 |
|
603 | const prefixOutput = this.prefix(output.clone(), actual);
|
604 | output.append(prefixOutput).nl(prefixOutput.isEmpty() ? 0 : 1);
|
605 |
|
606 | if (this.indent) {
|
607 | output.indentLines();
|
608 | }
|
609 |
|
610 | var actualElements = utils.duplicateArrayLikeUsingType(actual, this);
|
611 | var actualKeys = this.getKeys(actual);
|
612 | var expectedElements = utils.duplicateArrayLikeUsingType(expected, this);
|
613 | var expectedKeys = this.getKeys(expected);
|
614 | var nonNumericalKeysAndSymbols =
|
615 | !this.numericalPropertiesOnly &&
|
616 | utils.uniqueNonNumericalStringsAndSymbols(actualKeys, expectedKeys);
|
617 |
|
618 | const type = this;
|
619 | const changes = arrayChanges(
|
620 | actualElements,
|
621 | expectedElements,
|
622 | equal,
|
623 | (a, b) => type.similar(a, b),
|
624 | {
|
625 | includeNonNumericalProperties: nonNumericalKeysAndSymbols
|
626 | }
|
627 | );
|
628 | const indexOfLastNonInsert = changes.reduce(
|
629 | (previousValue, diffItem, index) =>
|
630 | diffItem.type === 'insert' ? previousValue : index,
|
631 | -1
|
632 | );
|
633 | const packing = utils.packArrows(changes);
|
634 | output.arrowsAlongsideChangeOutputs(
|
635 | packing,
|
636 | changes.map((diffItem, index) => {
|
637 | const delimiterOutput = type.delimiter(
|
638 | output.clone(),
|
639 | index,
|
640 | indexOfLastNonInsert + 1
|
641 | );
|
642 | if (diffItem.type === 'moveTarget') {
|
643 | return output.clone();
|
644 | } else {
|
645 | return output.clone().block(function() {
|
646 | if (diffItem.type === 'moveSource') {
|
647 | const propertyOutput = type.property(
|
648 | output.clone(),
|
649 | diffItem.actualIndex,
|
650 | inspect(diffItem.value),
|
651 | true
|
652 | );
|
653 | this.amend(propertyOutput)
|
654 | .amend(delimiterOutput)
|
655 | .sp()
|
656 | .error('// should be moved');
|
657 | } else if (diffItem.type === 'insert') {
|
658 | this.annotationBlock(function() {
|
659 | this.error('missing ').block(function() {
|
660 | const index =
|
661 | typeof diffItem.actualIndex !== 'undefined'
|
662 | ? diffItem.actualIndex
|
663 | : diffItem.expectedIndex;
|
664 | const propertyOutput = type.property(
|
665 | output.clone(),
|
666 | index,
|
667 | inspect(diffItem.value),
|
668 | true
|
669 | );
|
670 | this.amend(propertyOutput);
|
671 | });
|
672 | });
|
673 | } else if (diffItem.type === 'remove') {
|
674 | this.block(function() {
|
675 | const propertyOutput = type.property(
|
676 | output.clone(),
|
677 | diffItem.actualIndex,
|
678 | inspect(diffItem.value),
|
679 | true
|
680 | );
|
681 | this.amend(propertyOutput)
|
682 | .amend(delimiterOutput)
|
683 | .sp()
|
684 | .error('// should be removed');
|
685 | });
|
686 | } else if (diffItem.type === 'equal') {
|
687 | this.block(function() {
|
688 | const propertyOutput = type.property(
|
689 | output.clone(),
|
690 | diffItem.actualIndex,
|
691 | inspect(diffItem.value),
|
692 | true
|
693 | );
|
694 | this.amend(propertyOutput).amend(delimiterOutput);
|
695 | });
|
696 | } else {
|
697 | this.block(function() {
|
698 | const valueDiff = diff(diffItem.value, diffItem.expected);
|
699 | if (valueDiff && valueDiff.inline) {
|
700 | this.append(valueDiff).append(delimiterOutput);
|
701 | } else {
|
702 | const propertyOutput = type.property(
|
703 | output.clone(),
|
704 | diffItem.actualIndex,
|
705 | inspect(diffItem.value),
|
706 | true
|
707 | );
|
708 | this.append(propertyOutput)
|
709 | .append(delimiterOutput)
|
710 | .sp()
|
711 | .annotationBlock(function() {
|
712 | this.shouldEqualError(diffItem.expected, inspect);
|
713 | if (valueDiff) {
|
714 | this.nl(2).append(valueDiff);
|
715 | }
|
716 | });
|
717 | }
|
718 | });
|
719 | }
|
720 | });
|
721 | }
|
722 | })
|
723 | );
|
724 |
|
725 | if (this.indent) {
|
726 | output.outdentLines();
|
727 | }
|
728 |
|
729 | const suffixOutput = this.suffix(output.clone(), actual);
|
730 | return output.nl(suffixOutput.isEmpty() ? 0 : 1).append(suffixOutput);
|
731 | }
|
732 | });
|
733 |
|
734 | expect.addType({
|
735 | name: 'array',
|
736 | base: 'array-like',
|
737 | numericalPropertiesOnly: false,
|
738 | identify(arr) {
|
739 | return utils.isArray(arr);
|
740 | }
|
741 | });
|
742 |
|
743 | expect.addType({
|
744 | name: 'arguments',
|
745 | base: 'array-like',
|
746 | prefix(output) {
|
747 | return output.text('arguments(', 'cyan');
|
748 | },
|
749 | suffix(output) {
|
750 | return output.text(')', 'cyan');
|
751 | },
|
752 | identify(obj) {
|
753 | return Object.prototype.toString.call(obj) === '[object Arguments]';
|
754 | }
|
755 | });
|
756 |
|
757 | const errorMethodBlacklist = [
|
758 | 'message',
|
759 | 'name',
|
760 | 'description',
|
761 | 'line',
|
762 | 'number',
|
763 | 'column',
|
764 | 'sourceId',
|
765 | 'sourceURL',
|
766 | 'stack',
|
767 | 'stackArray',
|
768 | '__stackCleaned__',
|
769 | 'isOperational'
|
770 | ].reduce((result, prop) => {
|
771 | result[prop] = true;
|
772 | return result;
|
773 | }, {});
|
774 |
|
775 | if (Object.prototype.hasOwnProperty.call(new Error(), 'arguments')) {
|
776 |
|
777 | errorMethodBlacklist.arguments = true;
|
778 | errorMethodBlacklist.type = true;
|
779 | }
|
780 |
|
781 | expect.addType({
|
782 | base: 'object',
|
783 | name: 'Error',
|
784 | identify(value) {
|
785 | return utils.isError(value);
|
786 | },
|
787 | getKeys(value) {
|
788 | const keys = this.baseType
|
789 | .getKeys(value)
|
790 | .filter(key => !errorMethodBlacklist[key]);
|
791 | keys.unshift('message');
|
792 | return keys;
|
793 | },
|
794 | unwrap(value) {
|
795 | return this.getKeys(value).reduce((result, key) => {
|
796 | result[key] = value[key];
|
797 | return result;
|
798 | }, {});
|
799 | },
|
800 | equal(a, b, equal) {
|
801 | return (
|
802 | a === b ||
|
803 | (equal(a.message, b.message) &&
|
804 | utils.checkObjectEqualityUsingType(a, b, this, equal))
|
805 | );
|
806 | },
|
807 | inspect(value, depth, output, inspect) {
|
808 | output.errorName(value).text('(');
|
809 | const keys = this.getKeys(value);
|
810 | if (keys.length === 1 && keys[0] === 'message') {
|
811 | if (value.message !== '') {
|
812 | output.append(inspect(value.message));
|
813 | }
|
814 | } else {
|
815 | output.append(inspect(this.unwrap(value), depth));
|
816 | }
|
817 | return output.text(')');
|
818 | },
|
819 | diff(actual, expected, output, diff) {
|
820 | if (actual.constructor !== expected.constructor) {
|
821 | return output
|
822 | .text('Mismatching constructors ')
|
823 | .errorName(actual)
|
824 | .text(' should be ')
|
825 | .errorName(expected);
|
826 | }
|
827 |
|
828 | output = diff(this.unwrap(actual), this.unwrap(expected));
|
829 | if (output) {
|
830 | output = output
|
831 | .clone()
|
832 | .errorName(actual)
|
833 | .text('(')
|
834 | .append(output)
|
835 | .text(')');
|
836 | output.inline = false;
|
837 | }
|
838 | return output;
|
839 | }
|
840 | });
|
841 |
|
842 | const unexpectedErrorMethodBlacklist = [
|
843 | 'output',
|
844 | '_isUnexpected',
|
845 | 'htmlMessage',
|
846 | '_hasSerializedErrorMessage',
|
847 | 'expect',
|
848 | 'assertion',
|
849 | 'originalError'
|
850 | ].reduce((result, prop) => {
|
851 | result[prop] = true;
|
852 | return result;
|
853 | }, {});
|
854 | expect.addType({
|
855 | base: 'Error',
|
856 | name: 'UnexpectedError',
|
857 | identify(value) {
|
858 | return (
|
859 | value &&
|
860 | typeof value === 'object' &&
|
861 | value._isUnexpected &&
|
862 | this.baseType.identify(value)
|
863 | );
|
864 | },
|
865 | getKeys(value) {
|
866 | return this.baseType
|
867 | .getKeys(value)
|
868 | .filter(key => !unexpectedErrorMethodBlacklist[key]);
|
869 | },
|
870 | inspect(value, depth, output) {
|
871 | output.jsFunctionName(this.name).text('(');
|
872 | const errorMessage = value.getErrorMessage(output);
|
873 | if (errorMessage.isMultiline()) {
|
874 | output
|
875 | .nl()
|
876 | .indentLines()
|
877 | .i()
|
878 | .block(errorMessage)
|
879 | .nl();
|
880 | } else {
|
881 | output.append(errorMessage);
|
882 | }
|
883 | return output.text(')');
|
884 | }
|
885 | });
|
886 |
|
887 | expect.addType({
|
888 | name: 'date',
|
889 | identify(obj) {
|
890 | return Object.prototype.toString.call(obj) === '[object Date]';
|
891 | },
|
892 | equal(a, b) {
|
893 | return a.getTime() === b.getTime();
|
894 | },
|
895 | inspect(date, depth, output, inspect) {
|
896 |
|
897 | let dateStr = date.toUTCString().replace(/UTC/, 'GMT');
|
898 | const milliseconds = date.getUTCMilliseconds();
|
899 | if (milliseconds > 0) {
|
900 | let millisecondsStr = String(milliseconds);
|
901 | while (millisecondsStr.length < 3) {
|
902 | millisecondsStr = `0${millisecondsStr}`;
|
903 | }
|
904 | dateStr = dateStr.replace(' GMT', `.${millisecondsStr} GMT`);
|
905 | }
|
906 |
|
907 | return output
|
908 | .jsKeyword('new')
|
909 | .sp()
|
910 | .text('Date(')
|
911 | .append(inspect(dateStr).text(')'));
|
912 | }
|
913 | });
|
914 |
|
915 | expect.addType({
|
916 | base: 'object',
|
917 | name: 'function',
|
918 | identify(f) {
|
919 | return typeof f === 'function';
|
920 | },
|
921 | getKeys: Object.keys,
|
922 | equal(a, b) {
|
923 | return a === b;
|
924 | },
|
925 | inspect(f, depth, output, inspect) {
|
926 |
|
927 | const source = Function.prototype.toString
|
928 | .call(f)
|
929 | .replace(/\r\n?|\n\r?/g, '\n');
|
930 | let name = utils.getFunctionName(f) || '';
|
931 | let preamble;
|
932 | let body;
|
933 | let bodyIndent;
|
934 | const matchSource = source.match(
|
935 | /^\s*((?:async )?\s*(?:\S+\s*=>|\([^)]*\)\s*=>|class|function\s?(?:\*\s*)?\w*\s*\([^)]*\)))([\s\S]*)$/
|
936 | );
|
937 | if (matchSource) {
|
938 |
|
939 | preamble = matchSource[1]
|
940 | .replace(/function(\S)/, 'function $1')
|
941 | .replace(/\* /, '*');
|
942 | if (preamble === 'function ()' && name) {
|
943 |
|
944 | preamble = `function ${name}()`;
|
945 | }
|
946 | body = matchSource[2];
|
947 | let matchBodyAndIndent = body.match(/^(\s*\{)([\s\S]*?)([ ]*)\}\s*$/);
|
948 | let openingBrace;
|
949 | let isWrappedInBraces = true;
|
950 | let closingBrace = '}';
|
951 | let reindentBodyLevel = 0;
|
952 | if (matchBodyAndIndent) {
|
953 | openingBrace = matchBodyAndIndent[1];
|
954 | body = matchBodyAndIndent[2];
|
955 | bodyIndent = matchBodyAndIndent[3] || '';
|
956 | if (bodyIndent.length === 1) {
|
957 | closingBrace = ' }';
|
958 | }
|
959 | } else {
|
960 |
|
961 | matchBodyAndIndent = body.match(/^(\s*)([\s\S]*?)([ ]*)\s*$/);
|
962 |
|
963 | if (matchBodyAndIndent) {
|
964 | openingBrace = matchBodyAndIndent[1];
|
965 | isWrappedInBraces = false;
|
966 | body = matchBodyAndIndent[2];
|
967 | const matchInitialNewline = openingBrace.match(/^\n( +)/);
|
968 | if (matchInitialNewline) {
|
969 | openingBrace = '\n';
|
970 | if (/\n/.test(body)) {
|
971 |
|
972 |
|
973 |
|
974 |
|
975 |
|
976 |
|
977 | bodyIndent = matchInitialNewline[1];
|
978 | reindentBodyLevel = 1;
|
979 | } else {
|
980 | body = body.replace(/^\s*/, ' ');
|
981 | }
|
982 | } else {
|
983 | bodyIndent = matchBodyAndIndent[3] || '';
|
984 | }
|
985 | closingBrace = '';
|
986 | }
|
987 | }
|
988 |
|
989 |
|
990 | if (/\n/.test(body) && !/\\\n/.test(body)) {
|
991 | body = body.replace(new RegExp(`^ {${bodyIndent.length}}`, 'mg'), '');
|
992 | const indent = detectIndent(body);
|
993 | body = body.replace(
|
994 | new RegExp(`^(?:${indent.indent})*`, 'mg'),
|
995 | ({ length }) =>
|
996 | utils.leftPad(
|
997 | '',
|
998 | (length / indent.amount + reindentBodyLevel) *
|
999 | output.indentationWidth,
|
1000 | ' '
|
1001 | )
|
1002 | );
|
1003 | }
|
1004 | if (!name || name === 'anonymous') {
|
1005 | name = '';
|
1006 | }
|
1007 | if (/^\s*\[native code\]\s*$/.test(body)) {
|
1008 | body = ' /* native code */ ';
|
1009 | closingBrace = '}';
|
1010 | } else if (/^\s*$/.test(body)) {
|
1011 | body = '';
|
1012 | } else if (
|
1013 | /^\s*[^\r\n]{1,30}\s*$/.test(body) &&
|
1014 | body.indexOf('//') === -1 &&
|
1015 | isWrappedInBraces
|
1016 | ) {
|
1017 | body = ` ${body.trim()} `;
|
1018 | closingBrace = '}';
|
1019 | } else {
|
1020 | body = body.replace(
|
1021 | /^((?:.*\n){3}( *).*\n)[\s\S]*?\n[\s\S]*?\n((?:.*\n){3})$/,
|
1022 | '$1$2// ... lines removed ...\n$3'
|
1023 | );
|
1024 | }
|
1025 | if (matchBodyAndIndent) {
|
1026 | body = openingBrace + body + closingBrace;
|
1027 | } else {
|
1028 |
|
1029 | body = body.replace(/[ ]*$/, '');
|
1030 | }
|
1031 | } else {
|
1032 | preamble = `function ${name}( /*...*/ ) `;
|
1033 | body = '{ /*...*/ }';
|
1034 | }
|
1035 | return output.code(preamble + body, 'javascript');
|
1036 | },
|
1037 | diff(actual, expected, output) {
|
1038 |
|
1039 | if (typeof actual !== 'function' || typeof expected !== 'function') {
|
1040 | return this.baseType.diff(actual, expected, output);
|
1041 | }
|
1042 | }
|
1043 | });
|
1044 |
|
1045 | expect.addType({
|
1046 | base: 'function',
|
1047 | name: 'expect.it',
|
1048 | identify(f) {
|
1049 | return typeof f === 'function' && f._expectIt;
|
1050 | },
|
1051 | inspect({ _expectations, _OR }, depth, output, inspect) {
|
1052 | output.text('expect.it(');
|
1053 | let orBranch = false;
|
1054 | _expectations.forEach((expectation, index) => {
|
1055 | if (expectation === _OR) {
|
1056 | orBranch = true;
|
1057 | return;
|
1058 | }
|
1059 |
|
1060 | if (orBranch) {
|
1061 | output.text(')\n .or(');
|
1062 | } else if (index > 0) {
|
1063 | output.text(')\n .and(');
|
1064 | }
|
1065 |
|
1066 | const args = Array.prototype.slice.call(expectation);
|
1067 | args.forEach((arg, i) => {
|
1068 | if (i > 0) {
|
1069 | output.text(', ');
|
1070 | }
|
1071 | output.append(inspect(arg));
|
1072 | });
|
1073 | orBranch = false;
|
1074 | });
|
1075 |
|
1076 | return output.amend(')');
|
1077 | }
|
1078 | });
|
1079 |
|
1080 | expect.addType({
|
1081 | name: 'Promise',
|
1082 | base: 'object',
|
1083 | identify(obj) {
|
1084 | return (
|
1085 | obj && this.baseType.identify(obj) && typeof obj.then === 'function'
|
1086 | );
|
1087 | },
|
1088 | inspect(promise, depth, output, inspect) {
|
1089 | output.jsFunctionName('Promise');
|
1090 | if (promise.isPending && promise.isPending()) {
|
1091 | output.sp().yellow('(pending)');
|
1092 | } else if (promise.isFulfilled && promise.isFulfilled()) {
|
1093 | output.sp().green('(fulfilled)');
|
1094 | if (promise.value) {
|
1095 | const value = promise.value();
|
1096 | if (typeof value !== 'undefined') {
|
1097 | output
|
1098 | .sp()
|
1099 | .text('=>')
|
1100 | .sp()
|
1101 | .append(inspect(value));
|
1102 | }
|
1103 | }
|
1104 | } else if (promise.isRejected && promise.isRejected()) {
|
1105 | output.sp().red('(rejected)');
|
1106 | const reason = promise.reason();
|
1107 | if (typeof reason !== 'undefined') {
|
1108 | output
|
1109 | .sp()
|
1110 | .text('=>')
|
1111 | .sp()
|
1112 | .append(inspect(promise.reason()));
|
1113 | }
|
1114 | }
|
1115 | return output;
|
1116 | }
|
1117 | });
|
1118 |
|
1119 | expect.addType({
|
1120 | name: 'regexp',
|
1121 | base: 'object',
|
1122 | identify: isRegExp,
|
1123 | equal(a, b) {
|
1124 | return (
|
1125 | a === b ||
|
1126 | (a.source === b.source &&
|
1127 | a.global === b.global &&
|
1128 | a.ignoreCase === b.ignoreCase &&
|
1129 | a.multiline === b.multiline)
|
1130 | );
|
1131 | },
|
1132 | inspect(regExp, depth, output) {
|
1133 | return output.jsRegexp(regExp);
|
1134 | },
|
1135 | diff(actual, expected, output, diff, inspect) {
|
1136 | output.inline = false;
|
1137 | return output.stringDiff(String(actual), String(expected), {
|
1138 | type: 'Chars',
|
1139 | markUpSpecialCharacters: true
|
1140 | });
|
1141 | }
|
1142 | });
|
1143 |
|
1144 | expect.addType({
|
1145 | name: 'binaryArray',
|
1146 | base: 'array-like',
|
1147 | digitWidth: 2,
|
1148 | hexDumpWidth: 16,
|
1149 | identify: false,
|
1150 | prefix(output) {
|
1151 | return output.code(`${this.name}([`, 'javascript');
|
1152 | },
|
1153 | suffix(output) {
|
1154 | return output.code('])', 'javascript');
|
1155 | },
|
1156 | equal(a, b) {
|
1157 | if (a === b) {
|
1158 | return true;
|
1159 | }
|
1160 |
|
1161 | if (a.length !== b.length) {
|
1162 | return false;
|
1163 | }
|
1164 |
|
1165 | for (let i = 0; i < a.length; i += 1) {
|
1166 | if (a[i] !== b[i]) {
|
1167 | return false;
|
1168 | }
|
1169 | }
|
1170 |
|
1171 | return true;
|
1172 | },
|
1173 | hexDump(obj, maxLength) {
|
1174 | let hexDump = '';
|
1175 | if (typeof maxLength !== 'number' || maxLength === 0) {
|
1176 | maxLength = obj.length;
|
1177 | }
|
1178 | for (let i = 0; i < maxLength; i += this.hexDumpWidth) {
|
1179 | if (hexDump.length > 0) {
|
1180 | hexDump += '\n';
|
1181 | }
|
1182 | let hexChars = '';
|
1183 | let asciiChars = ' │';
|
1184 |
|
1185 | for (let j = 0; j < this.hexDumpWidth; j += 1) {
|
1186 | if (i + j < maxLength) {
|
1187 | const octet = obj[i + j];
|
1188 | hexChars += `${leftPad(
|
1189 | octet.toString(16).toUpperCase(),
|
1190 | this.digitWidth,
|
1191 | '0'
|
1192 | )} `;
|
1193 | asciiChars += String.fromCharCode(octet)
|
1194 | .replace(/\n/g, '␊')
|
1195 | .replace(/\r/g, '␍');
|
1196 | } else if (this.digitWidth === 2) {
|
1197 | hexChars += ' ';
|
1198 | }
|
1199 | }
|
1200 |
|
1201 | if (this.digitWidth === 2) {
|
1202 | hexDump += `${hexChars + asciiChars}│`;
|
1203 | } else {
|
1204 | hexDump += hexChars.replace(/\s+$/, '');
|
1205 | }
|
1206 | }
|
1207 | return hexDump;
|
1208 | },
|
1209 | inspect(obj, depth, output) {
|
1210 | this.prefix(output, obj);
|
1211 | let codeStr = '';
|
1212 | for (let i = 0; i < Math.min(this.hexDumpWidth, obj.length); i += 1) {
|
1213 | if (i > 0) {
|
1214 | codeStr += ', ';
|
1215 | }
|
1216 | const octet = obj[i];
|
1217 | codeStr += `0x${leftPad(
|
1218 | octet.toString(16).toUpperCase(),
|
1219 | this.digitWidth,
|
1220 | '0'
|
1221 | )}`;
|
1222 | }
|
1223 | if (obj.length > this.hexDumpWidth) {
|
1224 | codeStr += ` /* ${obj.length - this.hexDumpWidth} more */ `;
|
1225 | }
|
1226 | output.code(codeStr, 'javascript');
|
1227 | this.suffix(output, obj);
|
1228 | return output;
|
1229 | },
|
1230 | diffLimit: 512,
|
1231 | diff(actual, expected, output, diff, inspect) {
|
1232 | output.inline = false;
|
1233 | if (Math.max(actual.length, expected.length) > this.diffLimit) {
|
1234 | output.jsComment(`Diff suppressed due to size > ${this.diffLimit}`);
|
1235 | } else {
|
1236 | output
|
1237 | .stringDiff(this.hexDump(actual), this.hexDump(expected), {
|
1238 | type: 'Chars',
|
1239 | markUpSpecialCharacters: false
|
1240 | })
|
1241 |
|
1242 | .replaceText(/[\x00-\x1f\x7f-\xff␊␍]/g, '.')
|
1243 | .replaceText(/[│ ]/g, function(styles, content) {
|
1244 | this.text(content);
|
1245 | });
|
1246 | }
|
1247 | return output;
|
1248 | }
|
1249 | });
|
1250 |
|
1251 | [8, 16, 32].forEach(function(numBits) {
|
1252 | ['Int', 'Uint'].forEach(intOrUint => {
|
1253 | const constructorName = `${intOrUint + numBits}Array`;
|
1254 | const Constructor = global[constructorName];
|
1255 | expect.addType({
|
1256 | name: constructorName,
|
1257 | base: 'binaryArray',
|
1258 | hexDumpWidth: 128 / numBits,
|
1259 | digitWidth: numBits / 4,
|
1260 | identify:
|
1261 | Constructor !== 'undefined' &&
|
1262 | function(obj) {
|
1263 | return obj instanceof Constructor;
|
1264 | }
|
1265 | });
|
1266 | }, this);
|
1267 | }, this);
|
1268 |
|
1269 | expect.addType({
|
1270 | name: 'Buffer',
|
1271 | base: 'binaryArray',
|
1272 | identify: typeof Buffer === 'function' && Buffer.isBuffer,
|
1273 | prefix(output) {
|
1274 | return output.code(`Buffer.from([`, 'javascript');
|
1275 | }
|
1276 | });
|
1277 |
|
1278 | expect.addType({
|
1279 | name: 'string',
|
1280 | identify(value) {
|
1281 | return typeof value === 'string';
|
1282 | },
|
1283 | inspect(value, depth, output) {
|
1284 | return output.singleQuotedString(value);
|
1285 | },
|
1286 | diffLimit: 65536,
|
1287 | diff(actual, expected, output, diff, inspect) {
|
1288 | if (Math.max(actual.length, expected.length) > this.diffLimit) {
|
1289 | output.jsComment(`Diff suppressed due to size > ${this.diffLimit}`);
|
1290 | return output;
|
1291 | }
|
1292 | output.stringDiff(actual, expected, {
|
1293 | type: 'WordsWithSpace',
|
1294 | markUpSpecialCharacters: true
|
1295 | });
|
1296 | output.inline = false;
|
1297 | return output;
|
1298 | }
|
1299 | });
|
1300 |
|
1301 | expect.addType({
|
1302 | name: 'number',
|
1303 | identify(value) {
|
1304 | return typeof value === 'number' && !isNaN(value);
|
1305 | },
|
1306 | inspect(value, depth, output) {
|
1307 | if (value === 0 && 1 / value === -Infinity) {
|
1308 | value = '-0';
|
1309 | } else {
|
1310 | value = String(value);
|
1311 | }
|
1312 | return output.jsNumber(String(value));
|
1313 | }
|
1314 | });
|
1315 |
|
1316 | expect.addType({
|
1317 | name: 'NaN',
|
1318 | identify(value) {
|
1319 | return typeof value === 'number' && isNaN(value);
|
1320 | },
|
1321 | inspect(value, depth, output) {
|
1322 | return output.jsPrimitive(value);
|
1323 | }
|
1324 | });
|
1325 |
|
1326 | expect.addType({
|
1327 | name: 'BigInt',
|
1328 | identify(value) {
|
1329 | return typeof value === 'bigint';
|
1330 | },
|
1331 | inspect(value, depth, output) {
|
1332 | return output
|
1333 | .code('BigInt(', 'javascript')
|
1334 | .jsNumber(value.toString())
|
1335 | .code(')', 'javascript');
|
1336 | }
|
1337 | });
|
1338 |
|
1339 | expect.addType({
|
1340 | name: 'boolean',
|
1341 | identify(value) {
|
1342 | return typeof value === 'boolean';
|
1343 | },
|
1344 | inspect(value, depth, output) {
|
1345 | return output.jsPrimitive(value);
|
1346 | }
|
1347 | });
|
1348 |
|
1349 | expect.addType({
|
1350 | name: 'undefined',
|
1351 | identify(value) {
|
1352 | return typeof value === 'undefined';
|
1353 | },
|
1354 | inspect(value, depth, output) {
|
1355 | return output.jsPrimitive(value);
|
1356 | }
|
1357 | });
|
1358 |
|
1359 | expect.addType({
|
1360 | name: 'null',
|
1361 | identify(value) {
|
1362 | return value === null;
|
1363 | },
|
1364 | inspect(value, depth, output) {
|
1365 | return output.jsPrimitive(value);
|
1366 | }
|
1367 | });
|
1368 |
|
1369 | expect.addType({
|
1370 | name: 'assertion',
|
1371 | identify(value) {
|
1372 | return value instanceof AssertionString;
|
1373 | }
|
1374 | });
|
1375 | };
|