New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

unexpected

Package Overview
Dependencies
Maintainers
2
Versions
330
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unexpected - npm Package Compare versions

Comparing version 5.0.0-beta2 to 5.0.0-beta20

lib/styles.js

32

Development.md

@@ -14,20 +14,16 @@ # Development

* *src/unexpected-license.js*:<br>
The license file
* *src/unexpected-namespace.js*:<br>
The internal namespace definition
* *src/unexpected-es4-compatible.js*:<br>
ES5 functions shimmed to work in a ES4 compatible environment
* *src/unexpected-utils.js*:<br>
* *lib/index.js*:<br>
The entry point for the library.
* *lib/Unexpected.js*:<br>
The core of the library.
* *lib/Assertion.js*:<br>
The class that assertions are instantiated from.
* *lib/utils.js*:<br>
Utility functions
* *src/unexpected-equal.js*:<br>
Deep-equality
* *src/unexpected-inspect.js*:<br>
Object inspect
* *src/unexpected-core.js*:<br>
The core part of Unexpected
* *src/unexpected-assertions.js*:<br>
The core assertions provided by Unexpected
* *src/unexpected-module.js*:<br>
The module definitions
* *lib/styles.js*:<br>
MagicPen styles for controling the output.
* *lib/types.js*:<br>
Type definitions for every type Unexpected understands.
* *lib/assertions.js*:<br>
All assertions that is included in the core library.

@@ -38,3 +34,3 @@ ## Running tests in the console

