aboutsummaryrefslogtreecommitdiff
path: root/node_modules/ava/lib/assert.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/ava/lib/assert.js')
-rw-r--r--node_modules/ava/lib/assert.js171
1 files changed, 113 insertions, 58 deletions
diff --git a/node_modules/ava/lib/assert.js b/node_modules/ava/lib/assert.js
index c16e11a1a..a0e9fe82c 100644
--- a/node_modules/ava/lib/assert.js
+++ b/node_modules/ava/lib/assert.js
@@ -1,12 +1,32 @@
'use strict';
+const concordance = require('concordance');
const coreAssert = require('core-assert');
-const deepEqual = require('lodash.isequal');
const observableToPromise = require('observable-to-promise');
const isObservable = require('is-observable');
const isPromise = require('is-promise');
-const jestDiff = require('jest-diff');
+const concordanceOptions = require('./concordance-options').default;
+const concordanceDiffOptions = require('./concordance-options').diff;
const enhanceAssert = require('./enhance-assert');
-const formatAssertError = require('./format-assert-error');
+const snapshotManager = require('./snapshot-manager');
+
+function formatDescriptorDiff(actualDescriptor, expectedDescriptor, options) {
+ options = Object.assign({}, options, concordanceDiffOptions);
+ return {
+ label: 'Difference:',
+ formatted: concordance.diffDescriptors(actualDescriptor, expectedDescriptor, options)
+ };
+}
+
+function formatDescriptorWithLabel(label, descriptor) {
+ return {
+ label,
+ formatted: concordance.formatDescriptor(descriptor, concordanceOptions)
+ };
+}
+
+function formatWithLabel(label, value) {
+ return formatDescriptorWithLabel(label, concordance.describe(value, concordanceOptions));
+}
class AssertionError extends Error {
constructor(opts) {
@@ -19,6 +39,11 @@ class AssertionError extends Error {
this.operator = opts.operator;
this.values = opts.values || [];
+ // Raw expected and actual objects are stored for custom reporters
+ // (such as wallaby.js), that manage worker processes directly and
+ // use the values for custom diff views
+ this.raw = opts.raw;
+
// Reserved for power-assert statements
this.statements = [];
@@ -41,7 +66,6 @@ function wrapAssertions(callbacks) {
const fail = callbacks.fail;
const noop = () => {};
- const makeNoop = () => noop;
const makeRethrow = reason => () => {
throw reason;
};
@@ -59,31 +83,27 @@ function wrapAssertions(callbacks) {
},
is(actual, expected, message) {
- if (actual === expected) {
+ if (Object.is(actual, expected)) {
pass(this);
} else {
- const diff = formatAssertError.formatDiff(actual, expected);
- const values = diff ? [diff] : [
- formatAssertError.formatWithLabel('Actual:', actual),
- formatAssertError.formatWithLabel('Must be strictly equal to:', expected)
- ];
-
+ const actualDescriptor = concordance.describe(actual, concordanceOptions);
+ const expectedDescriptor = concordance.describe(expected, concordanceOptions);
fail(this, new AssertionError({
assertion: 'is',
message,
- operator: '===',
- values
+ raw: {actual, expected},
+ values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
}));
}
},
not(actual, expected, message) {
- if (actual === expected) {
+ if (Object.is(actual, expected)) {
fail(this, new AssertionError({
assertion: 'not',
message,
- operator: '!==',
- values: [formatAssertError.formatWithLabel('Value is strictly equal:', actual)]
+ raw: {actual, expected},
+ values: [formatWithLabel('Value is the same as:', actual)]
}));
} else {
pass(this);
@@ -91,29 +111,30 @@ function wrapAssertions(callbacks) {
},
deepEqual(actual, expected, message) {
- if (deepEqual(actual, expected)) {
+ const result = concordance.compare(actual, expected, concordanceOptions);
+ if (result.pass) {
pass(this);
} else {
- const diff = formatAssertError.formatDiff(actual, expected);
- const values = diff ? [diff] : [
- formatAssertError.formatWithLabel('Actual:', actual),
- formatAssertError.formatWithLabel('Must be deeply equal to:', expected)
- ];
-
+ const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
+ const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions);
fail(this, new AssertionError({
assertion: 'deepEqual',
message,
- values
+ raw: {actual, expected},
+ values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)]
}));
}
},
notDeepEqual(actual, expected, message) {
- if (deepEqual(actual, expected)) {
+ const result = concordance.compare(actual, expected, concordanceOptions);
+ if (result.pass) {
+ const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
fail(this, new AssertionError({
assertion: 'notDeepEqual',
message,
- values: [formatAssertError.formatWithLabel('Value is deeply equal:', actual)]
+ raw: {actual, expected},
+ values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)]
}));
} else {
pass(this);
@@ -131,7 +152,7 @@ function wrapAssertions(callbacks) {
assertion: 'throws',
improperUsage: true,
message: '`t.throws()` must be called with a function, Promise, or Observable',
- values: [formatAssertError.formatWithLabel('Called with:', fn)]
+ values: [formatWithLabel('Called with:', fn)]
}));
return;
}
@@ -160,15 +181,13 @@ function wrapAssertions(callbacks) {
}, coreAssertThrowsErrorArg);
return actual;
} catch (err) {
- const values = threw ?
- [formatAssertError.formatWithLabel('Threw unexpected exception:', actual)] :
- null;
-
throw new AssertionError({
assertion: 'throws',
message,
stack,
- values
+ values: threw ?
+ [formatWithLabel('Threw unexpected exception:', actual)] :
+ null
});
}
};
@@ -176,7 +195,14 @@ function wrapAssertions(callbacks) {
if (promise) {
// Record stack before it gets lost in the promise chain.
const stack = getStack();
- const intermediate = promise.then(makeNoop, makeRethrow).then(fn => test(fn, stack));
+ const intermediate = promise.then(value => {
+ throw new AssertionError({
+ assertion: 'throws',
+ message: 'Expected promise to be rejected, but it was resolved instead',
+ values: [formatWithLabel('Resolved with:', value)]
+ });
+ }, reason => test(makeRethrow(reason), stack));
+
pending(this, intermediate);
// Don't reject the returned promise, even if the assertion fails.
return intermediate.catch(noop);
@@ -202,7 +228,7 @@ function wrapAssertions(callbacks) {
assertion: 'notThrows',
improperUsage: true,
message: '`t.notThrows()` must be called with a function, Promise, or Observable',
- values: [formatAssertError.formatWithLabel('Called with:', fn)]
+ values: [formatWithLabel('Called with:', fn)]
}));
return;
}
@@ -215,7 +241,7 @@ function wrapAssertions(callbacks) {
assertion: 'notThrows',
message,
stack,
- values: [formatAssertError.formatWithLabel('Threw:', err.actual)]
+ values: [formatWithLabel('Threw:', err.actual)]
});
}
};
@@ -242,28 +268,57 @@ function wrapAssertions(callbacks) {
fail(this, new AssertionError({
assertion: 'ifError',
message,
- values: [formatAssertError.formatWithLabel('Error:', actual)]
+ values: [formatWithLabel('Error:', actual)]
}));
} else {
pass(this);
}
},
- snapshot(actual, message) {
- const state = this._test.getSnapshotState();
- const result = state.match(this.title, actual);
+ snapshot(expected, optionsOrMessage, message) {
+ const options = {};
+ if (typeof optionsOrMessage === 'string') {
+ message = optionsOrMessage;
+ } else if (optionsOrMessage) {
+ options.id = optionsOrMessage.id;
+ }
+ options.expected = expected;
+ options.message = message;
+
+ let result;
+ try {
+ result = this._test.compareWithSnapshot(options);
+ } catch (err) {
+ if (!(err instanceof snapshotManager.SnapshotError)) {
+ throw err;
+ }
+
+ const improperUsage = {name: err.name, snapPath: err.snapPath};
+ if (err instanceof snapshotManager.VersionMismatchError) {
+ improperUsage.snapVersion = err.snapVersion;
+ improperUsage.expectedVersion = err.expectedVersion;
+ }
+
+ fail(this, new AssertionError({
+ assertion: 'snapshot',
+ message: message || 'Could not compare snapshot',
+ improperUsage
+ }));
+ return;
+ }
+
if (result.pass) {
pass(this);
- } else {
- const diff = jestDiff(result.expected.trim(), result.actual.trim(), {expand: true})
- // Remove annotation
- .split('\n')
- .slice(3)
- .join('\n');
+ } else if (result.actual) {
fail(this, new AssertionError({
assertion: 'snapshot',
message: message || 'Did not match snapshot',
- values: [{label: 'Difference:', formatted: diff}]
+ values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})]
+ }));
+ } else {
+ fail(this, new AssertionError({
+ assertion: 'snapshot',
+ message: message || 'No snapshot available, run with --update-snapshots'
}));
}
}
@@ -276,7 +331,7 @@ function wrapAssertions(callbacks) {
assertion: 'truthy',
message,
operator: '!!',
- values: [formatAssertError.formatWithLabel('Value is not truthy:', actual)]
+ values: [formatWithLabel('Value is not truthy:', actual)]
});
}
},
@@ -287,7 +342,7 @@ function wrapAssertions(callbacks) {
assertion: 'falsy',
message,
operator: '!',
- values: [formatAssertError.formatWithLabel('Value is not falsy:', actual)]
+ values: [formatWithLabel('Value is not falsy:', actual)]
});
}
},
@@ -297,7 +352,7 @@ function wrapAssertions(callbacks) {
throw new AssertionError({
assertion: 'true',
message,
- values: [formatAssertError.formatWithLabel('Value is not `true`:', actual)]
+ values: [formatWithLabel('Value is not `true`:', actual)]
});
}
},
@@ -307,7 +362,7 @@ function wrapAssertions(callbacks) {
throw new AssertionError({
assertion: 'false',
message,
- values: [formatAssertError.formatWithLabel('Value is not `false`:', actual)]
+ values: [formatWithLabel('Value is not `false`:', actual)]
});
}
},
@@ -318,7 +373,7 @@ function wrapAssertions(callbacks) {
assertion: 'regex',
improperUsage: true,
message: '`t.regex()` must be called with a string',
- values: [formatAssertError.formatWithLabel('Called with:', string)]
+ values: [formatWithLabel('Called with:', string)]
});
}
if (!(regex instanceof RegExp)) {
@@ -326,7 +381,7 @@ function wrapAssertions(callbacks) {
assertion: 'regex',
improperUsage: true,
message: '`t.regex()` must be called with a regular expression',
- values: [formatAssertError.formatWithLabel('Called with:', regex)]
+ values: [formatWithLabel('Called with:', regex)]
});
}
@@ -335,8 +390,8 @@ function wrapAssertions(callbacks) {
assertion: 'regex',
message,
values: [
- formatAssertError.formatWithLabel('Value must match expression:', string),
- formatAssertError.formatWithLabel('Regular expression:', regex)
+ formatWithLabel('Value must match expression:', string),
+ formatWithLabel('Regular expression:', regex)
]
});
}
@@ -348,7 +403,7 @@ function wrapAssertions(callbacks) {
assertion: 'notRegex',
improperUsage: true,
message: '`t.notRegex()` must be called with a string',
- values: [formatAssertError.formatWithLabel('Called with:', string)]
+ values: [formatWithLabel('Called with:', string)]
});
}
if (!(regex instanceof RegExp)) {
@@ -356,7 +411,7 @@ function wrapAssertions(callbacks) {
assertion: 'notRegex',
improperUsage: true,
message: '`t.notRegex()` must be called with a regular expression',
- values: [formatAssertError.formatWithLabel('Called with:', regex)]
+ values: [formatWithLabel('Called with:', regex)]
});
}
@@ -365,8 +420,8 @@ function wrapAssertions(callbacks) {
assertion: 'notRegex',
message,
values: [
- formatAssertError.formatWithLabel('Value must not match expression:', string),
- formatAssertError.formatWithLabel('Regular expression:', regex)
+ formatWithLabel('Value must not match expression:', string),
+ formatWithLabel('Regular expression:', regex)
]
});
}