unexpected
Version:
Extensible BDD assertion toolkit
1,297 lines (1,160 loc) • 71.2 kB
JavaScript
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*global setTimeout*/
var utils = require('./utils');
var arrayChanges = require('array-changes');
var arrayChangesAsync = require('array-changes-async');
var throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
var objectIs = utils.objectIs;
var isRegExp = utils.isRegExp;
var extend = utils.extend;
module.exports = function (expect) {
expect.addAssertion('<any> [not] to be (ok|truthy)', function (expect, subject) {
var not = !!expect.flags.not;
var condition = !!subject;
if (condition === not) {
expect.fail();
}
});
expect.addAssertion('<any> [not] to be (ok|truthy) <string>', function (expect, subject, message) {
var not = !!expect.flags.not;
var condition = !!subject;
if (condition === not) {
expect.fail({
errorMode: 'bubble',
message: message
});
}
});
expect.addAssertion('<any> [not] to be <any>', function (expect, subject, value) {
expect(objectIs(subject, value), '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be <string>', function (expect, subject, value) {
expect(subject, '[not] to equal', value);
});
expect.addAssertion('<boolean> [not] to be true', function (expect, subject) {
expect(subject, '[not] to be', true);
});
expect.addAssertion('<boolean> [not] to be false', function (expect, subject) {
expect(subject, '[not] to be', false);
});
expect.addAssertion('<any> [not] to be falsy', function (expect, subject) {
expect(subject, '[!not] to be truthy');
});
expect.addAssertion('<any> [not] to be falsy <string>', function (expect, subject, message) {
var not = !!expect.flags.not;
var condition = !!subject;
if (condition !== not) {
expect.fail({
errorMode: 'bubble',
message: message
});
}
});
expect.addAssertion('<any> [not] to be null', function (expect, subject) {
expect(subject, '[not] to be', null);
});
expect.addAssertion('<any> [not] to be undefined', function (expect, subject) {
expect(typeof subject === 'undefined', '[not] to be truthy');
});
expect.addAssertion('<any> to be defined', function (expect, subject) {
expect(subject, 'not to be undefined');
});
expect.addAssertion('<number|NaN> [not] to be NaN', function (expect, subject) {
expect(isNaN(subject), '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be close to <number> <number?>', function (expect, subject, value, epsilon) {
expect.errorMode = 'bubble';
if (typeof epsilon !== 'number') {
epsilon = 1e-9;
}
expect.withError(function () {
expect(Math.abs(subject - value), '[not] to be less than or equal to', epsilon);
}, function (e) {
expect.fail(function (output) {
output.error('expected ').appendInspected(subject).sp().error(expect.testDescription).sp().appendInspected(value).sp().text('(epsilon: ').jsNumber(epsilon.toExponential()).text(')');
});
});
});
expect.addAssertion('<any> [not] to be (a|an) <type>', function (expect, subject, type) {
expect.argsOutput[0] = function (output) {
output.text(type.name);
};
expect(type.identify(subject), '[not] to be true');
});
expect.addAssertion('<any> [not] to be (a|an) <string>', function (expect, subject, typeName) {
typeName = /^reg(?:exp?|ular expression)$/.test(typeName) ? 'regexp' : typeName;
expect.argsOutput[0] = function (output) {
output.jsString(typeName);
};
if (!expect.getType(typeName)) {
expect.errorMode = 'nested';
expect.fail(function (output) {
output.error('Unknown type:').sp().jsString(typeName);
});
}
expect(expect.subjectType.is(typeName), '[not] to be truthy');
});
expect.addAssertion('<any> [not] to be (a|an) <function>', function (expect, subject, Constructor) {
var className = utils.getFunctionName(Constructor);
if (className) {
expect.argsOutput[0] = function (output) {
output.text(className);
};
}
expect(subject instanceof Constructor, '[not] to be truthy');
});
expect.addAssertion('<any> [not] to be one of <array>', function (expect, subject, superset) {
var found = false;
for (var i = 0; i < superset.length; i += 1) {
found = found || objectIs(subject, superset[i]);
}
if (found === expect.flags.not) {
expect.fail();
}
});
// Alias for common '[not] to be (a|an)' assertions
expect.addAssertion('<any> [not] to be an (object|array)', function (expect, subject) {
expect(subject, '[not] to be an', expect.alternations[0]);
});
expect.addAssertion('<any> [not] to be a (boolean|number|string|function|regexp|regex|regular expression|date)', function (expect, subject) {
expect(subject, '[not] to be a', expect.alternations[0]);
});
expect.addAssertion('<string> to be (the empty|an empty|a non-empty) string', function (expect, subject) {
expect(subject, expect.alternations[0] === 'a non-empty' ? 'not to be empty' : 'to be empty');
});
expect.addAssertion('<array-like> to be (the empty|an empty|a non-empty) array', function (expect, subject) {
expect(subject, expect.alternations[0] === 'a non-empty' ? 'not to be empty' : 'to be empty');
});
expect.addAssertion('<string> to match <regexp>', function (expect, subject, regexp) {
return expect.withError(function () {
var captures = subject.match(regexp);
expect(captures, 'to be truthy');
return captures;
}, function (e) {
e.label = 'should match';
expect.fail(e);
});
});
expect.addAssertion('<string> not to match <regexp>', function (expect, subject, regexp) {
return expect.withError(function () {
expect(regexp.test(subject), 'to be false');
}, function (e) {
expect.fail({
label: 'should not match',
diff: function diff(output) {
output.inline = false;
var lastIndex = 0;
function flushUntilIndex(i) {
if (i > lastIndex) {
output.text(subject.substring(lastIndex, i));
lastIndex = i;
}
}
subject.replace(new RegExp(regexp.source, 'g'), function ($0, index) {
flushUntilIndex(index);
lastIndex += $0.length;
output.removedHighlight($0);
});
flushUntilIndex(subject.length);
return output;
}
});
});
});
expect.addAssertion('<object|function> [not] to have own property <string>', function (expect, subject, key) {
expect(subject.hasOwnProperty(key), '[not] to be truthy');
return subject[key];
});
expect.addAssertion('<object|function> [not] to have (enumerable|configurable|writable) property <string>', function (expect, subject, key) {
var descriptor = expect.alternations[0];
expect(Object.getOwnPropertyDescriptor(subject, key)[descriptor], '[not] to be truthy');
return subject[key];
});
expect.addAssertion('<object|function> [not] to have property <string>', function (expect, subject, key) {
var subjectType = expect.findTypeOf(subject);
var subjectKey = subjectType.is('function') ? subject[key] : subjectType.valueForKey(subject, key);
expect(subjectKey, '[!not] to be undefined');
return subjectKey;
});
expect.addAssertion('<object|function> to have [own] property <string> <any>', function (expect, subject, key, expectedPropertyValue) {
return expect(subject, 'to have [own] property', key).then(function (actualPropertyValue) {
expect.argsOutput = function () {
this.appendInspected(key).sp().error('with a value of').sp().appendInspected(expectedPropertyValue);
};
expect(actualPropertyValue, 'to equal', expectedPropertyValue);
return actualPropertyValue;
});
});
expect.addAssertion('<object|function> [not] to have [own] properties <array>', function (expect, subject, propertyNames) {
var unsupportedPropertyNames = [];
propertyNames.forEach(function (propertyName) {
if (typeof propertyName !== 'string' && typeof propertyName !== 'number') {
unsupportedPropertyNames.push(propertyName);
}
});
if (unsupportedPropertyNames.length > 0) {
expect.errorMode = 'nested';
expect.fail(function () {
this.error('All expected properties must be passed as strings or numbers, but these are not:').indentLines();
unsupportedPropertyNames.forEach(function (propertyName) {
this.nl().i().appendInspected(propertyName);
}, this);
this.outdentLines();
});
}
propertyNames.forEach(function (propertyName) {
expect(subject, '[not] to have [own] property', String(propertyName));
});
});
expect.addAssertion('<object|function> to have [own] properties <object>', function (expect, subject, properties) {
expect.withError(function () {
Object.keys(properties).forEach(function (property) {
var value = properties[property];
if (typeof value === 'undefined') {
expect(subject, 'not to have [own] property', property);
} else {
expect(subject, 'to have [own] property', property, value);
}
});
}, function (e) {
expect.fail({
diff: function diff(output, _diff) {
output.inline = false;
var expected = extend({}, properties);
var actual = {};
var propertyNames = expect.findTypeOf(subject).getKeys(subject);
// Might put duplicates into propertyNames, but that does not matter:
for (var propertyName in subject) {
if (!subject.hasOwnProperty(propertyName)) {
propertyNames.push(propertyName);
}
}
propertyNames.forEach(function (propertyName) {
if ((!expect.flags.own || subject.hasOwnProperty(propertyName)) && !(propertyName in properties)) {
expected[propertyName] = subject[propertyName];
}
if ((!expect.flags.own || subject.hasOwnProperty(propertyName)) && !(propertyName in actual)) {
actual[propertyName] = subject[propertyName];
}
});
return utils.wrapConstructorNameAroundOutput(_diff(actual, expected), subject);
}
});
});
});
expect.addAssertion('<string|array-like> [not] to have length <number>', function (expect, subject, length) {
if (!expect.flags.not) {
expect.errorMode = 'nested';
}
expect(subject.length, '[not] to be', length);
});
expect.addAssertion('<string|array-like> [not] to be empty', function (expect, subject) {
expect(subject, '[not] to have length', 0);
});
expect.addAssertion('<string|array-like|object> to be non-empty', function (expect, subject) {
expect(subject, 'not to be empty');
});
expect.addAssertion('<object> to [not] [only] have keys <array>', function (expect, subject, keys) {
var keysInSubject = {};
var subjectType = expect.findTypeOf(subject);
var subjectKeys = subjectType.getKeys(subject);
subjectKeys.forEach(function (key) {
keysInSubject[key] = true;
});
if (expect.flags.not && keys.length === 0) {
return;
}
var hasKeys = keys.every(function (key) {
return keysInSubject[key];
});
if (expect.flags.only) {
expect(hasKeys, 'to be truthy');
expect.withError(function () {
expect(subjectKeys.length === keys.length, '[not] to be truthy');
}, function (err) {
expect.fail({
diff: !expect.flags.not && function (output, diff, inspect, equal) {
output.inline = true;
var keyInValue = {};
keys.forEach(function (key) {
keyInValue[key] = true;
});
var subjectIsArrayLike = subjectType.is('array-like');
subjectType.prefix(output, subject);
output.nl().indentLines();
subjectKeys.forEach(function (key, index) {
var propertyOutput = subjectType.property(output.clone(), key, inspect(subjectType.valueForKey(subject, key)), subjectIsArrayLike);
var delimiterOutput = subjectType.delimiter(output.clone(), index, subjectKeys.length);
output.i().block(function () {
this.append(propertyOutput).amend(delimiterOutput);
if (!keyInValue[key]) {
this.sp().annotationBlock(function () {
this.error('should be removed');
});
}
}).nl();
});
output.outdentLines();
subjectType.suffix(output, subject);
return output;
}
});
});
} else {
expect(hasKeys, '[not] to be truthy');
}
});
expect.addAssertion('<object> [not] to be empty', function (expect, subject) {
if (expect.flags.not && !expect.findTypeOf(subject).getKeys(subject).length) {
return expect.fail();
}
expect(subject, 'to [not] only have keys', []);
});
expect.addAssertion('<object> not to have keys <array>', function (expect, subject, keys) {
expect(subject, 'to not have keys', keys);
});
expect.addAssertion('<object> not to have key <string>', function (expect, subject, value) {
expect(subject, 'to not have keys', [value]);
});
expect.addAssertion('<object> not to have keys <string+>', function (expect, subject, value) {
expect(subject, 'to not have keys', Array.prototype.slice.call(arguments, 2));
});
expect.addAssertion('<object> to [not] [only] have key <string>', function (expect, subject, value) {
expect(subject, 'to [not] [only] have keys', [value]);
});
expect.addAssertion('<object> to [not] [only] have keys <string+>', function (expect, subject) {
expect(subject, 'to [not] [only] have keys', Array.prototype.slice.call(arguments, 2));
});
expect.addAssertion('<string> [not] to contain <string+>', function (expect, subject) {
var args = Array.prototype.slice.call(arguments, 2);
args.forEach(function (arg) {
if (arg === '') {
throw new Error('The \'' + expect.testDescription + '\' assertion does not support the empty string');
}
});
expect.withError(function () {
args.forEach(function (arg) {
expect(subject.indexOf(arg) !== -1, '[not] to be truthy');
});
}, function (e) {
expect.fail({
diff: function diff(output) {
output.inline = false;
var lastIndex = 0;
function flushUntilIndex(i) {
if (i > lastIndex) {
output.text(subject.substring(lastIndex, i));
lastIndex = i;
}
}
if (expect.flags.not) {
subject.replace(new RegExp(args.map(function (arg) {
return utils.escapeRegExpMetaChars(arg);
}).join('|'), 'g'), function ($0, index) {
flushUntilIndex(index);
lastIndex += $0.length;
output.removedHighlight($0);
});
flushUntilIndex(subject.length);
} else {
var ranges = [];
args.forEach(function (arg) {
var needle = arg;
var partial = false;
while (needle.length > 1) {
var found = false;
lastIndex = -1;
var index = void 0;
do {
index = subject.indexOf(needle, lastIndex + 1);
if (index !== -1) {
found = true;
ranges.push({
startIndex: index,
endIndex: index + needle.length,
partial: partial
});
}
lastIndex = index;
} while (lastIndex !== -1);
if (found) {
break;
}
needle = arg.substr(0, needle.length - 1);
partial = true;
}
});
lastIndex = 0;
ranges.sort(function (a, b) {
return a.startIndex - b.startIndex;
}).forEach(function (_ref) {
var startIndex = _ref.startIndex,
endIndex = _ref.endIndex,
partial = _ref.partial;
flushUntilIndex(startIndex);
var firstUncoveredIndex = Math.max(startIndex, lastIndex);
if (endIndex > firstUncoveredIndex) {
if (partial) {
output.partialMatch(subject.substring(firstUncoveredIndex, endIndex));
} else {
output.match(subject.substring(firstUncoveredIndex, endIndex));
}
lastIndex = endIndex;
}
});
flushUntilIndex(subject.length);
}
return output;
}
});
});
});
expect.addAssertion('<array-like> [not] to contain <any+>', function (expect, subject) {
var args = Array.prototype.slice.call(arguments, 2);
expect.withError(function () {
args.forEach(function (arg) {
expect(subject && Array.prototype.some.call(subject, function (item) {
return expect.equal(item, arg);
}), '[not] to be truthy');
});
}, function (e) {
expect.fail({
diff: expect.flags.not && function (output, diff, inspect, equal) {
return diff(subject, Array.prototype.filter.call(subject, function (item) {
return !args.some(function (arg) {
return equal(item, arg);
});
}));
}
});
});
});
expect.addAssertion(['<string> [not] to begin with <string>', '<string> [not] to start with <string>'], function (expect, subject, value) {
if (value === '') {
throw new Error('The \'' + expect.testDescription + '\' assertion does not support a prefix of the empty string');
}
var isTruncated = false;
var outputSubject = utils.truncateSubjectStringForBegin(subject, value);
if (outputSubject === null) {
outputSubject = subject;
} else {
isTruncated = true;
}
expect.subjectOutput = function (output) {
output = output.jsString("'" + outputSubject.replace(/\n/g, '\\n') + "'");
if (isTruncated) {
output.jsComment('...');
}
};
expect.withError(function () {
expect(subject.substr(0, value.length), '[not] to equal', value);
}, function (err) {
expect.fail({
diff: function diff(output) {
output.inline = false;
if (expect.flags.not) {
output.removedHighlight(value).text(subject.substr(value.length));
} else {
var i = 0;
while (subject[i] === value[i]) {
i += 1;
}
if (i === 0) {
// No common prefix, omit diff
return null;
} else {
output.partialMatch(subject.substr(0, i)).text(outputSubject.substr(i)).jsComment(isTruncated ? '...' : '');
}
}
return output;
}
});
});
});
expect.addAssertion('<string> [not] to end with <string>', function (expect, subject, value) {
if (value === '') {
throw new Error('The \'' + expect.testDescription + '\' assertion does not support a suffix of the empty string');
}
var isTruncated = false;
var outputSubject = utils.truncateSubjectStringForEnd(subject, value);
if (outputSubject === null) {
outputSubject = subject;
} else {
isTruncated = true;
}
expect.subjectOutput = function (output) {
if (isTruncated) {
output = output.jsComment('...');
}
output.jsString("'" + outputSubject.replace(/\n/g, '\\n') + "'");
};
expect.withError(function () {
expect(subject.substr(-value.length), '[not] to equal', value);
}, function (err) {
expect.fail({
diff: function diff(output) {
output.inline = false;
if (expect.flags.not) {
output.text(subject.substr(0, subject.length - value.length)).removedHighlight(value);
} else {
var i = 0;
while (outputSubject[outputSubject.length - 1 - i] === value[value.length - 1 - i]) {
i += 1;
}
if (i === 0) {
// No common suffix, omit diff
return null;
}
output.jsComment(isTruncated ? '...' : '').text(outputSubject.substr(0, outputSubject.length - i)).partialMatch(outputSubject.substr(outputSubject.length - i, outputSubject.length));
}
return output;
}
});
});
});
expect.addAssertion('<number> [not] to be finite', function (expect, subject) {
expect(isFinite(subject), '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be infinite', function (expect, subject) {
expect(!isNaN(subject) && !isFinite(subject), '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be within <number> <number>', function (expect, subject, start, finish) {
expect.argsOutput = function (output) {
output.appendInspected(start).text('..').appendInspected(finish);
};
expect(subject >= start && subject <= finish, '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be within <string> <string>', function (expect, subject, start, finish) {
expect.argsOutput = function (output) {
output.appendInspected(start).text('..').appendInspected(finish);
};
expect(subject >= start && subject <= finish, '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be (less than|below) <number>', function (expect, subject, value) {
expect(subject < value, '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be (less than|below) <string>', function (expect, subject, value) {
expect(subject < value, '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be less than or equal to <number>', function (expect, subject, value) {
expect(subject <= value, '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be less than or equal to <string>', function (expect, subject, value) {
expect(subject <= value, '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be (greater than|above) <number>', function (expect, subject, value) {
expect(subject > value, '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be (greater than|above) <string>', function (expect, subject, value) {
expect(subject > value, '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be greater than or equal to <number>', function (expect, subject, value) {
expect(subject >= value, '[not] to be truthy');
});
expect.addAssertion('<string> [not] to be greater than or equal to <string>', function (expect, subject, value) {
expect(subject >= value, '[not] to be truthy');
});
expect.addAssertion('<number> [not] to be positive', function (expect, subject) {
expect(subject, '[not] to be greater than', 0);
});
expect.addAssertion('<number> [not] to be negative', function (expect, subject) {
expect(subject, '[not] to be less than', 0);
});
expect.addAssertion('<any> to equal <any>', function (expect, subject, value) {
expect.withError(function () {
expect(expect.equal(value, subject), 'to be truthy');
}, function (e) {
expect.fail({
label: 'should equal',
diff: function diff(output, _diff2) {
return _diff2(subject, value);
}
});
});
});
expect.addAssertion('<any> not to equal <any>', function (expect, subject, value) {
expect(expect.equal(value, subject), 'to be falsy');
});
expect.addAssertion('<function> to error', function (expect, subject) {
return expect.promise(function () {
return subject();
}).then(function () {
expect.fail();
}, function (error) {
return error;
});
});
expect.addAssertion('<function> to error [with] <any>', function (expect, subject, arg) {
return expect(subject, 'to error').then(function (error) {
expect.errorMode = 'nested';
return expect.withError(function () {
if (error.isUnexpected && (typeof arg === 'string' || isRegExp(arg))) {
return expect(error, 'to have message', arg);
} else {
return expect(error, 'to satisfy', arg);
}
}, function (e) {
e.originalError = error;
throw e;
});
});
});
expect.addAssertion('<function> not to error', function (expect, subject) {
var threw = false;
return expect.promise(function () {
try {
return subject();
} catch (e) {
threw = true;
throw e;
}
}).caught(function (error) {
expect.errorMode = 'nested';
expect.fail({
output: function output(_output) {
_output.error(threw ? 'threw' : 'returned promise rejected with').error(': ').appendErrorMessage(error);
},
originalError: error
});
});
});
expect.addAssertion('<function> not to throw', function (expect, subject) {
var threw = false;
var error = void 0;
try {
subject();
} catch (e) {
error = e;
threw = true;
}
if (threw) {
expect.errorMode = 'nested';
expect.fail({
output: function output(_output2) {
_output2.error('threw: ').appendErrorMessage(error);
},
originalError: error
});
}
});
expect.addAssertion('<function> to (throw|throw error|throw exception)', function (expect, subject) {
try {
subject();
} catch (e) {
return e;
}
expect.errorMode = 'nested';
expect.fail('did not throw');
});
expect.addAssertion('<function> to throw (a|an) <function>', function (expect, subject, value) {
var constructorName = utils.getFunctionName(value);
if (constructorName) {
expect.argsOutput[0] = function (output) {
output.jsFunctionName(constructorName);
};
}
expect.errorMode = 'nested';
return expect(subject, 'to throw').then(function (error) {
expect(error, 'to be a', value);
});
});
expect.addAssertion('<function> to (throw|throw error|throw exception) <any>', function (expect, subject, arg) {
expect.errorMode = 'nested';
return expect(subject, 'to throw').then(function (error) {
var isUnexpected = error && error._isUnexpected;
// in the presence of a matcher an error must have been thrown.
expect.errorMode = 'nested';
return expect.withError(function () {
if (isUnexpected && (typeof arg === 'string' || isRegExp(arg))) {
return expect(error.getErrorMessage('text').toString(), 'to satisfy', arg);
} else {
return expect(error, 'to satisfy', arg);
}
}, function (err) {
err.originalError = error;
throw err;
});
});
});
expect.addAssertion('<function> to have arity <number>', function (expect, _ref2, value) {
var length = _ref2.length;
expect(length, 'to equal', value);
});
expect.addAssertion(['<object> to have values [exhaustively] satisfying <any>', '<object> to have values [exhaustively] satisfying <assertion>', '<object> to be (a map|a hash|an object) whose values [exhaustively] satisfy <any>', '<object> to be (a map|a hash|an object) whose values [exhaustively] satisfy <assertion>'], function (expect, subject, nextArg) {
expect.errorMode = 'nested';
expect(subject, 'not to be empty');
expect.errorMode = 'bubble';
var keys = expect.subjectType.getKeys(subject);
var expected = {};
keys.forEach(function (key, index) {
if (typeof nextArg === 'string') {
expected[key] = function (s) {
return expect.shift(s);
};
} else if (typeof nextArg === 'function') {
expected[key] = function (s) {
return nextArg._expectIt ? nextArg(s, expect.context) : nextArg(s, index);
};
} else {
expected[key] = nextArg;
}
});
return expect.withError(function () {
return expect(subject, 'to [exhaustively] satisfy', expected);
}, function (err) {
expect.fail({
message: function message(output) {
output.append(expect.standardErrorMessage(output.clone(), {
compact: err && err._isUnexpected && err.hasDiff()
}));
},
diff: function diff(output) {
var diff = err.getDiff({ output: output });
diff.inline = true;
return diff;
}
});
});
});
expect.addAssertion(['<array-like> to have items [exhaustively] satisfying <any>', '<array-like> to have items [exhaustively] satisfying <assertion>', '<array-like> to be an array whose items [exhaustively] satisfy <any>', '<array-like> to be an array whose items [exhaustively] satisfy <assertion>'], function (expect, subject) {
for (var _len = arguments.length, rest = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
rest[_key - 2] = arguments[_key];
}
// ...
expect.errorMode = 'nested';
expect(subject, 'not to be empty');
expect.errorMode = 'bubble';
return expect.withError(function () {
return expect.apply(undefined, [subject, 'to have values [exhaustively] satisfying'].concat(rest));
}, function (err) {
expect.fail({
message: function message(output) {
output.append(expect.standardErrorMessage(output.clone(), {
compact: err && err._isUnexpected && err.hasDiff()
}));
},
diff: function diff(output) {
var diff = err.getDiff({ output: output });
diff.inline = true;
return diff;
}
});
});
});
expect.addAssertion(['<object> to have keys satisfying <any>', '<object> to have keys satisfying <assertion>', '<object> to be (a map|a hash|an object) whose (keys|properties) satisfy <any>', '<object> to be (a map|a hash|an object) whose (keys|properties) satisfy <assertion>'], function (expect, subject) {
for (var _len2 = arguments.length, rest = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
rest[_key2 - 2] = arguments[_key2];
}
expect.errorMode = 'nested';
expect(subject, 'not to be empty');
expect.errorMode = 'default';
var keys = expect.subjectType.getKeys(subject);
return expect.apply(undefined, [keys, 'to have items satisfying'].concat(rest));
});
expect.addAssertion(['<object> [not] to have a value [exhaustively] satisfying <any>', '<object> [not] to have a value [exhaustively] satisfying <assertion>'], function (expect, subject, nextArg) {
expect.errorMode = 'nested';
expect(subject, 'not to be empty');
expect.errorMode = 'bubble';
var subjectType = expect.findTypeOf(subject);
var keys = subjectType.getKeys(subject);
var not = !!expect.flags.not;
var keyResults = new Array(keys.length);
expect.withError(function () {
return expect.promise[not ? 'all' : 'any'](keys.map(function (key, index) {
var expected = void 0;
if (typeof nextArg === 'string') {
expected = function expected(s) {
return expect.shift(s);
};
} else if (typeof nextArg === 'function') {
expected = function expected(s) {
return nextArg(s, index);
};
} else {
expected = nextArg;
}
keyResults[key] = expect.promise(function () {
return expect(subjectType.valueForKey(subject, key), '[not] to [exhaustively] satisfy', expected);
});
return keyResults[key];
}));
}, function (err) {
expect.fail({
message: function message(output) {
output.append(expect.standardErrorMessage(output.clone(), {
compact: err && err._isUnexpected && err.hasDiff()
}));
},
diff: expect.flags.not && function (output, diff, inspect, equal) {
var expectedObject = subjectType.is('array-like') ? [] : {};
keys.forEach(function (key) {
if (keyResults[key].isFulfilled()) {
expectedObject[key] = subjectType.valueForKey(subject, key);
}
});
return diff(subject, expectedObject);
}
});
});
});
expect.addAssertion(['<array-like> [not] to have an item [exhaustively] satisfying <any>', '<array-like> [not] to have an item [exhaustively] satisfying <assertion>'], function (expect, subject) {
for (var _len3 = arguments.length, rest = Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) {
rest[_key3 - 2] = arguments[_key3];
}
expect.errorMode = 'nested';
expect(subject, 'not to be empty');
expect.errorMode = 'default';
return expect.apply(undefined, [subject, '[not] to have a value [exhaustively] satisfying'].concat(rest));
});
expect.addAssertion('<object> to be canonical', function (expect, subject) {
var stack = [];
(function traverse(obj) {
var i = void 0;
for (i = 0; i < stack.length; i += 1) {
if (stack[i] === obj) {
return;
}
}
if (obj && (typeof obj === 'undefined' ? 'undefined' : (0, _typeof3.default)(obj)) === 'object') {
var keys = Object.keys(obj);
for (i = 0; i < keys.length - 1; i += 1) {
expect(keys[i], 'to be less than', keys[i + 1]);
}
stack.push(obj);
keys.forEach(function (key) {
traverse(obj[key]);
});
stack.pop();
}
})(subject);
});
expect.addAssertion('<Error> to have message <any>', function (expect, subject, value) {
expect.errorMode = 'nested';
return expect(subject.isUnexpected ? subject.getErrorMessage('text').toString() : subject.message, 'to satisfy', value);
});
expect.addAssertion('<Error> to [exhaustively] satisfy <Error>', function (expect, subject, value) {
expect(subject.constructor, 'to be', value.constructor);
var unwrappedValue = expect.argTypes[0].unwrap(value);
return expect.withError(function () {
return expect(subject, 'to [exhaustively] satisfy', unwrappedValue);
}, function (e) {
expect.fail({
diff: function diff(output, _diff3) {
output.inline = false;
var unwrappedSubject = expect.subjectType.unwrap(subject);
return utils.wrapConstructorNameAroundOutput(_diff3(unwrappedSubject, unwrappedValue), subject);
}
});
});
});
expect.addAssertion('<Error> to [exhaustively] satisfy <object>', function (expect, subject, value) {
var valueType = expect.argTypes[0];
var subjectKeys = expect.subjectType.getKeys(subject);
var valueKeys = valueType.getKeys(value);
var convertedSubject = {};
subjectKeys.concat(valueKeys).forEach(function (key) {
convertedSubject[key] = subject[key];
});
return expect(convertedSubject, 'to [exhaustively] satisfy', value);
});
expect.addAssertion('<Error> to [exhaustively] satisfy <regexp|string>', function (expect, _ref3, value) {
var message = _ref3.message;
return expect(message, 'to [exhaustively] satisfy', value);
});
expect.addAssertion('<Error> to [exhaustively] satisfy <any>', function (expect, _ref4, value) {
var message = _ref4.message;
return expect(message, 'to [exhaustively] satisfy', value);
});
expect.addAssertion('<binaryArray> to [exhaustively] satisfy <expect.it>', function (expect, subject, value) {
return expect.withError(function () {
return value(subject, expect.context);
}, function (e) {
expect.fail({
diff: function diff(output, _diff4, inspect, equal) {
output.inline = false;
return output.appendErrorMessage(e);
}
});
});
});
expect.addAssertion('<UnexpectedError> to [exhaustively] satisfy <function>', function (expect, subject, value) {
return expect.promise(function () {
subject.serializeMessage(expect.outputFormat());
return value(subject);
});
});
expect.addAssertion('<any|Error> to [exhaustively] satisfy <function>', function (expect, subject, value) {
return expect.promise(function () {
return value(subject);
});
});
if (typeof Buffer !== 'undefined') {
expect.addAssertion('<Buffer> [when] decoded as <string> <assertion?>', function (expect, subject, value) {
return expect.shift(subject.toString(value));
});
}
expect.addAssertion('<any> not to [exhaustively] satisfy [assertion] <any>', function (expect, subject, value) {
return expect.promise(function (resolve, reject) {
return expect.promise(function () {
return expect(subject, 'to [exhaustively] satisfy [assertion]', value);
}).then(function () {
try {
expect.fail();
} catch (e) {
reject(e);
}
}).caught(function (e) {
if (!e || !e._isUnexpected) {
reject(e);
} else {
resolve();
}
});
});
});
expect.addAssertion('<any> to [exhaustively] satisfy assertion <any>', function (expect, subject, value) {
expect.errorMode = 'bubble'; // to satisfy assertion 'to be a number' => to be a number
return expect(subject, 'to [exhaustively] satisfy', value);
});
expect.addAssertion('<any> to [exhaustively] satisfy assertion <assertion>', function (expect, subject) {
expect.errorMode = 'bubble'; // to satisfy assertion 'to be a number' => to be a number
return expect.shift();
});
expect.addAssertion('<any> to [exhaustively] satisfy [assertion] <expect.it>', function (expect, subject, value) {
return expect.withError(function () {
return value(subject, expect.context);
}, function (e) {
expect.fail({
diff: function diff(output) {
output.inline = false;
return output.appendErrorMessage(e);
}
});
});
});
expect.addAssertion('<regexp> to [exhaustively] satisfy <regexp>', function (expect, subject, value) {
expect(subject, 'to equal', value);
});
expect.addAssertion('<string> to [exhaustively] satisfy <regexp>', function (expect, subject, value) {
expect.errorMode = 'bubble';
return expect(subject, 'to match', value);
});
expect.addAssertion('<function> to [exhaustively] satisfy <function>', function (expect, subject, value) {
expect.errorMode = 'bubble';
expect(subject, 'to equal', value);
});
expect.addAssertion('<binaryArray> to [exhaustively] satisfy <binaryArray>', function (expect, subject, value) {
expect.errorMode = 'bubble';
expect(subject, 'to equal', value);
});
expect.addAssertion('<any> to [exhaustively] satisfy <any>', function (expect, subject, value) {
expect.errorMode = 'bubble';
expect(subject, 'to equal', value);
});
expect.addAssertion('<array-like> to [exhaustively] satisfy <array-like>', function (expect, subject, value) {
expect.errorMode = 'bubble';
var subjectType = expect.subjectType;
var subjectKeys = subjectType.getKeys(subject);
var valueType = expect.argTypes[0];
var valueKeys = valueType.getKeys(value).filter(function (key) {
return utils.numericalRegExp.test(key) || (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'symbol' ||
// include keys whose value is not undefined on either LHS or RHS
typeof valueType.valueForKey(value, key) !== 'undefined' || typeof subjectType.valueForKey(subject, key) !== 'undefined';
});
var keyPromises = {};
valueKeys.forEach(function (keyInValue) {
keyPromises[keyInValue] = expect.promise(function () {
var subjectKey = subjectType.valueForKey(subject, keyInValue);
var valueKey = valueType.valueForKey(value, keyInValue);
var valueKeyType = expect.findTypeOf(valueKey);
if (valueKeyType.is('function')) {
return valueKey(subjectKey);
} else {
return expect(subjectKey, 'to [exhaustively] satisfy', valueKey);
}
});
});
return expect.promise.all([expect.promise(function () {
// create subject key presence object
var remainingKeysInSubject = {};
subjectType.getKeys(subject).forEach(function (key) {
remainingKeysInSubject[key] = 1; // present in subject
});
// discard or mark missing each previously seen value key
valueKeys.forEach(function (key) {
if (!remainingKeysInSubject[key]) {
remainingKeysInSubject[key] = 2; // present in value
} else {
delete remainingKeysInSubject[key];
}
});
// filter outstanding keys which should not lead to an error
var outstandingKeys = Object.keys(remainingKeysInSubject).filter(function (key) {
return utils.numericalRegExp.test(key) || (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'symbol' || typeof subjectType.valueForKey(subject, key) !== 'undefined' || remainingKeysInSubject[key] === 2;
});
// key checking succeeds with no outstanding keys
expect(outstandingKeys.length === 0, 'to be truthy');
}), expect.promise.all(keyPromises)]).caught(function () {
var i = 0;
return expect.promise.settle(keyPromises).then(function () {
var toSatisfyMatrix = new Array(subject.length);
for (i = 0; i < subject.length; i += 1) {
toSatisfyMatrix[i] = new Array(value.length);
if (i < value.length) {
toSatisfyMatrix[i][i] = keyPromises[i].isFulfilled() || keyPromises[i].reason();
}
}
if (subject.length > 10 || value.length > 10) {
var indexByIndexChanges = [];
for (i = 0; i < subject.length; i += 1) {
var promise = keyPromises[i];
if (i < value.length) {
indexByIndexChanges.push({
type: promise.isFulfilled() ? 'equal' : 'similar',
value: subject[i],
expected: value[i],
actualIndex: i,
expectedIndex: i,
last: i === Math.max(subject.length, value.length) - 1
});
} else {
indexByIndexChanges.push({
type: 'remove',
value: subject[i],
actualIndex: i,
last: i === subject.length - 1
});
}
}
for (i = subject.length; i < value.length; i += 1) {
indexByIndexChanges.push({
type: 'insert',
value: value[i],
expectedIndex: i
});
}
return failWithChanges(indexByIndexChanges);
}
var isAsync = false;
var subjectElements = utils.duplicateArrayLikeUsingType(subject, subjectType);
var valueElements = utils.duplicateArrayLikeUsingType(value, valueType);
var nonNumericalKeysAndSymbols = !subjectType.numericalPropertiesOnly && utils.uniqueNonNumericalStringsAndSymbols(subjectKeys, valueKeys);
var changes = arrayChanges(subjectElements, valueElements, function equal(a, b, aIndex, bIndex) {
toSatisfyMatrix[aIndex] = toSatisfyMatrix[aIndex] || [];
var existingResult = toSatisfyMatrix[aIndex][bIndex];
if (typeof existingResult !== 'undefined') {
return existingResult === true;
}
var result = void 0;
try {
result = expect(a, 'to [exhaustively] satisfy', b);
} catch (err) {
throwIfNonUnexpectedError(err);
toSatisfyMatrix[aIndex][bIndex] = err;
return false;
}
result.then(function () {}, function () {});
if (result.isPending()) {
isAsync = true;
return false;
}
toSatisfyMatrix[aIndex][bIndex] = true;
return true;
}, function (a, b) {
return subjectType.similar(a, b);
}, {
includeNonNumericalProperties: nonNumericalKeysAndSymbols
});
if (isAsync) {
return expect.promise(function (resolve, reject) {
arrayChangesAsync(subject, value, function equal(a, b, aIndex, bIndex, cb) {
toSatisfyMatrix[aIndex] = toSatisfyMatrix[aIndex] || [];
var existingResult = toSatisfyMatrix[aIndex][bIndex];
if (typeof existingResult !== 'undefined') {
return cb(existingResult === true);
}
expect.promise(function () {
return expect(a, 'to [exhaustively] satisfy', b);
}).then(function () {
toSatisfyMatrix[aIndex][bIndex] = true;
cb(true);
}, function (err) {
toSatisfyMatrix[aIndex][bIndex] = err;
cb(false);
});
}, function (a, b, aIndex, bIndex, cb) {
cb(subjectType.similar(a, b));
}, nonNumericalKeysAndSymbols, resolve);
}).then(failWithChanges);
} else {
return failWithChanges(changes);
}
function failWithChanges(changes) {
expect.errorMode = 'default';
expect.fail({
diff: function diff(output, _diff5, inspect, equal) {
output.inline = true;
var indexOfLastNonInsert = changes.reduce(function (previousValue, _ref5, index) {
var type = _ref5.type;
return type === 'insert' ? previousValue : index;
}, -1);
var prefixOutput = subjectType.prefix(output.clone(), subject);
output.append(prefixOutput).nl(prefixOutput.isEmpty() ? 0 : 1);
if (subjectType.indent) {
output.indentLines();
}
var packing = utils.packArrows(changes); // NOTE: Will have side effects in changes if the packing results in too many arrow lanes
output.arrowsAlongsideChangeOutputs(packing, changes.map(function (diffItem, index) {
var delimiterOutput = subjectType.delimiter(output.clone(), index, indexOfLastNonInsert + 1);
var type = diffItem.type;
if (type === 'moveTarget') {
return output.clone();
} else {
return output.clone().block(function () {
if (type === 'moveSource') {
var propertyOutput = subjectType.property(output.clone(), diffItem.actualIndex, inspect(diffItem.value), true);
this.append(propertyOutput).amend(delimiterOutput).sp().error('// should be moved');
} else if (type === 'insert') {
this.annotationBlock(function () {
if (expect.findTypeOf(diffItem.value).is('function')) {
this.error('missing: ').block(function () {
this.omitSubject = undefined;
var promise = keyPromises[diffItem.expectedIndex];
if (promise.isRejected()) {
this.appendErrorMessage(promise.reason());
} else {
this.appendInspected(diffItem.value);
}
});
} else {
var _index = typeof diffItem.actualIndex !== 'undefined' ? diffItem.actualIndex : diffItem.expectedIndex;
var _propertyOutput = subjectType.property(output.clone(), _index, inspect(diffItem.value), true);
this.error('missing ').append(_propertyOutput);
}
});
} else {
var _propertyOutput2 = subjectType.property(output.clone(), diffItem.actualIndex, inspect(diffItem.value), true);
this.block(function () {
if (type === 'remove') {
this.append(_propertyOutput2).amend(delimiterOutput).sp().error('// should be removed');
} else if (type === 'equal') {
this.append(_propertyOutput2).amend(delimiterOutput);
} else {
var toSatisfyResult = toSatisfyMatrix[diffItem.actualIndex][diffItem.expectedIndex];
var valueDiff = toSatisfyResult && toSatisfyResult !== true && toSatisfyResult.getDiff({
output: output.clone()
});
if (valueDiff && valueDiff.inline) {
this.append(valueDiff).amend(delimiterOutput);
} else {
this.append(_propertyOutput2).amend(delimiterOutput).sp().annotationBlock(function () {
this.omitSubject = diffItem.value;
var label = toSatisfyResult.getLabel();
if (label) {
this.error(label).sp().block(inspect(diffItem.expected));
if (valueDiff) {
this.nl(2).append(valueDi