make test
make test-production
make test-phantomjs
```

@@ -41,0 +37,0 @@

function Assertion(expect, subject, testDescription, flags, alternations, args) {
this.expect = expect;
this.obj = subject; // deprecated
this.equal = expect.equal.bind(expect); // deprecated
this.eql = this.equal; // deprecated
this.inspect = expect.inspect.bind(expect); // deprecated
this.subject = subject;

@@ -27,5 +23,12 @@ this.testDescription = testDescription;

if (0 < index) {
argsOutput.text(', ');
if (index !== this.assertionIndex && index - 1 !== this.assertionIndex) {
argsOutput.text(',');
}
argsOutput.text(' ');
}
argsOutput.append(expect.inspect(arg));
if (index === this.assertionIndex) {
argsOutput.text(arg);
} else {
argsOutput.append(expect.inspect(arg));
}
}, this);

@@ -68,2 +71,7 @@ }

Assertion.prototype.shift = function (expect, subject, assertionIndex) {
this.assertionIndex = assertionIndex;
expect.apply(expect, [subject].concat(this.args.slice(assertionIndex)));
};
Assertion.prototype.throwStandardError = function () {

@@ -76,10 +84,2 @@ var err = new Error();

Assertion.prototype.assert = function (condition) {
var not = !!this.flags.not;
condition = !!condition;
if (condition === not) {
this.throwStandardError();
}
};
module.exports = Assertion;

@@ -8,3 +8,7 @@ var utils = require('./utils');

expect.addAssertion('[not] to be (ok|truthy)', function (expect, subject) {
this.assert(subject);
var not = !!this.flags.not;
var condition = !!subject;
if (condition === not) {
expect.fail();
}
});

@@ -66,8 +70,5 @@

if ('string' === typeof type) {
// typeof with support for 'array'
expect('array' === type ? isArray(subject) :
'object' === type ? 'object' === typeof subject && null !== subject :
/^reg(?:exp?|ular expression)$/.test(type) ? isRegExp(subject) :
type === typeof subject,
'[not] to be true');
var subjectType = expect.findTypeOf(subject);
type = /^reg(?:exp?|ular expression)$/.test(type) ? 'regexp' : type;
expect(subjectType.is(type), '[not] to be true');
} else {

@@ -85,3 +86,3 @@ expect(subject instanceof type, '[not] to be true');

expect.addAssertion(['string', 'array', 'object'], 'to be (the empty|an empty|a non-empty) (string|array|object)', function (expect, subject) {
expect.addAssertion(['string', 'arrayLike'], 'to be (the empty|an empty|a non-empty) (string|array)', function (expect, subject) {
expect(subject, 'to be a', this.alternations[1]);

@@ -92,23 +93,26 @@ expect(subject, this.alternations[0] === 'a non-empty' ? 'not to be empty' : 'to be empty');

expect.addAssertion('[not] to match', function (expect, subject, regexp) {
subject = String(subject);
try {
expect(String(subject).match(regexp), '[not] to be truthy');
} catch (e) {
if (e._isUnexpected && this.flags.not) {
e.createDiff = function () {
var output = expect.output.clone();
var lastIndex = 0;
function flushUntilIndex(i) {
if (i > lastIndex) {
output.text(subject.substring(lastIndex, i));
lastIndex = i;
if (e._isUnexpected) {
e.label = 'should match';
if (this.flags.not) {
e.createDiff = function (output) {
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.diffRemovedHighlight($0);
});
flushUntilIndex(subject.length);
return {diff: output};
};
subject.replace(new RegExp(regexp.source, 'g'), function ($0, index) {
flushUntilIndex(index);
lastIndex += $0.length;
output.diffRemovedHighlight($0);
});
flushUntilIndex(subject.length);
return {diff: output};
};
}
}

@@ -155,3 +159,3 @@ expect.fail(e);

if (e._isUnexpected) {
e.createDiff = function () {
e.createDiff = function (output, diff) {
var expected = extend({}, properties);

@@ -167,3 +171,3 @@ var actual = {};

}
return expect.diff(actual, expected);
return diff(actual, expected);
};

@@ -198,3 +202,3 @@ }

expect.addAssertion(['string', 'object'], 'to be non-empty', function (expect, subject) {
expect.addAssertion(['string', 'arrayLike'], 'to be non-empty', function (expect, subject) {
expect(subject, 'not to be empty');

@@ -219,52 +223,50 @@ });

expect.addAssertion(['string', 'array'], '[not] to contain', function (expect, subject) {
expect.addAssertion('string', '[not] to contain', function (expect, subject) {
var args = Array.prototype.slice.call(arguments, 2);
try {
args.forEach(function (arg) {
expect(subject.indexOf(arg) !== -1, '[not] to be truthy');
});
} catch (e) {
if (e._isUnexpected && this.flags.not) {
e.createDiff = function (output) {
var lastIndex = 0;
function flushUntilIndex(i) {
if (i > lastIndex) {
output.text(subject.substring(lastIndex, i));
lastIndex = i;
}
}
subject.replace(new RegExp(args.map(function (arg) {
return utils.escapeRegExpMetaChars(String(arg));
}).join('|'), 'g'), function ($0, index) {
flushUntilIndex(index);
lastIndex += $0.length;
output.diffRemovedHighlight($0);
});
flushUntilIndex(subject.length);
return {diff: output};
};
}
expect.fail(e);
}
});
if ('string' === typeof subject) {
try {
args.forEach(function (arg) {
expect(subject.indexOf(arg) !== -1, '[not] to be truthy');
});
} catch (e) {
if (e._isUnexpected && this.flags.not) {
e.createDiff = function () {
var output = expect.output.clone();
var lastIndex = 0;
function flushUntilIndex(i) {
if (i > lastIndex) {
output.text(subject.substring(lastIndex, i));
lastIndex = i;
}
}
subject.replace(new RegExp(args.map(function (arg) {
return utils.escapeRegExpMetaChars(String(arg));
}).join('|'), 'g'), function ($0, index) {
flushUntilIndex(index);
lastIndex += $0.length;
output.diffRemovedHighlight($0);
expect.addAssertion('arrayLike', '[not] to contain', function (expect, subject) {
var args = Array.prototype.slice.call(arguments, 2);
try {
args.forEach(function (arg) {
expect(subject && Array.prototype.some.call(subject, function (item) { return expect.equal(item, arg); }), '[not] to be truthy');
});
} catch (e) {
if (e._isUnexpected && this.flags.not) {
e.createDiff = function (output, diff, inspect, equal) {
return diff(subject, Array.prototype.filter.call(subject, function (item) {
return !args.some(function (arg) {
return equal(item, arg);
});
flushUntilIndex(subject.length);
return {diff: output};
};
}
expect.fail(e);
}));
};
}
} else {
// array
try {
args.forEach(function (arg) {
expect(subject && subject.some(function (item) { return expect.equal(item, arg); }), '[not] to be truthy');
});
} catch (e) {
if (e._isUnexpected && this.flags.not) {
e.createDiff = function () {
return expect.diff(subject, subject.filter(function (item) {
return !args.some(function (arg) {
return expect.equal(item, arg);
});
}));
};
}
expect.fail(e);
}
expect.fail(e);
}

@@ -314,6 +316,9 @@ });

} catch (e) {
if (!this.flags.not && e._isUnexpected) {
e.createDiff = function () {
return expect.diff(subject, value);
};
if (e._isUnexpected) {
e.label = 'should equal';
if (!this.flags.not) {
e.createDiff = function (output, diff) {
return diff(subject, value);
};
}
}

@@ -367,2 +372,6 @@ expect.fail(e);

expect.addAssertion('function', 'to have arity', function (expect, subject, value) {
expect(subject.length, 'to equal', value);
});
expect.addAssertion('object', 'to be (a|an) [non-empty] (map|hash|object) whose values satisfy', function (expect, subject) {

@@ -376,3 +385,3 @@ var extraArgs = Array.prototype.slice.call(arguments, 2);

if (this.flags['non-empty']) {
expect(subject, 'to be non-empty');
expect(subject, 'not to equal', {});
}

@@ -382,3 +391,3 @@ this.errorMode = 'bubble';

var errors = {};
Object.keys(subject).forEach(function (key, index) {
expect.findTypeOf(subject).getKeys(subject).forEach(function (key, index) {
try {

@@ -393,3 +402,3 @@ if (typeof extraArgs[0] === 'function') {

}
});
}, this);

@@ -427,3 +436,3 @@ var errorKeys = Object.keys(errors);

expect.addAssertion('array', 'to be (a|an) [non-empty] array whose items satisfy', function (expect, subject) { // ...
expect.addAssertion('arrayLike', 'to be (a|an) [non-empty] array whose items satisfy', function (expect, subject) { // ...
var extraArgs = Array.prototype.slice.call(arguments, 2);

@@ -434,3 +443,2 @@ if (extraArgs.length === 0) {

this.errorMode = 'nested';
expect(subject, 'to be an array');
if (this.flags['non-empty']) {

@@ -443,3 +451,3 @@ expect(subject, 'to be non-empty');

expect.addAssertion('array', 'to be (a|an) [non-empty] array of (strings|numbers|booleans|arrays|objects|functions|regexps|regexes|regular expressions)', function (expect, subject) {
expect.addAssertion('arrayLike', 'to be (a|an) [non-empty] array of (strings|numbers|booleans|arrays|objects|functions|regexps|regexes|regular expressions)', function (expect, subject) {
if (this.flags['non-empty']) {

@@ -460,3 +468,3 @@ expect(subject, 'to be non-empty');

if (this.flags['non-empty']) {
expect(subject, 'to be non-empty');
expect(subject, 'not to equal', {});
}

@@ -527,2 +535,21 @@ this.errorMode = 'bubble';

expect.addAssertion('Error', 'to [exhaustively] satisfy [assertion]', function (expect, subject, value) {
var valueType = expect.findTypeOf(value);
if (valueType.is('Error')) {
expect(subject, 'to equal', value);
} else if (valueType.is('object')) {
var keys = valueType.getKeys(value);
keys.forEach(function (key) {
expect(subject[key], 'to [exhaustively] satisfy', value[key]);
});
if (this.flags.exhaustively) {
expect(utils.getKeysOfDefinedProperties(subject), 'to have length', keys.filter(function (key) {
return typeof value[key] !== 'undefined';
}).length);
}
} else {
expect(subject.message, 'to [exhaustively] satisfy', value);
}
});
expect.addAssertion('[not] to [exhaustively] satisfy [assertion]', function (expect, subject, value) {

@@ -542,4 +569,17 @@ if (this.flags.not) {

expect.apply(expect, Array.prototype.slice.call(arguments, 1));
} else if (value && value._expectIt) {
try {
value(subject);
} catch (e) {
if (e._isUnexpected) {
e.createDiff = function (output, diff, inspect, equal) {
return {
diff: output.append(e.output),
inline: false
};
};
}
expect.fail(e);
}
} else if (typeof value === 'function') {
// FIXME: If expect.fn, it should be possible to produce a better error message
value(subject);

@@ -550,9 +590,98 @@ } else if (isRegExp(value)) {

var type = expect.findTypeOf(subject, value);
if (type.name === 'object' || type.name === 'array') {
expect(subject, 'to be an object');
Object.keys(value).forEach(function (key) {
expect(subject[key], 'to [exhaustively] satisfy', value[key]);
});
if (this.flags.exhaustively) {
expect(subject, 'to only have keys', Object.keys(value));
if (type.is('arrayLike') || type.is('object')) {
try {
expect(subject, 'to be an object');
var keys = type.getKeys(value);
keys.forEach(function (key) {
expect(subject[key], 'to [exhaustively] satisfy', value[key]);
});
if (this.flags.exhaustively) {
expect(subject, 'to only have keys', keys);
}
} catch (e) {
if (e._isUnexpected) {
var flags = this.flags;
e.createDiff = function (output, diff, inspect, equal) {
var result = {
diff: output,
inline: true
};
var keyIndex = {};
Object.keys(subject).concat(Object.keys(value)).forEach(function (key) {
if (!(key in result)) {
keyIndex[key] = key;
}
});
var keys = Object.keys(keyIndex);
output.text('{').nl().indentLines();
keys.forEach(function (key, index) {
output.i().block(function () {
var valueOutput;
var annotation = output.clone();
var conflicting;
try {
expect(subject[key], 'to [exhaustively] satisfy', value[key]);
} catch (e) {
if (!e._isUnexpected) {
expect.fail(e);
}
conflicting = e;
}
var isInlineDiff = false;
if (conflicting) {
if (!(key in value)) {
if (flags.exhaustively) {
annotation.error('should be removed');
}
} else {
var keyDiff = conflicting.createDiff && conflicting.createDiff(output.clone(), diff, inspect, equal);
if (value[key] && value[key]._expectIt) {
annotation.append(keyDiff.diff);
} else if (!keyDiff || (keyDiff && !keyDiff.inline)) {
annotation.error(conflicting.label || 'should satisfy').sp()
.block(inspect(value[key]));
if (keyDiff) {
annotation.nl().append(keyDiff.diff);
}
} else {
isInlineDiff = true;
valueOutput = keyDiff.diff;
}
}
}
var last = index === keys.length - 1;
if (!valueOutput) {
valueOutput = inspect(subject[key], conflicting ? Infinity : 1);
}
if (/^[a-z\$\_][a-z0-9\$\_]*$/i.test(key)) {
this.key(key);
} else {
this.append(inspect(key));
}
this.text(':').sp();
valueOutput.text(last ? '' : ',');
if (isInlineDiff) {
this.append(valueOutput);
} else {
this.block(valueOutput);
}
if (!annotation.isEmpty()) {
this.sp().annotationBlock(annotation);
}
}).nl();
});
output.outdentLines().text('}');
return result;
};
}
expect.fail(e);
}

@@ -564,2 +693,46 @@ } else {

});
function wrapDiffWithTypePrefixAndSuffix(e, type) {
if (e._isUnexpected) {
var createDiff = e.createDiff;
e.createDiff = function (output) { // ...
type.prefix.call(e, output);
var result = createDiff.apply(this, arguments);
type.suffix.call(e, output);
return result;
};
}
return e;
}
expect.addAssertion('wrapperObject', 'to [exhaustively] satisfy', function (expect, subject, value) {
var valueType = expect.findTypeOf(value);
if (valueType.is('wrapperObject')) {
var type = expect.findTypeOf(subject, value);
expect(type.is('wrapperObject'), 'to be true');
try {
expect(type.unwrap(subject), 'to [exhaustively] satisfy', type.unwrap(value));
} catch (e) {
expect.fail(wrapDiffWithTypePrefixAndSuffix(e, type));
}
} else {
var subjectType = expect.findTypeOf(subject);
expect(subjectType.is('wrapperObject'), 'to be true');
try {
expect(subjectType.unwrap(subject), 'to [exhaustively] satisfy', value);
} catch (e) {
e.label = 'should satisfy';
expect.fail(wrapDiffWithTypePrefixAndSuffix(e, subjectType));
}
}
});
expect.addAssertion('function', 'when called with', function (expect, subject, args) { // ...
this.shift(expect, subject.apply(subject, args), 1);
});
expect.addAssertion('array', 'when passed as parameters to', function (expect, subject, fn) { // ...
this.shift(expect, fn.apply(fn, subject), 1);
});
};
var Unexpected = require('./Unexpected');
module.exports = Unexpected.create()
.installPlugin(require('./colors'))
.installPlugin(require('./styles'))
.installPlugin(require('./types'))
.installPlugin(require('./assertions'));

@@ -6,5 +6,48 @@ var utils = require('./utils');

var arrayDiff = require('arraydiff');
var leven = require('leven');
module.exports = function (expect) {
expect.addType({
name: 'wrapperObject',
identify: false,
equal: function (a, b, equal) {
return a === b || equal(this.unwrap(a), this.unwrap(b));
},
inspect: function (value, depth, output, inspect) {
output.append(this.prefix(output.clone()));
output.append(inspect(this.unwrap(value)));
return output.append(this.suffix(output.clone()));
},
diff: function (actual, expected, output, diff, inspect) {
actual = this.unwrap(actual);
expected = this.unwrap(expected);
var comparison = diff(actual, expected);
var prefixOutput = this.prefix(output.clone());
var suffixOutput = this.suffix(output.clone());
if (comparison && comparison.inline) {
return {
inline: true,
diff: output.append(prefixOutput).append(comparison.diff).append(suffixOutput)
};
} else {
return {
inline: true,
diff: output.append(prefixOutput).nl()
.indentLines()
.i().block(function () {
this.append(inspect(actual)).sp().annotationBlock(function () {
this.error('should be ').block(inspect(expected));
if (comparison) {
this.nl().append(comparison.diff);
}
});
}).nl()
.outdentLines()
.append(suffixOutput)
};
}
}
});
expect.addType({
name: 'object',

@@ -14,2 +57,3 @@ identify: function (obj) {

},
getKeys: Object.keys,
equal: function (a, b, equal) {

@@ -72,3 +116,9 @@ if (a === b) {

if (hasGetter || !hasSetter) {
propertyOutput.sp().append(inspect(obj[key]));
var value = obj[key];
var inspectedValue = inspect(value);
if (value && value._expectIt) {
propertyOutput.sp().block(inspectedValue);
} else {
propertyOutput.sp().append(inspectedValue);
}
}

@@ -161,3 +211,3 @@

if (!keyDiff || (keyDiff && !keyDiff.inline)) {
annotation.error('should be: ')
annotation.error('should be ')
.block(inspect(expected[key]));

@@ -192,3 +242,5 @@

}
this.block(annotation.prependLinesWith('error', ' // '));
if (!annotation.isEmpty()) {
this.sp().annotationBlock(annotation);
}
}).nl();

@@ -212,3 +264,3 @@ });

if (typeA === 'string') {
return utils.levenshteinDistance(a, b) < a.length / 2;
return leven(a, b) < a.length / 2;
}

@@ -237,24 +289,38 @@

expect.addType({
name: 'array',
name: 'arrayLike',
base: 'object',
identify: function (arr) {
return utils.isArray(arr) || utils.isArguments(arr);
identify: function (obj) {
return obj && typeof obj === 'object' && typeof obj.length === 'number';
},
getKeys: function (obj) {
var keys = new Array(obj.length);
for (var i = 0 ; i < obj.length ; i += 1) {
keys[i] = i;
}
return keys;
},
equal: function (a, b, equal) {
return a === b || (a.length === b.length && a.every(function (v, index) {
return a === b || (a.constructor === b.constructor && a.length === b.length && Array.prototype.every.call(a, function (v, index) {
return equal(v, b[index]);
}));
},
prefix: function (output) {
return output.text('[');
},
suffix: function (output) {
return output.text(']');
},
inspect: function (arr, depth, output, inspect) {
var prefixOutput = this.prefix(output.clone(), arr);
var suffixOutput = this.suffix(output.clone(), arr);
if (arr.length === 0) {
return output.text('[]');
return output.append(prefixOutput).append(suffixOutput);
}
if (depth === 1) {
return output.text('[...]');
return output.append(prefixOutput).text('...').append(suffixOutput);
}
if (utils.isArguments(arr)) {
if (!Array.isArray(arr)) {
arr = Array.prototype.slice.call(arr);

@@ -282,3 +348,3 @@ }

if (multipleLines) {
output.text('[').nl().indentLines();
output.append(prefixOutput).nl().indentLines();

@@ -289,5 +355,5 @@ inspectedItems.forEach(function (inspectedItem, index) {

output.outdentLines().text(']');
output.outdentLines().append(suffixOutput);
} else {
output.text('[ ');
output.append(prefixOutput).sp();
inspectedItems.forEach(function (inspectedItem, index) {

@@ -300,3 +366,3 @@ output.append(inspectedItem);

});
output.text(' ]');
output.sp().append(suffixOutput);
}

@@ -311,7 +377,10 @@ return output;

if (utils.isArguments(actual)) {
if (actual.constructor !== expected.constructor) {
return this.baseType.diff(actual, expected, output, diff, inspect, equal);
}
if (!Array.isArray(actual)) {
actual = Array.prototype.slice.call(actual);
}
if (utils.isArguments(expected)) {
if (!Array.isArray(expected)) {
expected = Array.prototype.slice.call(expected);

@@ -355,8 +424,12 @@ }

removedItems = 0;
actual.forEach(function (_, index) {
removedItems += removesByIndex[index] || 0;
removeTable[index] = removedItems;
});
function updateRemoveTable() {
removedItems = 0;
actual.forEach(function (_, index) {
removedItems += removesByIndex[index] || 0;
removeTable[index] = removedItems;
});
}
updateRemoveTable();
var moves = itemsDiff.filter(function (diffItem) {

@@ -379,10 +452,5 @@ return diffItem.type === 'move';

removesByIndex[diffItem.from] = movedItems;
updateRemoveTable();
});
removedItems = 0;
actual.forEach(function (_, index) {
removedItems += removesByIndex[index] || 0;
removeTable[index] = removedItems;
});
var inserts = itemsDiff.filter(function (diffItem) {

@@ -411,5 +479,4 @@ return diffItem.type === 'insert';

});
output.append(this.prefix(output.clone())).nl().indentLines();
output.text('[').nl().indentLines();
mutatedArray.forEach(function (diffItem, index) {

@@ -421,6 +488,7 @@ output.i().block(function () {

if (type === 'insert') {
this.error('missing: ').block(inspect(diffItem.value))
.prependLinesWith('error', '// ');
this.annotationBlock(function () {
this.error('missing ').block(inspect(diffItem.value));
});
} else if (type === 'remove') {
this.block(inspect(diffItem.value).text(last ? '' : ',').error(' // should be removed'));
this.block(inspect(diffItem.value).text(last ? ' ' : ', ').error('// should be removed'));
} else if (equal(diffItem.value, diffItem.expected)) {

@@ -433,11 +501,9 @@ this.block(inspect(diffItem.value).text(last ? '' : ','));

} else if (valueDiff) {
this.block(inspect(diffItem.value).text(last ? '' : ',')).block(function () {
this.error('should be: ').append(inspect(diffItem.expected)).nl()
.append(valueDiff.diff)
.prependLinesWith('error', ' // ');
this.block(inspect(diffItem.value).text(last ? ' ' : ', ')).annotationBlock(function () {
this.error('should be ').block(inspect(diffItem.expected)).nl()
.append(valueDiff.diff);
});
} else {
this.block(inspect(diffItem.value).text(last ? '' : ',')).block(function () {
this.error('should be: ').append(inspect(diffItem.expected))
.prependLinesWith('error', ' // ');
this.block(inspect(diffItem.value).text(last ? ' ' : ', ')).annotationBlock(function () {
this.error('should be ').block(inspect(diffItem.expected));
});

@@ -449,3 +515,3 @@ }

output.outdentLines().text(']');
output.outdentLines().append(this.suffix(output.clone()));

@@ -457,2 +523,24 @@ return result;

expect.addType({
name: 'array',
base: 'arrayLike',
identify: function (arr) {
return utils.isArray(arr);
}
});
expect.addType({
name: 'arguments',
base: 'arrayLike',
prefix: function (output) {
return output.text('arguments(', 'cyan');
},
suffix: function (output) {
return output.text(')', 'cyan');
},
identify: function (obj) {
return Object.prototype.toString.call(obj) === '[object Arguments]';
}
});
expect.addType({
base: 'object',

@@ -504,9 +592,12 @@ name: 'Error',

},
inspect: function (f, depth, output) {
inspect: function (f, depth, output, inspect) {
var source = f.toString();
var name;
var args;
var body;
var matchSource = source.match(/^function (\w*)?\s*\(([^\)]*)\)\s*\{([\s\S]*?( *)?)\}$/);
if (matchSource) {
var name = matchSource[1];
var args = matchSource[2];
var body = matchSource[3];
name = matchSource[1];
args = matchSource[2];
body = matchSource[3];
var bodyIndent = matchSource[4] || '';

@@ -524,9 +615,8 @@ if (!/\\\n/.test(body)) {

}
output.code('function ' + name + '(' + args + ') {' + body + '}', 'javascript');
} else {
if (f.name) {
output.sp().code(f.name, 'javascript');
}
output.text('(...) {...}');
name = f.name || '';
args = ' /*...*/ ';
body = ' /*...*/ ';
}
output.code('function ' + name + '(' + args + ') {' + body + '}', 'javascript');
return output;

@@ -544,7 +634,15 @@ }

output.text('expect.it(');
var orBranch = false;
f._expectations.forEach(function (expectation, index) {
if (0 < index) {
output.text(').and(');
if (expectation === f._OR) {
orBranch = true;
return;
}
if (orBranch) {
output.text(')\n .or(');
} else if (0 < index) {
output.text(')\n .and(');
}
var args = Array.prototype.slice.call(expectation);

@@ -557,2 +655,3 @@ args.forEach(function (arg, i) {

});
orBranch = false;
});

@@ -593,8 +692,6 @@

name: 'binaryArray',
base: 'array',
base: 'arrayLike',
digitWidth: 2,
hexDumpWidth: 16,
identify: function () {
return false;
},
identify: false,
equal: function (a, b) {

@@ -629,3 +726,3 @@ if (a === b) {

hexChars += leftPad(octet.toString(16).toUpperCase(), this.digitWidth, '0') + ' ';
asciiChars += String.fromCharCode(octet);
asciiChars += String.fromCharCode(octet).replace(/\n/g, '␊').replace(/\r/g, '␍');
} else if (this.digitWidth === 2) {

@@ -659,38 +756,12 @@ hexChars += ' ';

},
diffLimit: 512,
diff: function (actual, expected, output, diff, inspect) {
var result = {
diff: utils.diffStrings(this.hexDump(actual), this.hexDump(expected), output, {type: 'Chars', markUpSpecialCharacters: false})
};
for (var i = 0 ; i < result.diff.output.length ; i += 1) {
var isInAsciiChars = false;
for (var j = 0 ; j < result.diff.output[i].length ; j += 1) {
var obj = result.diff.output[i][j];
var replacement = '';
for (var k = 0 ; k < obj.args[0].length ; k += 1) {
var ch = obj.args[0].charAt(k);
if (ch === '│') {
isInAsciiChars = true;
} else if (isInAsciiChars) {
if (/[\x00-\x1f\x7f-\xff]/.test(ch)) {
ch = '.';
}
} else if (ch === ' ' && /\bbg/.test(obj.args[1])) {
var leftover = obj.args[0].substr(k + 1);
if (replacement) {
obj.args[0] = replacement;
j += 1;
}
replacement = '';
result.diff.output[i].splice(j, 0, {style: 'text', args: [' ', 'white']});
k = 0;
ch = ' ';
if (leftover.length > 0) {
result.diff.output[i].splice(j + 1, 0, {style: 'text', args: [leftover, obj.args[1]]});
}
obj = result.diff.output[i][j];
}
replacement += ch;
}
obj.args[0] = replacement;
}
var result = {diff: output};
if (Math.max(actual.length, expected.length) > this.diffLimit) {
result.diff.comment('Diff suppressed due to size > ' + this.diffLimit);
} else {
result.diff = utils.diffStrings(this.hexDump(actual), this.hexDump(expected), output, {type: 'Chars', markUpSpecialCharacters: false})
.replaceText(/[\x00-\x1f\x7f-\xff␊␍]/g, '.').replaceText(/[│ ]/g, function (styles, content) {
this.text(content);
});
}

@@ -697,0 +768,0 @@ return result;

@@ -7,3 +7,3 @@ /*global window*/

var extend = utils.extend;
var levenshteinDistance = utils.levenshteinDistance;
var leven = require('leven');
var cloneError = utils.cloneError;

@@ -24,2 +24,17 @@

return null;
},
is: function (typeOrTypeName) {
var typeName;
if (typeof typeOrTypeName === 'string') {
typeName = typeOrTypeName;
} else {
typeName = typeOrTypeName.name;
}
if (this.name === typeName) {
return true;
} else if (this.baseType) {
return this.baseType.is(typeName);
} else {
return false;
}
}

@@ -37,27 +52,102 @@ };

function createExpectIt(expect, expectations) {
function expectIt(subject) {
var evaluation = expectations.map(function (expectation) {
var OR = {};
function getOrGroups(expectations) {
var orGroups = [[]];
expectations.forEach(function (expectation) {
if (expectation === OR) {
orGroups.push([]);
} else {
orGroups[orGroups.length - 1].push(expectation);
}
});
return orGroups;
}
function evaluateGroup(expect, subject, orGroup) {
var failedGroup = false;
return orGroup.map(function (expectation) {
var args = Array.prototype.slice.call(expectation);
args.unshift(subject);
var evaluation = { expectation: args };
if (!failedGroup) {
evaluation.evaluated = true;
try {
var args = Array.prototype.slice.call(expectation);
args.unshift(subject);
expect.apply(expect, args);
return null;
} catch (e) {
return e;
if (!e._isUnexpected) {
throw e;
}
failedGroup = true;
evaluation.failure = e;
}
}).filter(function (e) {
return e;
}
return evaluation;
});
}
function writeGroupEvaluationsToOutput(expect, output, groupEvaluations) {
var hasOrClauses = groupEvaluations.length > 1;
var hasAndClauses = groupEvaluations.some(function (groupEvaluation) {
return groupEvaluation.length > 1;
});
groupEvaluations.forEach(function (groupEvaluation, i) {
if (i > 0) {
if (hasAndClauses) {
output.nl();
} else {
output.sp();
}
output.comment('or').nl();
}
groupEvaluation.forEach(function (evaluation, j) {
if (j > 0) {
output.comment(' and').nl();
}
if (evaluation.failure) {
if (hasAndClauses || hasOrClauses) {
output.error('⨯ ');
}
output.append(evaluation.failure.output);
} else {
var style = evaluation.evaluated ? 'success' : 'text';
var expectation = evaluation.expectation;
if (evaluation.evaluated) {
output.success('✓ ');
} else {
output.sp(2);
}
output[style]('expected ');
output.text(expect.inspect(expectation[0])).sp();
output[style](expectation[1]);
expectation.slice(2).forEach(function (v) {
output.sp().append(expect.inspect(v));
});
}
});
});
}
if (evaluation.length > 0) {
expect.fail(function (output) {
evaluation.forEach(function (failedExpectation, index) {
if (index > 0) {
output.text(' and').nl();
}
function createExpectIt(expect, expectations) {
var orGroups = getOrGroups(expectations);
output.append(failedExpectation.output);
});
function expectIt(subject) {
var groupEvaluations = orGroups.map(function (orGroup) {
return evaluateGroup(expect, subject, orGroup);
});
var failed = groupEvaluations.every(function (groupEvaluation) {
return groupEvaluation.some(function (evaluation) {
return evaluation.failure;
});
});
if (failed) {
expect.fail(function (output) {
writeGroupEvaluationsToOutput(expect, output, groupEvaluations);
});
}

@@ -67,2 +157,3 @@ }

expectIt._expectations = expectations;
expectIt._OR = OR;
expectIt.and = function () {

@@ -73,2 +164,7 @@ var copiedExpectations = expectations.slice();

};
expectIt.or = function () {
var copiedExpectations = expectations.slice();
copiedExpectations.push(OR, arguments);
return createExpectIt(expect, copiedExpectations);
};
return expectIt;

@@ -266,3 +362,10 @@ }

};
this.types.unshift(extendedType);
if (extendedType.identify === false) {
extendedType.identify = function () {
return false;
};
this.types.push(extendedType);
} else {
this.types.unshift(extendedType);
}

@@ -288,3 +391,13 @@ return this.expect;

function handleNestedExpects(e, assertion) {
function buildDiff(expect, err) {
return err.createDiff && err.createDiff(expect.output.clone(), function (actual, expected) {
return expect.diff(actual, expected);
}, function (v, depth) {
return expect.inspect(v, depth || Infinity);
}, function (actual, expected) {
return expect.equal(actual, expected);
});
}
function handleNestedExpects(expect, e, assertion) {
switch (assertion.errorMode) {

@@ -301,2 +414,13 @@ case 'nested':

return errorWithMessage(e, e.output);
case 'diff':
return errorWithMessage(e, e.output.clone().append(function (output) {
var comparison = buildDiff(expect, e);
delete e.createDiff;
if (comparison && comparison.diff) {
output.append(comparison.diff);
} else {
output.append(e.output);
}
}));
default:

@@ -336,7 +460,5 @@ throw new Error("Unknown error mode: '" + assertion.errorMode + "'");

if (err.createDiff) {
var comparison = err.createDiff();
if (comparison) {
message.nl(2).blue('Diff:').nl(2).append(comparison.diff);
}
var comparison = buildDiff(this.expect, err);
if (comparison) {
message.nl(2).append(comparison.diff);
}

@@ -382,3 +504,3 @@

if (nestingLevel === 0) {
var wrappedError = handleNestedExpects(e, assertion);
var wrappedError = handleNestedExpects(wrappedExpect, e, assertion);
that.setErrorMessage(wrappedError);

@@ -418,2 +540,3 @@ throw wrappedError;

wrappedExpect.format = this.format;
wrappedExpect.it = this.it.bind(this);

@@ -463,3 +586,3 @@ var args = Array.prototype.slice.call(arguments, 2);

assertion: assertion,
score: typeMatchBonus - levenshteinDistance(testDescriptionString, assertion)
score: typeMatchBonus - leven(testDescriptionString, assertion)
});

@@ -466,0 +589,0 @@ });

@@ -81,6 +81,2 @@ var stringDiff = require('diff');

isArguments: function (object) {
return Object.prototype.toString.call(object) === '[object Arguments]';
},
getKeysOfDefinedProperties: function (object) {

@@ -98,40 +94,2 @@ var keys = Object.keys(object).filter(function (key) {

/**
* Levenshtein distance algorithm from wikipedia
* http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
*/
levenshteinDistance: function (a, b) {
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
var matrix = [];
// increment along the first column of each row
var i;
for (i = 0; i <= b.length; i += 1) {
matrix[i] = [i];
}
// increment each column in the first row
var j;
for (j = 0; j <= a.length; j += 1) {
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for (i = 1; i <= b.length; i += 1) {
for (j = 1; j <= a.length; j += 1) {
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
Math.min(matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j] + 1)); // deletion
}
}
}
return matrix[b.length][a.length];
},
truncateStack: function (err, fn) {

@@ -215,6 +173,6 @@ if (Error.captureStackTrace) {

});
return output;
} else {
output.write(baseStyle, text);
}
return output;
}

@@ -221,0 +179,0 @@

{
"name": "unexpected",
"version": "5.0.0-beta2",
"version": "5.0.0-beta20",
"author": "Sune Sloth Simonsen <sune@we-knowhow.dk>",

@@ -23,7 +23,8 @@ "keywords": [

"arraydiff": "0.1.1",
"diff": "=1.0.8",
"magicpen": "=2.1.0"
"diff": "1.1.0",
"leven": "1.0.0",
"magicpen": "3.0.0"
},
"devDependencies": {
"browserify": "=5.9.1",
"browserify": "5.9.1",
"bundle-collapser": "^1.1.0",

@@ -34,8 +35,8 @@ "coveralls": "^2.11.1",

"jshint": "2.5.6",
"mocha": "=1.21.4",
"mocha-phantomjs": "=3.5.0",
"mocha": "2.0.1",
"mocha-phantomjs": "3.5.1",
"mocha-slow-reporter": "*",
"phantomjs": "=1.9.7-15",
"phantomjs": "1.9.7-15",
"serve": "*"
}
}
# Unexpected
Minimalistic BDD assertion toolkit inspired by
Extensible BDD assertion toolkit inspired by
[expect.js](https://github.com/LearnBoost/expect.js)

@@ -19,3 +19,3 @@

[Run the test in the browser](http://sunesimonsen.github.io/unexpected/test/tests.production.html)
[Run the test in the browser](http://sunesimonsen.github.io/unexpected/test/tests.html)

@@ -176,7 +176,3 @@ ## Features

expect(NaN, 'to be NaN');
expect({}, 'to be NaN');
expect(2, 'not to be NaN');
expect(null, 'not to be NaN');
expect(undefined, 'to be NaN');
expect("String", 'to be NaN');
```

@@ -210,3 +206,2 @@

expect('hello world', 'to contain', 'world');
expect(null, 'not to contain', 'world');
```

@@ -222,3 +217,3 @@

**empty**: asserts that an array is empty or not
**empty**: asserts that an array or array-like object (identified by the presence of a `length` property) is empty

@@ -228,6 +223,5 @@ ```js

expect('', 'to be empty');
expect({}, 'to be empty');
expect({ length: 0, duck: 'typing' }, 'to be empty');
expect({ my: 'object' }, 'not to be empty');
expect([1,2,3], 'not to be empty');
expect({ length: 0, duck: 'typing' }, 'to be empty');
```

@@ -252,3 +246,3 @@

expect({ a: 'a', b: { c: 'c' }, d: 'd' }, 'to have own properties', ['a', 'b']);
expect({ a: 'a', b: { c: 'c' }, d: 'd' }, 'to not have properties', ['k', 'l']);
expect({ a: 'a', b: { c: 'c' }, d: 'd' }, 'not to have properties', ['k', 'l']);
expect({ a: 'a', b: { c: 'c' }, d: 'd' }, 'to have properties', {

@@ -267,3 +261,2 @@ a: 'a',

```js
expect(null, 'not to have key', 'a');
expect({ a: 'b' }, 'to have key', 'a');

@@ -290,2 +283,8 @@ expect({ a: 'b' }, 'not to have key', 'b');

**arity**: asserts that the `Function` takes the given number of arguments
```js
expect(Math.max, 'to have arity', 2);
```
**finite/infinite**: asserts a finite or infinite number

@@ -297,3 +296,2 @@

expect(Infinity, 'to be infinite');
expect(false, 'not to be infinite');
```

@@ -365,3 +363,3 @@

**array whose items satify**: will run an assertion function for each items in an array
**array whose items satisfy**: will run an assertion function for each items in an array

@@ -383,3 +381,3 @@ ```js

Using this assertion result in very detailed error reporting show in the below example:
Using this assertion result in very detailed error reporting as shown in the below example:

@@ -399,12 +397,44 @@ ```js

failed expectation in [ [ 0, 1, 2 ], [ 4, '5', 6 ], [ 7, 8, '9' ] ]:
1: failed expectation in [ 4, '5', 6 ]:
1: expected '5' to be a 'number'
2: failed expectation in [ 7, 8, '9' ]:
2: expected '9' to be a 'number'
1: failed expectation in [ 4, '5', 6 ]:
1: expected '5' to be a number
2: failed expectation in [ 7, 8, '9' ]:
2: expected '9' to be a number
```
**map whose keys satify**: will run an assertion function for each key in a map
**satisfy**: match against a spec
All properties and nested objects mentioned in the right-hand side object are
required to be present. Primitive values are compared with `to equal` semantics:
```js
expect({ hey: { there: true } }, 'to satisfy', { hey: {} });
```
To disallow additional properties in the subject, use `to exhaustively satisfy`:
```js
expect({ hey: { there: true } }, 'to exhaustively satisfy', { hey: { there: true } });
```
Regular expressions and functions in the right-hand side object will be run
against the corresponding values in the subject:
```js
expect({ bar: 'quux', baz: true }, 'to satisfy', { bar: /QU*X/i });
```
Can be combined with `expect.it` to create complex specifications that delegate to
existing assertions:
```js
expect({foo: 123, baz: 'bogus'}, 'to satisfy', {
foo: expect.it('to be a number').and('to be greater than', 10),
baz: expect.it('not to match', /^boh/)
});
```
**map whose keys satisfy**: will run an assertion function for each key in a map
```js
expect({ foo: 0, bar: 1, baz: 2, qux: 3 },

@@ -420,3 +450,3 @@ 'to be a map whose keys satisfy', function (key) {

Using this assertion result in very detailed error reporting show in the below example:
Using this assertion result in very detailed error reporting as shown in the below example:

@@ -434,6 +464,6 @@ ```js

failed expectation on keys foo, bar, baz, qux, quux:
quux: expected 'quux' to have length 3
quux: expected 'quux' to have length 3
```
**map whose values satify**: will run an assertion function for each value in a map
**map whose values satisfy**: will run an assertion function for each value in a map

@@ -451,3 +481,3 @@ ```js

Using this assertion result in very detailed error reporting show in the below example:
Using this assertion result in very detailed error reporting as shown in the below example:

@@ -467,9 +497,11 @@ ```js

failed expectation in
{ foo: [ 0, 1, 2 ],
{
foo: [ 0, 1, 2 ],
bar: [ 4, '5', 6 ],
baz: [ 7, 8, '9' ] }:
bar: failed expectation in [ 4, '5', 6 ]:
1: expected '5' to be a 'number'
baz: failed expectation in [ 7, 8, '9' ]:
2: expected '9' to be a 'number'
baz: [ 7, 8, '9' ]
}:
bar: failed expectation in [ 4, '5', 6 ]:
1: expected '5' to be a number
baz: failed expectation in [ 7, 8, '9' ]:
2: expected '9' to be a number
```

@@ -586,3 +618,3 @@

expected [ 4, 3, 1, 2 ] to be sorted
expected [ 4, 3, 1, 2 ] to equal [ 1, 2, 3, 4 ]
expected [ 4, 3, 1, 2 ] to equal [ 1, 2, 3, 4 ]
```

@@ -593,3 +625,3 @@

[unexpected-assertions.js](https://github.com/sunesimonsen/unexpected/blob/master/lib/unexpected-assertions.js)
[lib/assertions.js](https://github.com/sunesimonsen/unexpected/blob/master/lib/assertions.js)

@@ -631,9 +663,11 @@ ### expect.installPlugin(plugin)

```js
describe('test suite', function () {
it('should expose a function', function () {
expect(add, 'to be a', 'function');
});
describe('math.js', function () {
describe('add', function () {
it('is a function', function () {
expect(add, 'to be a', 'function');
});
it('should do math', function () {
expect(add(1, 3), 'to be', 4);
it('does addition on numbers', function () {
expect(add(1, 3), 'to be', 4);
});
});

@@ -640,0 +674,0 @@ });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc