Don't require matchers and asymmetric equality testers to pass custom object formatters back to Jasmine

This makes it easier to write high quality matchers and asymmetric equality
testers, and is also a step toward supporting custom object formatters.

Previously, Jasmine passed custom object formatters as the second argument
to matcher factories and as and the second argument to asymmetric equality
testers' `asymmetricMatch` method. Matchers and asymmetric equality testers
were responsible for passing the custom object formatters to methods like
`matchersUtil#equals`:

  function toEqual(util, customEqualityTesters) {
    return {
      compare: function(actual, expected) {
        // ...
        result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);

And:

  ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
    // ...
    for (var i = 0; i < this.sample.length; i++) {
      var item = this.sample[i];
      if (!j$.matchersUtil.contains(other, item, customTesters)) {
        return false;
      }
    }

With this change, that is no longer necessary. Matchers and asymmetric
equality testers can ignore the existence of custom equality testers and
still fully support them:

  function toEqual(util) {
    return {
      compare: function(actual, expected) {
        // ...
        result.pass = util.equals(actual, expected, diffBuilder);

And:

  ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
    // ...
    for (var i = 0; i < this.sample.length; i++) {
      var item = this.sample[i];
      if (!matchersUtil.contains(other, item)) {
        return false;
      }
    }

The old interfaces are still supported, for now, but will be deprecated
in a future commit and removed in the next major release after that.

In addition to making matchers and custom equality testers simpler,
this change sets the stage for adding support for custom object
formatters. Those will be architecturally similar to custom equality
testers, and by injecting a `MatchersUtil` instance everywhere we can
add them without requiring user code to pass them around as used to be
the case with custom object formatters.
This commit is contained in:
Steve Gravrock
2019-09-21 10:58:09 -07:00
committed by Steve Gravrock
parent a00f995c68
commit dec67bd535
43 changed files with 1214 additions and 455 deletions

View File

@@ -73,7 +73,12 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.buildExpectationResult = jRequire.buildExpectationResult(); j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.noopTimer = jRequire.noopTimer(); j$.noopTimer = jRequire.noopTimer();
j$.JsApiReporter = jRequire.JsApiReporter(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$);
j$.matchersUtil = jRequire.matchersUtil(j$); j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim(
j$
);
j$.MatchersUtil = jRequire.MatchersUtil(j$);
j$.matchersUtil = new j$.MatchersUtil({ customTesters: [] });
j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$);
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
@@ -1188,6 +1193,7 @@ getJasmineRequireObj().Env = function(j$) {
} }
var customMatchers = var customMatchers =
runnableResources[currentRunnable().id].customMatchers; runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) { for (var matcherName in matchersToAdd) {
customMatchers[matcherName] = matchersToAdd[matcherName]; customMatchers[matcherName] = matchersToAdd[matcherName];
} }
@@ -1201,6 +1207,7 @@ getJasmineRequireObj().Env = function(j$) {
} }
var customAsyncMatchers = var customAsyncMatchers =
runnableResources[currentRunnable().id].customAsyncMatchers; runnableResources[currentRunnable().id].customAsyncMatchers;
for (var matcherName in matchersToAdd) { for (var matcherName in matchersToAdd) {
customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
} }
@@ -1220,9 +1227,12 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var expectationFactory = function(actual, spec) { var expectationFactory = function(actual, spec) {
var customEqualityTesters =
runnableResources[spec.id].customEqualityTesters;
return j$.Expectation.factory({ return j$.Expectation.factory({
util: j$.matchersUtil, util: new j$.MatchersUtil({ customTesters: customEqualityTesters }),
customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customEqualityTesters: customEqualityTesters,
customMatchers: runnableResources[spec.id].customMatchers, customMatchers: runnableResources[spec.id].customMatchers,
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
@@ -1234,8 +1244,11 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var asyncExpectationFactory = function(actual, spec) { var asyncExpectationFactory = function(actual, spec) {
var customEqualityTesters =
runnableResources[spec.id].customEqualityTesters;
return j$.Expectation.asyncFactory({ return j$.Expectation.asyncFactory({
util: j$.matchersUtil, util: new j$.MatchersUtil({ customTesters: customEqualityTesters }),
customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
actual: actual, actual: actual,
@@ -2269,7 +2282,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) { ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isArray_(this.sample)) { if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.'); throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
} }
@@ -2283,7 +2296,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
for (var i = 0; i < this.sample.length; i++) { for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i]; var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) { if (!matchersUtil.contains(other, item)) {
return false; return false;
} }
} }
@@ -2304,7 +2317,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
this.sample = sample; this.sample = sample;
} }
ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) { ArrayWithExactContents.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isArray_(this.sample)) { if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.'); throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
} }
@@ -2315,7 +2328,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
for (var i = 0; i < this.sample.length; i++) { for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i]; var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) { if (!matchersUtil.contains(other, item)) {
return false; return false;
} }
} }
@@ -2380,7 +2393,7 @@ getJasmineRequireObj().MapContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
MapContaining.prototype.asymmetricMatch = function(other, customTesters) { MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isMap(other)) return false; if (!j$.isMap(other)) return false;
var hasAllMatches = true; var hasAllMatches = true;
@@ -2390,8 +2403,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
var hasMatch = false; var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) { j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
if ( if (
j$.matchersUtil.equals(oKey, key, customTesters) matchersUtil.equals(oKey, key)
&& j$.matchersUtil.equals(oValue, value, customTesters) && matchersUtil.equals(oValue, value)
) { ) {
hasMatch = true; hasMatch = true;
oBreakLoop(); oBreakLoop();
@@ -2470,12 +2483,12 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
return hasProperty(getPrototype(obj), property); return hasProperty(getPrototype(obj), property);
} }
ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) { ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); } if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
for (var property in this.sample) { for (var property in this.sample) {
if (!hasProperty(other, property) || if (!hasProperty(other, property) ||
!j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) { !matchersUtil.equals(this.sample[property], other[property])) {
return false; return false;
} }
} }
@@ -2499,17 +2512,17 @@ getJasmineRequireObj().SetContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
SetContaining.prototype.asymmetricMatch = function(other, customTesters) { SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isSet(other)) return false; if (!j$.isSet(other)) return false;
var hasAllMatches = true; var hasAllMatches = true;
j$.util.forEachBreakable(this.sample, function(breakLoop, item) { j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
// for each item in `sample` there should be at least one matching item in `other` // for each item in `sample` there should be at least one matching item in `other`
// (not using `j$.matchersUtil.contains` because it compares set members by reference, // (not using `matchersUtil.contains` because it compares set members by reference,
// not by deep value equality) // not by deep value equality)
var hasMatch = false; var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oItem) { j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
if (j$.matchersUtil.equals(oItem, item, customTesters)) { if (matchersUtil.equals(oItem, item)) {
hasMatch = true; hasMatch = true;
oBreakLoop(); oBreakLoop();
} }
@@ -2566,6 +2579,112 @@ getJasmineRequireObj().Truthy = function(j$) {
return Truthy; return Truthy;
}; };
getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
/*
Older versions of Jasmine passed an array of custom equality testers as the
second argument to each asymmetric equality tester's `asymmetricMatch`
method. Newer versions will pass a `MatchersUtil` instance. The
asymmetricEqualityTesterArgCompatShim allows for a graceful migration from
the old interface to the new by "being" both an array of custom equality
testers and a `MatchersUtil` at the same time.
This code should be removed in the next major release.
*/
var likelyArrayProps = [
'concat',
'constructor',
'copyWithin',
'entries',
'every',
'fill',
'filter',
'find',
'findIndex',
'flat',
'flatMap',
'forEach',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf',
'length',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toSource',
'toString',
'unshift',
'values'
];
function asymmetricEqualityTesterArgCompatShim(
matchersUtil,
customEqualityTesters
) {
var self = Object.create(matchersUtil),
props,
i,
k;
copy(self, customEqualityTesters, 'length');
for (i = 0; i < customEqualityTesters.length; i++) {
copy(self, customEqualityTesters, i);
}
var props = arrayProps();
for (i = 0; i < props.length; i++) {
k = props[i];
if (k !== 'length') {
copy(self, Array.prototype, k);
}
}
return self;
}
function copy(dest, src, propName) {
Object.defineProperty(dest, propName, {
get: function() {
return src[propName];
}
});
}
function arrayProps() {
var props, a, k;
if (!Object.getOwnPropertyDescriptors) {
return likelyArrayProps.filter(function(k) {
return Array.prototype.hasOwnProperty(k);
});
}
props = Object.getOwnPropertyDescriptors(Array.prototype);
a = [];
for (k in props) {
a.push(k);
}
return a;
}
return asymmetricEqualityTesterArgCompatShim;
};
getJasmineRequireObj().CallTracker = function(j$) { getJasmineRequireObj().CallTracker = function(j$) {
/** /**
* @namespace Spy#calls * @namespace Spy#calls
@@ -3822,7 +3941,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
* @example * @example
* return expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
*/ */
return function toBeRejectedWith(util, customEqualityTesters) { return function toBeRejectedWith(util) {
return { return {
compare: function(actualPromise, expectedValue) { compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) { if (!j$.isPromiseLike(actualPromise)) {
@@ -3843,7 +3962,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
}; };
}, },
function(actualValue) { function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) { if (util.equals(actualValue, expectedValue)) {
return { return {
pass: true, pass: true,
message: prefix(true) + '.' message: prefix(true) + '.'
@@ -4000,7 +4119,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
* @example * @example
* return expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
*/ */
return function toBeResolvedTo(util, customEqualityTesters) { return function toBeResolvedTo(util) {
return { return {
compare: function(actualPromise, expectedValue) { compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) { if (!j$.isPromiseLike(actualPromise)) {
@@ -4015,7 +4134,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
return actualPromise.then( return actualPromise.then(
function(actualValue) { function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) { if (util.equals(actualValue, expectedValue)) {
return { return {
pass: true, pass: true,
message: prefix(true) + '.' message: prefix(true) + '.'
@@ -4073,66 +4192,70 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
}; };
}; };
getJasmineRequireObj().matchersUtil = function(j$) { getJasmineRequireObj().MatchersUtil = function(j$) {
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
return { function MatchersUtil(options) {
equals: equals, options = options || {};
this.customTesters_ = options.customTesters || [];
contains: function(haystack, needle, customTesters) { if (!j$.isArray_(this.customTesters_)) {
customTesters = customTesters || []; throw new Error("MatchersUtil requires custom equality testers");
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (equals(haystack[i], needle, customTesters)) {
return true;
}
}
return false;
}
return !!haystack && haystack.indexOf(needle) >= 0;
},
buildFailureMessage: function() {
var args = Array.prototype.slice.call(arguments, 0),
matcherName = args[0],
isNot = args[1],
actual = args[2],
expected = args.slice(3),
englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
var message = 'Expected ' +
j$.pp(actual) +
(isNot ? ' not ' : ' ') +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + j$.pp(expected[i]);
}
}
return message + '.';
} }
}
MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (this.equals(haystack[i], needle, customTesters)) {
return true;
}
}
return false;
}
return !!haystack && haystack.indexOf(needle) >= 0;
};
MatchersUtil.prototype.buildFailureMessage = function() {
var args = Array.prototype.slice.call(arguments, 0),
matcherName = args[0],
isNot = args[1],
actual = args[2],
expected = args.slice(3),
englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
var message = 'Expected ' +
j$.pp(actual) +
(isNot ? ' not ' : ' ') +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + j$.pp(expected[i]);
}
}
return message + '.';
}; };
function isAsymmetric(obj) { function isAsymmetric(obj) {
return obj && j$.isA_('Function', obj.asymmetricMatch); return obj && j$.isA_('Function', obj.asymmetricMatch);
} }
function asymmetricMatch(a, b, customTesters, diffBuilder) { MatchersUtil.prototype.asymmetricMatch_ = function(a, b, customTesters, diffBuilder) {
var asymmetricA = isAsymmetric(a), var asymmetricA = isAsymmetric(a),
asymmetricB = isAsymmetric(b), asymmetricB = isAsymmetric(b),
shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters),
result; result;
if (asymmetricA && asymmetricB) { if (asymmetricA && asymmetricB) {
@@ -4140,7 +4263,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
if (asymmetricA) { if (asymmetricA) {
result = a.asymmetricMatch(b, customTesters); result = a.asymmetricMatch(b, shim);
if (!result) { if (!result) {
diffBuilder.record(a, b); diffBuilder.record(a, b);
} }
@@ -4148,27 +4271,36 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
if (asymmetricB) { if (asymmetricB) {
result = b.asymmetricMatch(a, customTesters); result = b.asymmetricMatch(a, shim);
if (!result) { if (!result) {
diffBuilder.record(a, b); diffBuilder.record(a, b);
} }
return result; return result;
} }
} };
function equals(a, b, customTesters, diffBuilder) { MatchersUtil.prototype.equals = function(a, b, customTestersOrDiffBuilder, diffBuilderOrNothing) {
customTesters = customTesters || []; var customTesters, diffBuilder;
if (isDiffBuilder(customTestersOrDiffBuilder)) {
diffBuilder = customTestersOrDiffBuilder;
} else {
customTesters = customTestersOrDiffBuilder;
diffBuilder = diffBuilderOrNothing;
}
customTesters = customTesters || this.customTesters_;
diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder = diffBuilder || j$.NullDiffBuilder();
return eq(a, b, [], [], customTesters, diffBuilder); return this.eq_(a, b, [], [], customTesters, diffBuilder);
} };
// Equality function lovingly adapted from isEqual in // Equality function lovingly adapted from isEqual in
// [Underscore](http://underscorejs.org) // [Underscore](http://underscorejs.org)
function eq(a, b, aStack, bStack, customTesters, diffBuilder) { MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, customTesters, diffBuilder) {
var result = true, i; var result = true, self = this, i;
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder); var asymmetricResult = this.asymmetricMatch_(a, b, customTesters, diffBuilder);
if (!j$.util.isUndefined(asymmetricResult)) { if (!j$.util.isUndefined(asymmetricResult)) {
return asymmetricResult; return asymmetricResult;
} }
@@ -4305,7 +4437,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter); diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
result = false; result = false;
} else { } else {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result; result = self.eq_(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
} }
}); });
} }
@@ -4346,12 +4478,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// otherwise explicitly look up the mapKey in the other Map since we want keys with unique // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
// obj identity (that are otherwise equal) to not match. // obj identity (that are otherwise equal) to not match.
if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) && if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
mapValueB = b.get(cmpKey); mapValueB = b.get(cmpKey);
} else { } else {
mapValueB = b.get(mapKey); mapValueB = b.get(mapKey);
} }
result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder()); result = this.eq_(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
} }
} }
@@ -4395,7 +4527,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
otherValue = otherValues[l]; otherValue = otherValues[l];
prevStackSize = baseStack.length; prevStackSize = baseStack.length;
// compare by value equality // compare by value equality
found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder()); found = this.eq_(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
if (!found && prevStackSize !== baseStack.length) { if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize); baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize); otherStack.splice(prevStackSize);
@@ -4444,7 +4576,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
diffBuilder.withPath(key, function() { diffBuilder.withPath(key, function() {
if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) { if(!self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
result = false; result = false;
} }
}); });
@@ -4459,7 +4591,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
bStack.pop(); bStack.pop();
return result; return result;
} };
function keys(obj, isArray) { function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) : var allKeys = Object.keys ? Object.keys(obj) :
@@ -4542,6 +4674,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
return formatted; return formatted;
} }
function isDiffBuilder(obj) {
return obj && typeof obj.record === 'function';
}
return MatchersUtil;
}; };
getJasmineRequireObj().nothing = function() { getJasmineRequireObj().nothing = function() {
@@ -4839,7 +4977,7 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) {
* expect(3).toBeInstanceOf(Number); * expect(3).toBeInstanceOf(Number);
* expect(new Error()).toBeInstanceOf(Error); * expect(new Error()).toBeInstanceOf(Error);
*/ */
function toBeInstanceOf(util, customEqualityTesters) { function toBeInstanceOf() {
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual), var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual),
@@ -5109,14 +5247,12 @@ getJasmineRequireObj().toContain = function() {
* expect(array).toContain(anElement); * expect(array).toContain(anElement);
* expect(string).toContain(substring); * expect(string).toContain(substring);
*/ */
function toContain(util, customEqualityTesters) { function toContain(util) {
customEqualityTesters = customEqualityTesters || [];
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
return { return {
pass: util.contains(actual, expected, customEqualityTesters) pass: util.contains(actual, expected)
}; };
} }
}; };
@@ -5135,9 +5271,7 @@ getJasmineRequireObj().toEqual = function(j$) {
* @example * @example
* expect(bigObject).toEqual({"foo": ['bar', 'baz']}); * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
*/ */
function toEqual(util, customEqualityTesters) { function toEqual(util) {
customEqualityTesters = customEqualityTesters || [];
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
var result = { var result = {
@@ -5145,7 +5279,7 @@ getJasmineRequireObj().toEqual = function(j$) {
}, },
diffBuilder = j$.DiffBuilder(); diffBuilder = j$.DiffBuilder();
result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder); result.pass = util.equals(actual, expected, diffBuilder);
// TODO: only set error message if test fails // TODO: only set error message if test fails
result.message = diffBuilder.getMessage(); result.message = diffBuilder.getMessage();
@@ -5315,7 +5449,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
* @example * @example
* expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2); * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
*/ */
function toHaveBeenCalledWith(util, customEqualityTesters) { function toHaveBeenCalledWith(util) {
return { return {
compare: function() { compare: function() {
var args = Array.prototype.slice.call(arguments, 0), var args = Array.prototype.slice.call(arguments, 0),
@@ -5336,7 +5470,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
return result; return result;
} }
if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) { if (util.contains(actual.calls.allArgs(), expectedArgs)) {
result.pass = true; result.pass = true;
result.message = function() { result.message = function() {
return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' + return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' +
@@ -5351,7 +5485,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) { var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) {
var diffBuilder = new j$.DiffBuilder(); var diffBuilder = new j$.DiffBuilder();
util.equals(argsForCall, expectedArgs, customEqualityTesters, diffBuilder); util.equals(argsForCall, expectedArgs, diffBuilder);
return 'Call ' + callIx + ':\n' + return 'Call ' + callIx + ':\n' +
diffBuilder.getMessage().replace(/^/mg, ' '); diffBuilder.getMessage().replace(/^/mg, ' ');
}); });
@@ -5384,7 +5518,7 @@ getJasmineRequireObj().toHaveClass = function(j$) {
* el.className = 'foo bar baz'; * el.className = 'foo bar baz';
* expect(el).toHaveClass('bar'); * expect(el).toHaveClass('bar');
*/ */
function toHaveClass(util, customEqualityTesters) { function toHaveClass() {
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
if (!isElement(actual)) { if (!isElement(actual)) {
@@ -6899,6 +7033,8 @@ getJasmineRequireObj().Spy = function(j$) {
}; };
})(); })();
var matchersUtil = new j$.MatchersUtil();
/** /**
* _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj} * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
* @constructor * @constructor
@@ -7094,7 +7230,7 @@ getJasmineRequireObj().Spy = function(j$) {
var i; var i;
for (i = 0; i < this.strategies.length; i++) { for (i = 0; i < this.strategies.length; i++) {
if (j$.matchersUtil.equals(args, this.strategies[i].args)) { if (matchersUtil.equals(args, this.strategies[i].args)) {
return this.strategies[i].strategy; return this.strategies[i].strategy;
} }
} }

View File

@@ -25,7 +25,7 @@ describe('AsyncExpectation', function() {
var addExpectationResult = jasmine.createSpy('addExpectationResult'), var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(), actual = Promise.resolve(),
expectation = jasmineUnderTest.Expectation.asyncFactory({ expectation = jasmineUnderTest.Expectation.asyncFactory({
util: jasmineUnderTest.matchersUtil, util: new jasmineUnderTest.MatchersUtil(),
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -47,7 +47,7 @@ describe('AsyncExpectation', function() {
var addExpectationResult = jasmine.createSpy('addExpectationResult'), var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject(), actual = Promise.reject(),
expectation = jasmineUnderTest.Expectation.asyncFactory({ expectation = jasmineUnderTest.Expectation.asyncFactory({
util: jasmineUnderTest.matchersUtil, util: new jasmineUnderTest.MatchersUtil(),
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -183,7 +183,7 @@ describe('AsyncExpectation', function() {
expectation = jasmineUnderTest.Expectation.asyncFactory({ expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: actual, actual: actual,
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
util: jasmineUnderTest.matchersUtil util: new jasmineUnderTest.MatchersUtil()
}); });
return expectation return expectation
@@ -208,7 +208,7 @@ describe('AsyncExpectation', function() {
expectation = jasmineUnderTest.Expectation.asyncFactory({ expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: actual, actual: actual,
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
util: jasmineUnderTest.matchersUtil util: new jasmineUnderTest.MatchersUtil()
}); });
return expectation return expectation

View File

@@ -304,4 +304,62 @@ describe('Env', function() {
expect(globalErrors.install).toHaveBeenCalled(); expect(globalErrors.install).toHaveBeenCalled();
}); });
}); });
it('creates an expectationFactory that uses the current custom equality testers', function(done) {
function customEqualityTester() {}
var RealSpec = jasmineUnderTest.Spec,
specInstance,
expectationFactory;
spyOn(jasmineUnderTest, 'MatchersUtil');
spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) {
expectationFactory = options.expectationFactory;
specInstance = new RealSpec(options);
return specInstance;
});
env.it('spec', function() {
env.addCustomEqualityTester(customEqualityTester);
expectationFactory('actual', specInstance);
});
env.addReporter({
jasmineDone: function() {
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester]
});
done();
}
});
env.execute();
});
it('creates an asyncExpectationFactory that uses the current custom equality testers', function(done) {
function customEqualityTester() {}
var RealSpec = jasmineUnderTest.Spec,
specInstance,
asyncExpectationFactory;
spyOn(jasmineUnderTest, 'MatchersUtil');
spyOn(jasmineUnderTest, 'Spec').and.callFake(function(options) {
asyncExpectationFactory = options.asyncExpectationFactory;
specInstance = new RealSpec(options);
return specInstance;
});
env.it('spec', function() {
env.addCustomEqualityTester(customEqualityTester);
asyncExpectationFactory('actual', specInstance);
});
env.addReporter({
jasmineDone: function() {
expect(jasmineUnderTest.MatchersUtil).toHaveBeenCalledWith({
customTesters: [customEqualityTester]
});
done();
}
});
env.execute();
});
}); });

View File

@@ -634,7 +634,7 @@ describe('Expectation', function() {
addExpectationResult = jasmine.createSpy('addExpectationResult'), addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = jasmineUnderTest.Expectation.factory({ expectation = jasmineUnderTest.Expectation.factory({
customMatchers: matchers, customMatchers: matchers,
util: jasmineUnderTest.matchersUtil, util: new jasmineUnderTest.MatchersUtil(),
actual: 'an actual', actual: 'an actual',
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });

View File

@@ -0,0 +1,101 @@
describe('asymmetricEqualityTesterArgCompatShim', function() {
it('provides all the properties of the MatchersUtil', function() {
var matchersUtil = {
foo: function() {},
bar: function() {}
},
shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(
matchersUtil,
[]
);
expect(shim.foo).toBe(matchersUtil.foo);
expect(shim.bar).toBe(matchersUtil.bar);
});
it('provides all the properties of the customEqualityTesters', function() {
var customEqualityTesters = [function() {}, function() {}],
shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(
{},
customEqualityTesters
);
expect(shim.length).toBe(2);
expect(shim[0]).toBe(customEqualityTesters[0]);
expect(shim[1]).toBe(customEqualityTesters[1]);
});
it('provides all the properties of Array.prototype', function() {
var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []);
expect(shim.filter).toBe(Array.prototype.filter);
expect(shim.forEach).toBe(Array.prototype.forEach);
expect(shim.map).toBe(Array.prototype.map);
});
it('provides properties of Array.prototype', function() {
var keys = [
'concat',
'constructor',
'every',
'filter',
'forEach',
'indexOf',
'join',
'lastIndexOf',
'length',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toString',
'unshift'
],
optionalKeys = [
'copyWithin',
'entries',
'fill',
'find',
'findIndex',
'flat',
'flatMap',
'includes',
'keys',
'toSource',
'values'
],
shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []),
i,
k;
// Properties that are present on all supported runtimes
for (i = 0; i < keys.length; i++) {
k = keys[i];
expect(shim[k])
.withContext(k)
.not.toBeUndefined();
expect(shim[k])
.withContext(k)
.toBe(Array.prototype[k]);
}
// Properties that are present on only some supported runtimes
for (i = 0; i < optionalKeys.length; i++) {
k = optionalKeys[i];
if (shim[k] !== undefined) {
expect(shim[k])
.withContext(k)
.toBe(Array.prototype[k]);
}
}
});
});

View File

@@ -15,26 +15,30 @@ describe("ArrayContaining", function() {
it("matches when the item is in the actual", function() { it("matches when the item is in the actual", function() {
var containing = new jasmineUnderTest.ArrayContaining(["foo"]); var containing = new jasmineUnderTest.ArrayContaining(["foo"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(["foo"])).toBe(true); expect(containing.asymmetricMatch(["foo"], matchersUtil)).toBe(true);
}); });
it("matches when additional items are in the actual", function() { it("matches when additional items are in the actual", function() {
var containing = new jasmineUnderTest.ArrayContaining(["foo"]); var containing = new jasmineUnderTest.ArrayContaining(["foo"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(["foo", "bar"])).toBe(true); expect(containing.asymmetricMatch(["foo", "bar"], matchersUtil)).toBe(true);
}); });
it("does not match when the item is not in the actual", function() { it("does not match when the item is not in the actual", function() {
var containing = new jasmineUnderTest.ArrayContaining(["foo"]); var containing = new jasmineUnderTest.ArrayContaining(["foo"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(["bar"])).toBe(false); expect(containing.asymmetricMatch(["bar"], matchersUtil)).toBe(false);
}); });
it("does not match when the actual is not an array", function() { it("does not match when the actual is not an array", function() {
var containing = new jasmineUnderTest.ArrayContaining(["foo"]); var containing = new jasmineUnderTest.ArrayContaining(["foo"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch("foo")).toBe(false); expect(containing.asymmetricMatch("foo", matchersUtil)).toBe(false);
}); });
it("jasmineToStrings itself", function() { it("jasmineToStrings itself", function() {
@@ -52,7 +56,8 @@ describe("ArrayContaining", function() {
} }
}; };
var containing = new jasmineUnderTest.ArrayContaining(["fooVal"]); var containing = new jasmineUnderTest.ArrayContaining(["fooVal"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(containing.asymmetricMatch(["fooBar"], [tester])).toBe(true); expect(containing.asymmetricMatch(["fooBar"], matchersUtil)).toBe(true);
}); });
}); });

View File

@@ -1,8 +1,9 @@
describe("ArrayWithExactContents", function() { describe("ArrayWithExactContents", function() {
it("matches an array with the same items in a different order", function() { it("matches an array with the same items in a different order", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]); var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matcher.asymmetricMatch([2, 'a', /a/])).toBe(true); expect(matcher.asymmetricMatch([2, 'a', /a/], matchersUtil)).toBe(true);
}); });
it("does not work when not passed an array", function() { it("does not work when not passed an array", function() {
@@ -15,15 +16,17 @@ describe("ArrayWithExactContents", function() {
it("does not match when an item is missing", function() { it("does not match when an item is missing", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]); var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matcher.asymmetricMatch(['a', 2])).toBe(false); expect(matcher.asymmetricMatch(['a', 2], matchersUtil)).toBe(false);
expect(matcher.asymmetricMatch(['a', 2, undefined])).toBe(false); expect(matcher.asymmetricMatch(['a', 2, undefined], matchersUtil)).toBe(false);
}); });
it("does not match when there is an extra item", function() { it("does not match when there is an extra item", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a']); var matcher = new jasmineUnderTest.ArrayWithExactContents(['a']);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matcher.asymmetricMatch(['a', 2])).toBe(false); expect(matcher.asymmetricMatch(['a', 2], matchersUtil)).toBe(false);
}); });
it("jasmineToStrings itself", function() { it("jasmineToStrings itself", function() {
@@ -41,7 +44,8 @@ describe("ArrayWithExactContents", function() {
} }
}; };
var matcher = new jasmineUnderTest.ArrayWithExactContents(["fooVal"]); var matcher = new jasmineUnderTest.ArrayWithExactContents(["fooVal"]);
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(matcher.asymmetricMatch(["fooBar"], [tester])).toBe(true); expect(matcher.asymmetricMatch(["fooBar"], matchersUtil)).toBe(true);
}); });
}); });

View File

@@ -31,8 +31,9 @@ describe('MapContaining', function() {
['foo', [1, 2, 3]], ['foo', [1, 2, 3]],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(true); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true);
}); });
it('does not match when a key is not in actual', function() { it('does not match when a key is not in actual', function() {
@@ -46,8 +47,9 @@ describe('MapContaining', function() {
['foo', [1, 2, 3]], ['foo', [1, 2, 3]],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(false); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false);
}); });
it('does not match when a value is not in actual', function() { it('does not match when a value is not in actual', function() {
@@ -61,8 +63,9 @@ describe('MapContaining', function() {
['foo', [1, 2]], ['foo', [1, 2]],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(false); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false);
}); });
it('matches when all the key/value pairs in sample have asymmetric matches in actual', function() { it('matches when all the key/value pairs in sample have asymmetric matches in actual', function() {
@@ -74,17 +77,18 @@ describe('MapContaining', function() {
var containingMap = new MapI([ var containingMap = new MapI([
[ [
jasmine.stringMatching(/^foo\d/), jasmineUnderTest.stringMatching(/^foo\d/),
'bar' 'bar'
], ],
[ [
'baz', 'baz',
jasmine.arrayContaining([2, 3]) jasmineUnderTest.arrayContaining([2, 3])
], ],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(true); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true);
}); });
it('does not match when a key in sample has no asymmetric matches in actual', function() { it('does not match when a key in sample has no asymmetric matches in actual', function() {
@@ -95,17 +99,18 @@ describe('MapContaining', function() {
var containingMap = new MapI([ var containingMap = new MapI([
[ [
jasmine.stringMatching(/^foo\d/), jasmineUnderTest.stringMatching(/^foo\d/),
'bar' 'bar'
], ],
[ [
'baz', 'baz',
jasmine.arrayContaining([2, 3]) jasmineUnderTest.arrayContaining([2, 3])
], ],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(false); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false);
}); });
it('does not match when a value in sample has no asymmetric matches in actual', function() { it('does not match when a value in sample has no asymmetric matches in actual', function() {
@@ -116,17 +121,18 @@ describe('MapContaining', function() {
var containingMap = new MapI([ var containingMap = new MapI([
[ [
jasmine.stringMatching(/^foo\d/), jasmineUnderTest.stringMatching(/^foo\d/),
'bar' 'bar'
], ],
[ [
'baz', 'baz',
jasmine.arrayContaining([4, 5]) jasmineUnderTest.arrayContaining([4, 5])
], ],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(false); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(false);
}); });
it('matches recursively', function() { it('matches recursively', function() {
@@ -147,8 +153,9 @@ describe('MapContaining', function() {
], ],
]); ]);
var containing = new jasmineUnderTest.MapContaining(containingMap); var containing = new jasmineUnderTest.MapContaining(containingMap);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualMap)).toBe(true); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true);
}); });
it('uses custom equality testers', function() { it('uses custom equality testers', function() {
@@ -158,8 +165,9 @@ describe('MapContaining', function() {
} }
var actualMap = new MapI([['foo', -1]]); var actualMap = new MapI([['foo', -1]]);
var containing = new jasmineUnderTest.MapContaining(new MapI([['foo', -2]])); var containing = new jasmineUnderTest.MapContaining(new MapI([['foo', -2]]));
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(containing.asymmetricMatch(actualMap, [tester])).toBe(true); expect(containing.asymmetricMatch(actualMap, matchersUtil)).toBe(true);
}); });
it('does not match when actual is not a map', function() { it('does not match when actual is not a map', function() {

View File

@@ -2,8 +2,9 @@ describe("ObjectContaining", function() {
it("matches any actual to an empty object", function() { it("matches any actual to an empty object", function() {
var containing = new jasmineUnderTest.ObjectContaining({}); var containing = new jasmineUnderTest.ObjectContaining({});
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch("foo")).toBe(true); expect(containing.asymmetricMatch("foo", matchersUtil)).toBe(true);
}); });
it("does not match an empty object actual", function() { it("does not match an empty object actual", function() {
@@ -16,20 +17,23 @@ describe("ObjectContaining", function() {
it("matches when the key/value pair is present in the actual", function() { it("matches when the key/value pair is present in the actual", function() {
var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"}); var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"});
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({foo: "fooVal", bar: "barVal"})).toBe(true); expect(containing.asymmetricMatch({foo: "fooVal", bar: "barVal"}, matchersUtil)).toBe(true);
}); });
it("does not match when the key/value pair is not present in the actual", function() { it("does not match when the key/value pair is not present in the actual", function() {
var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"}); var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"});
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({bar: "barVal", quux: "quuxVal"})).toBe(false); expect(containing.asymmetricMatch({bar: "barVal", quux: "quuxVal"}, matchersUtil)).toBe(false);
}); });
it("does not match when the key is present but the value is different in the actual", function() { it("does not match when the key is present but the value is different in the actual", function() {
var containing = new jasmineUnderTest.ObjectContaining({foo: "other"}); var containing = new jasmineUnderTest.ObjectContaining({foo: "other"});
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({foo: "fooVal", bar: "barVal"})).toBe(false); expect(containing.asymmetricMatch({foo: "fooVal", bar: "barVal"}, matchersUtil)).toBe(false);
}); });
it("jasmineToString's itself", function() { it("jasmineToString's itself", function() {
@@ -40,34 +44,39 @@ describe("ObjectContaining", function() {
it("matches recursively", function() { it("matches recursively", function() {
var containing = new jasmineUnderTest.ObjectContaining({one: new jasmineUnderTest.ObjectContaining({two: {}})}); var containing = new jasmineUnderTest.ObjectContaining({one: new jasmineUnderTest.ObjectContaining({two: {}})});
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({one: {two: {}}})).toBe(true); expect(containing.asymmetricMatch({one: {two: {}}}, matchersUtil)).toBe(true);
}); });
it("matches when key is present with undefined value", function() { it("matches when key is present with undefined value", function() {
var containing = new jasmineUnderTest.ObjectContaining({ one: undefined }); var containing = new jasmineUnderTest.ObjectContaining({ one: undefined });
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({ one: undefined })).toBe(true); expect(containing.asymmetricMatch({ one: undefined }, matchersUtil)).toBe(true);
}); });
it("does not match when key with undefined value is not present", function() { it("does not match when key with undefined value is not present", function() {
var containing = new jasmineUnderTest.ObjectContaining({ one: undefined }); var containing = new jasmineUnderTest.ObjectContaining({ one: undefined });
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch({})).toBe(false); expect(containing.asymmetricMatch({}, matchersUtil)).toBe(false);
}); });
it("matches defined properties", function(){ it("matches defined properties", function(){
var containing = new jasmineUnderTest.ObjectContaining({ foo: "fooVal" }); var containing = new jasmineUnderTest.ObjectContaining({ foo: "fooVal" });
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var definedPropertyObject = {}; var definedPropertyObject = {};
Object.defineProperty(definedPropertyObject, "foo", { Object.defineProperty(definedPropertyObject, "foo", {
get: function() { return "fooVal" } get: function() { return "fooVal" }
}); });
expect(containing.asymmetricMatch(definedPropertyObject)).toBe(true); expect(containing.asymmetricMatch(definedPropertyObject, matchersUtil)).toBe(true);
}); });
it("matches prototype properties", function(){ it("matches prototype properties", function(){
var containing = new jasmineUnderTest.ObjectContaining({ foo: "fooVal" }); var containing = new jasmineUnderTest.ObjectContaining({ foo: "fooVal" });
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var prototypeObject = {foo: "fooVal"}; var prototypeObject = {foo: "fooVal"};
var obj; var obj;
@@ -81,7 +90,7 @@ describe("ObjectContaining", function() {
obj = new Foo(); obj = new Foo();
} }
expect(containing.asymmetricMatch(obj)).toBe(true); expect(containing.asymmetricMatch(obj, matchersUtil)).toBe(true);
}); });
it("uses custom equality testers", function() { it("uses custom equality testers", function() {
@@ -93,7 +102,8 @@ describe("ObjectContaining", function() {
} }
}; };
var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"}); var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"});
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(containing.asymmetricMatch({foo: "fooBar"}, [tester])).toBe(true); expect(containing.asymmetricMatch({foo: "fooBar"}, matchersUtil)).toBe(true);
}); });
}); });

View File

@@ -28,8 +28,9 @@ describe('SetContaining', function() {
[1, 2, 3], {'foo': 'bar'} [1, 2, 3], {'foo': 'bar'}
]); ]);
var containing = new jasmineUnderTest.SetContaining(containingSet); var containing = new jasmineUnderTest.SetContaining(containingSet);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualSet)).toBe(true); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true);
}); });
it('does not match when a value is not in actual', function() { it('does not match when a value is not in actual', function() {
@@ -41,8 +42,9 @@ describe('SetContaining', function() {
[1, 2], {'foo': 'bar'} [1, 2], {'foo': 'bar'}
]); ]);
var containing = new jasmineUnderTest.SetContaining(containingSet); var containing = new jasmineUnderTest.SetContaining(containingSet);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualSet)).toBe(false); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(false);
}); });
it('matches when all the values in sample have asymmetric matches in actual', function() { it('matches when all the values in sample have asymmetric matches in actual', function() {
@@ -51,12 +53,13 @@ describe('SetContaining', function() {
]); ]);
var containingSet = new SetI([ var containingSet = new SetI([
jasmine.stringMatching(/^foo\d/), jasmineUnderTest.stringMatching(/^foo\d/),
jasmine.arrayContaining([2, 3]), jasmineUnderTest.arrayContaining([2, 3]),
]); ]);
var containing = new jasmineUnderTest.SetContaining(containingSet); var containing = new jasmineUnderTest.SetContaining(containingSet);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualSet)).toBe(true); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true);
}); });
it('does not match when a value in sample has no asymmetric matches in actual', function() { it('does not match when a value in sample has no asymmetric matches in actual', function() {
@@ -69,8 +72,9 @@ describe('SetContaining', function() {
jasmine.arrayContaining([2, 3]), jasmine.arrayContaining([2, 3]),
]); ]);
var containing = new jasmineUnderTest.SetContaining(containingSet); var containing = new jasmineUnderTest.SetContaining(containingSet);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualSet)).toBe(false); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(false);
}); });
it('matches recursively', function() { it('matches recursively', function() {
@@ -82,8 +86,9 @@ describe('SetContaining', function() {
new jasmineUnderTest.SetContaining(new SetI(['bar'])), 'foo' new jasmineUnderTest.SetContaining(new SetI(['bar'])), 'foo'
]); ]);
var containing = new jasmineUnderTest.SetContaining(containingSet); var containing = new jasmineUnderTest.SetContaining(containingSet);
var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(containing.asymmetricMatch(actualSet)).toBe(true); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true);
}); });
it('uses custom equality testers', function() { it('uses custom equality testers', function() {
@@ -93,8 +98,9 @@ describe('SetContaining', function() {
} }
var actualSet = new SetI(['foo', -1]); var actualSet = new SetI(['foo', -1]);
var containing = new jasmineUnderTest.SetContaining(new SetI([-2, 'foo'])); var containing = new jasmineUnderTest.SetContaining(new SetI([-2, 'foo']));
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(containing.asymmetricMatch(actualSet, [tester])).toBe(true); expect(containing.asymmetricMatch(actualSet, matchersUtil)).toBe(true);
}); });
it('does not match when actual is not a set', function() { it('does not match when actual is not a set', function() {

View File

@@ -111,4 +111,36 @@ describe('Custom Async Matchers (Integration)', function() {
env.addReporter({ specDone: specExpectations, jasmineDone: done }); env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute(); env.execute();
}); });
it("provides custom equality testers to the matcher factory via matchersUtil", function(done) {
jasmine.getEnv().requirePromises();
var matcherFactory = function (matchersUtil) {
return {
compare: function (actual, expected) {
return Promise.resolve({pass: matchersUtil.equals(actual[0], expected)});
}
};
},
customEqualityFn = jasmine.createSpy("customEqualityFn").and.callFake(function (a, b) {
return a.toString() === b;
});
env.it("spec with expectation", function() {
env.addCustomEqualityTester(customEqualityFn);
env.addAsyncMatchers({
toBeArrayWithFirstElement: matcherFactory
});
return env.expectAsync([1, 2]).toBeArrayWithFirstElement("1");
});
var specExpectations = function(result) {
expect(customEqualityFn).toHaveBeenCalledWith(1, "1");
expect(result.failedExpectations).toEqual([]);
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
}); });

View File

@@ -1,19 +1,19 @@
describe("Custom Matchers (Integration)", function() { describe("Custom Matchers (Integration)", function () {
var env; var env;
var fakeTimer; var fakeTimer;
beforeEach(function() { beforeEach(function () {
env = new jasmineUnderTest.Env(); env = new jasmineUnderTest.Env();
env.configure({random: false}); env.configure({random: false});
}); });
it("allows adding more matchers local to a spec", function(done) { it("allows adding more matchers local to a spec", function (done) {
env.it('spec defining a custom matcher', function() { env.it('spec defining a custom matcher', function () {
env.addMatchers({ env.addMatchers({
matcherForSpec: function() { matcherForSpec: function () {
return { return {
compare: function(actual, expected) { compare: function (actual, expected) {
return { pass: false, message: "matcherForSpec: actual: " + actual + "; expected: " + expected }; return {pass: false, message: "matcherForSpec: actual: " + actual + "; expected: " + expected};
} }
} }
} }
@@ -83,6 +83,8 @@ describe("Custom Matchers (Integration)", function() {
it("supports asymmetric equality testers that take a list of custom equality testers", function(done) { it("supports asymmetric equality testers that take a list of custom equality testers", function(done) {
// TODO: remove this in the next major release. // TODO: remove this in the next major release.
spyOn(jasmineUnderTest, 'getEnv').and.returnValue(env);
env.it("spec using custom asymmetric equality tester", function() { env.it("spec using custom asymmetric equality tester", function() {
var customEqualityFn = function(a, b) { var customEqualityFn = function(a, b) {
if (a === 2 && b === "two") { if (a === 2 && b === "two") {
@@ -229,4 +231,34 @@ describe("Custom Matchers (Integration)", function() {
env.addReporter({ specDone: specExpectations, jasmineDone: done }); env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute(); env.execute();
}); });
it("provides custom equality testers to the matcher factory via matchersUtil", function (done) {
var matcherFactory = function (matchersUtil) {
return {
compare: function (actual, expected) {
return {pass: matchersUtil.equals(actual[0], expected)};
}
};
},
customEqualityFn = jasmine.createSpy("customEqualityFn").and.callFake(function (a, b) {
return a.toString() === b;
});
env.it("spec with expectation", function () {
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeArrayWithFirstElement: matcherFactory
});
env.expect([1, 2]).toBeArrayWithFirstElement("1");
});
var specExpectations = function (result) {
expect(customEqualityFn).toHaveBeenCalledWith(1, "1");
expect(result.failedExpectations).toEqual([]);
};
env.addReporter({specDone: specExpectations, jasmineDone: done});
env.execute();
});
}); });

View File

@@ -2149,7 +2149,7 @@ describe("Env integration", function() {
env.it('is a spec without any expectations', function() { env.it('is a spec without any expectations', function() {
// does nothing, just a mock spec without expectations // does nothing, just a mock spec without expectations
}); });
}); });
it('should report "failed" status if "failSpecWithNoExpectations" is enabled', function(done) { it('should report "failed" status if "failSpecWithNoExpectations" is enabled', function(done) {
@@ -2556,4 +2556,33 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
it("supports asymmetric equality testers that take a matchersUtil", function(done) {
var env = new jasmineUnderTest.Env();
env.it("spec using custom asymmetric equality tester", function() {
var customEqualityFn = function(a, b) {
if (a === 2 && b === "two") {
return true;
}
};
var arrayWithFirstElement = function(sample) {
return {
asymmetricMatch: function (actual, matchersUtil) {
return matchersUtil.equals(sample, actual[0]);
}
};
};
env.addCustomEqualityTester(customEqualityFn);
env.expect(["two"]).toEqual(arrayWithFirstElement(2));
});
var specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
}); });

View File

@@ -449,7 +449,10 @@ describe('Matchers (Integration)', function() {
describe('toThrow', function() { describe('toThrow', function() {
verifyPasses(function(env) { verifyPasses(function(env) {
env.expect(function() { throw new Error(); }).toThrow(); env.addCustomEqualityTester(function(a, b) {
return a.toString() === b.toString();
});
env.expect(function() { throw '5'; }).toThrow(5);
}); });
verifyFails(function(env) { verifyFails(function(env) {

View File

@@ -2,7 +2,8 @@ describe('toBeRejected', function() {
it('passes if the actual is rejected', function() { it('passes if the actual is rejected', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejected(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil),
actual = Promise.reject('AsyncExpectationSpec rejection'); actual = Promise.reject('AsyncExpectationSpec rejection');
return matcher.compare(actual).then(function(result) { return matcher.compare(actual).then(function(result) {
@@ -13,7 +14,8 @@ describe('toBeRejected', function() {
it('fails if the actual is resolved', function() { it('fails if the actual is resolved', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejected(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil),
actual = Promise.resolve(); actual = Promise.resolve();
return matcher.compare(actual).then(function(result) { return matcher.compare(actual).then(function(result) {
@@ -22,7 +24,8 @@ describe('toBeRejected', function() {
}); });
it('fails if actual is not a promise', function() { it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejected(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil),
actual = 'not a promise'; actual = 'not a promise';
function f() { function f() {

View File

@@ -2,7 +2,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error type matches', function () { it('passes when Error type matches', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new TypeError('foo')); actual = Promise.reject(new TypeError('foo'));
return matcher.compare(actual, TypeError).then(function (result) { return matcher.compare(actual, TypeError).then(function (result) {
@@ -16,7 +17,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error type and message matches', function () { it('passes when Error type and message matches', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new TypeError('foo')); actual = Promise.reject(new TypeError('foo'));
return matcher.compare(actual, TypeError, 'foo').then(function (result) { return matcher.compare(actual, TypeError, 'foo').then(function (result) {
@@ -30,7 +32,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error matches and is exactly Error', function() { it('passes when Error matches and is exactly Error', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error()); actual = Promise.reject(new Error());
return matcher.compare(actual, Error).then(function (result) { return matcher.compare(actual, Error).then(function (result) {
@@ -45,7 +48,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error message matches a string', function () { it('passes when Error message matches a string', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error('foo')); actual = Promise.reject(new Error('foo'));
return matcher.compare(actual, 'foo').then(function (result) { return matcher.compare(actual, 'foo').then(function (result) {
@@ -59,7 +63,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error message matches a RegExp', function () { it('passes when Error message matches a RegExp', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error('foo')); actual = Promise.reject(new Error('foo'));
return matcher.compare(actual, /foo/).then(function (result) { return matcher.compare(actual, /foo/).then(function (result) {
@@ -73,7 +78,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when Error message is empty', function () { it('passes when Error message is empty', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error()); actual = Promise.reject(new Error());
return matcher.compare(actual, '').then(function (result) { return matcher.compare(actual, '').then(function (result) {
@@ -87,7 +93,8 @@ describe('#toBeRejectedWithError', function () {
it('passes when no arguments', function () { it('passes when no arguments', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error()); actual = Promise.reject(new Error());
return matcher.compare(actual, void 0).then(function (result) { return matcher.compare(actual, void 0).then(function (result) {
@@ -101,7 +108,8 @@ describe('#toBeRejectedWithError', function () {
it('fails when resolved', function () { it('fails when resolved', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.resolve(new Error('foo')); actual = Promise.resolve(new Error('foo'));
return matcher.compare(actual, 'foo').then(function (result) { return matcher.compare(actual, 'foo').then(function (result) {
@@ -115,7 +123,8 @@ describe('#toBeRejectedWithError', function () {
it('fails when rejected with non Error type', function () { it('fails when rejected with non Error type', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject('foo'); actual = Promise.reject('foo');
return matcher.compare(actual, 'foo').then(function (result) { return matcher.compare(actual, 'foo').then(function (result) {
@@ -129,7 +138,8 @@ describe('#toBeRejectedWithError', function () {
it('fails when Error type mismatches', function () { it('fails when Error type mismatches', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error('foo')); actual = Promise.reject(new Error('foo'));
return matcher.compare(actual, TypeError, 'foo').then(function (result) { return matcher.compare(actual, TypeError, 'foo').then(function (result) {
@@ -143,7 +153,8 @@ describe('#toBeRejectedWithError', function () {
it('fails when Error message mismatches', function () { it('fails when Error message mismatches', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = Promise.reject(new Error('foo')); actual = Promise.reject(new Error('foo'));
return matcher.compare(actual, 'bar').then(function (result) { return matcher.compare(actual, 'bar').then(function (result) {
@@ -155,7 +166,8 @@ describe('#toBeRejectedWithError', function () {
}); });
it('fails if actual is not a promise', function() { it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(matchersUtil),
actual = 'not a promise'; actual = 'not a promise';
function f() { function f() {

View File

@@ -2,7 +2,8 @@ describe('#toBeRejectedWith', function () {
it('should return true if the promise is rejected with the expected value', function () { it('should return true if the promise is rejected with the expected value', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = Promise.reject({error: 'PEBCAK'}); actual = Promise.reject({error: 'PEBCAK'});
return matcher.compare(actual, {error: 'PEBCAK'}).then(function (result) { return matcher.compare(actual, {error: 'PEBCAK'}).then(function (result) {
@@ -13,7 +14,8 @@ describe('#toBeRejectedWith', function () {
it('should fail if the promise resolves', function () { it('should fail if the promise resolves', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = Promise.resolve(); actual = Promise.resolve();
return matcher.compare(actual, '').then(function (result) { return matcher.compare(actual, '').then(function (result) {
@@ -24,7 +26,8 @@ describe('#toBeRejectedWith', function () {
it('should fail if the promise is rejected with a different value', function () { it('should fail if the promise is rejected with a different value', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = Promise.reject('A Bad Apple'); actual = Promise.reject('A Bad Apple');
return matcher.compare(actual, 'Some Cool Thing').then(function (result) { return matcher.compare(actual, 'Some Cool Thing').then(function (result) {
@@ -38,7 +41,8 @@ describe('#toBeRejectedWith', function () {
it('should build its error correctly when negated', function () { it('should build its error correctly when negated', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = Promise.reject(true); actual = Promise.reject(true);
return matcher.compare(actual, true).then(function (result) { return matcher.compare(actual, true).then(function (result) {
@@ -53,7 +57,8 @@ describe('#toBeRejectedWith', function () {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var customEqualityTesters = [function() { return true; }], var customEqualityTesters = [function() { return true; }],
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil, customEqualityTesters), matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: customEqualityTesters}),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = Promise.reject('actual'); actual = Promise.reject('actual');
return matcher.compare(actual, 'expected').then(function(result) { return matcher.compare(actual, 'expected').then(function(result) {
@@ -62,7 +67,8 @@ describe('#toBeRejectedWith', function () {
}); });
it('fails if actual is not a promise', function() { it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil),
actual = 'not a promise'; actual = 'not a promise';
function f() { function f() {

View File

@@ -2,7 +2,8 @@ describe('toBeResolved', function() {
it('passes if the actual is resolved', function() { it('passes if the actual is resolved', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolved(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil),
actual = Promise.resolve(); actual = Promise.resolve();
return matcher.compare(actual).then(function(result) { return matcher.compare(actual).then(function(result) {
@@ -13,7 +14,8 @@ describe('toBeResolved', function() {
it('fails if the actual is rejected', function() { it('fails if the actual is rejected', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolved(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil),
actual = Promise.reject('AsyncExpectationSpec rejection'); actual = Promise.reject('AsyncExpectationSpec rejection');
return matcher.compare(actual).then(function(result) { return matcher.compare(actual).then(function(result) {
@@ -22,7 +24,8 @@ describe('toBeResolved', function() {
}); });
it('fails if actual is not a promise', function() { it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeResolved(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil),
actual = 'not a promise'; actual = 'not a promise';
function f() { function f() {

View File

@@ -2,7 +2,8 @@ describe('#toBeResolvedTo', function() {
it('passes if the promise is resolved to the expected value', function() { it('passes if the promise is resolved to the expected value', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.resolve({foo: 42}); actual = Promise.resolve({foo: 42});
return matcher.compare(actual, {foo: 42}).then(function(result) { return matcher.compare(actual, {foo: 42}).then(function(result) {
@@ -13,7 +14,8 @@ describe('#toBeResolvedTo', function() {
it('fails if the promise is rejected', function() { it('fails if the promise is rejected', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.reject('AsyncExpectationSpec error'); actual = Promise.reject('AsyncExpectationSpec error');
return matcher.compare(actual, '').then(function(result) { return matcher.compare(actual, '').then(function(result) {
@@ -27,7 +29,8 @@ describe('#toBeResolvedTo', function() {
it('fails if the promise is resolved to a different value', function() { it('fails if the promise is resolved to a different value', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.resolve({foo: 17}); actual = Promise.resolve({foo: 17});
return matcher.compare(actual, {foo: 42}).then(function(result) { return matcher.compare(actual, {foo: 42}).then(function(result) {
@@ -41,7 +44,8 @@ describe('#toBeResolvedTo', function() {
it('builds its message correctly when negated', function() { it('builds its message correctly when negated', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.resolve(true); actual = Promise.resolve(true);
return matcher.compare(actual, true).then(function(result) { return matcher.compare(actual, true).then(function(result) {
@@ -56,7 +60,8 @@ describe('#toBeResolvedTo', function() {
jasmine.getEnv().requirePromises(); jasmine.getEnv().requirePromises();
var customEqualityTesters = [function() { return true; }], var customEqualityTesters = [function() { return true; }],
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil, customEqualityTesters), matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: customEqualityTesters}),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = Promise.resolve('actual'); actual = Promise.resolve('actual');
return matcher.compare(actual, 'expected').then(function(result) { return matcher.compare(actual, 'expected').then(function(result) {
@@ -65,7 +70,8 @@ describe('#toBeResolvedTo', function() {
}); });
it('fails if actual is not a promise', function() { it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil), var matchersUtil = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil),
actual = 'not a promise'; actual = 'not a promise';
function f() { function f() {

View File

@@ -1,178 +1,210 @@
describe("matchersUtil", function() { describe("matchersUtil", function() {
describe("equals", function() { describe("equals", function() {
it("passes for literals that are triple-equal", function() { it("passes for literals that are triple-equal", function() {
expect(jasmineUnderTest.matchersUtil.equals(null, null)).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(void 0, void 0)).toBe(true); expect(matchersUtil.equals(null, null)).toBe(true);
expect(matchersUtil.equals(void 0, void 0)).toBe(true);
}); });
it("fails for things that are not equivalent", function() { it("fails for things that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals({a: "foo"}, 1)).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({a: "foo"}, 1)).toBe(false);
}); });
it("passes for Strings that are equivalent", function() { it("passes for Strings that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals("foo", "foo")).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals("foo", "foo")).toBe(true);
}); });
it("fails for Strings that are not equivalent", function() { it("fails for Strings that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals("foo", "bar")).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals("foo", "bar")).toBe(false);
}); });
it("passes for Numbers that are equivalent", function() { it("passes for Numbers that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(123, 123)).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(123, 123)).toBe(true);
}); });
it("fails for Numbers that are not equivalent", function() { it("fails for Numbers that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(123, 456)).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(123, 456)).toBe(false);
}); });
it("passes for Dates that are equivalent", function() { it("passes for Dates that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Jan 1, 1970"))).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Jan 1, 1970"))).toBe(true);
}); });
it("fails for Dates that are not equivalent", function() { it("fails for Dates that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Feb 3, 1991"))).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Date("Jan 1, 1970"), new Date("Feb 3, 1991"))).toBe(false);
}); });
it("passes for Booleans that are equivalent", function() { it("passes for Booleans that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(true, true)).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(true, true)).toBe(true);
}); });
it("fails for Booleans that are not equivalent", function() { it("fails for Booleans that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(true, false)).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(true, false)).toBe(false);
}); });
it("passes for RegExps that are equivalent", function() { it("passes for RegExps that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(/foo/, /foo/)).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(/foo/, /foo/)).toBe(true);
}); });
it("fails for RegExps that are not equivalent", function() { it("fails for RegExps that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals(/foo/, /bar/)).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(new RegExp("foo", "i"), new RegExp("foo"))).toBe(false); expect(matchersUtil.equals(/foo/, /bar/)).toBe(false);
expect(matchersUtil.equals(new RegExp("foo", "i"), new RegExp("foo"))).toBe(false);
}); });
it("passes for Arrays that are equivalent", function() { it("passes for Arrays that are equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2])).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals([1, 2], [1, 2])).toBe(true);
}); });
it("passes for Arrays that are equivalent, with elements added by changing length", function() { it("passes for Arrays that are equivalent, with elements added by changing length", function() {
var foo = []; var foo = [],
matchersUtil = new jasmineUnderTest.MatchersUtil();
foo.length = 1; foo.length = 1;
expect(jasmineUnderTest.matchersUtil.equals(foo, [undefined])).toBe(true); expect(matchersUtil.equals(foo, [undefined])).toBe(true);
}); });
it("fails for Arrays that have different lengths", function() { it("fails for Arrays that have different lengths", function() {
expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false);
}); });
it("fails for Arrays that have different elements", function() { it("fails for Arrays that have different elements", function() {
expect(jasmineUnderTest.matchersUtil.equals([1, 2, 3], [1, 5, 3])).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals([1, 2, 3], [1, 5, 3])).toBe(false);
}); });
it("fails for Arrays whose contents are equivalent, but have differing properties", function() { it("fails for Arrays whose contents are equivalent, but have differing properties", function() {
var one = [1,2,3], var one = [1,2,3],
two = [1,2,3]; two = [1,2,3],
matchersUtil = new jasmineUnderTest.MatchersUtil();
one.foo = 'bar'; one.foo = 'bar';
two.foo = 'baz'; two.foo = 'baz';
expect(jasmineUnderTest.matchersUtil.equals(one, two)).toBe(false); expect(matchersUtil.equals(one, two)).toBe(false);
}); });
it("passes for Arrays with equivalent contents and properties", function() { it("passes for Arrays with equivalent contents and properties", function() {
var one = [1,2,3], var one = [1,2,3],
two = [1,2,3]; two = [1,2,3],
matchersUtil = new jasmineUnderTest.MatchersUtil();
one.foo = 'bar'; one.foo = 'bar';
two.foo = 'bar'; two.foo = 'bar';
expect(jasmineUnderTest.matchersUtil.equals(one, two)).toBe(true); expect(matchersUtil.equals(one, two)).toBe(true);
}); });
it("passes for Errors that are the same type and have the same message", function() { it("passes for Errors that are the same type and have the same message", function() {
expect(jasmineUnderTest.matchersUtil.equals(new Error("foo"), new Error("foo"))).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Error("foo"), new Error("foo"))).toBe(true);
}); });
it("fails for Errors that are the same type and have different messages", function() { it("fails for Errors that are the same type and have different messages", function() {
expect(jasmineUnderTest.matchersUtil.equals(new Error("foo"), new Error("bar"))).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Error("foo"), new Error("bar"))).toBe(false);
}); });
it("fails for objects with different constructors", function() { it("fails for objects with different constructors", function() {
var matchersUtil = new jasmineUnderTest.MatchersUtil();
function One() {} function One() {}
function Two() {} function Two() {}
expect(jasmineUnderTest.matchersUtil.equals(new One(), new Two())).toBe(false); expect(matchersUtil.equals(new One(), new Two())).toBe(false);
}); });
it("passes for Objects that are equivalent (simple case)", function() { it("passes for Objects that are equivalent (simple case)", function() {
expect(jasmineUnderTest.matchersUtil.equals({a: "foo"}, {a: "foo"})).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({a: "foo"}, {a: "foo"})).toBe(true);
}); });
it("fails for Objects that are not equivalent (simple case)", function() { it("fails for Objects that are not equivalent (simple case)", function() {
expect(jasmineUnderTest.matchersUtil.equals({a: "foo"}, {a: "bar"})).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({a: "foo"}, {a: "bar"})).toBe(false);
}); });
it("passes for Objects that are equivalent (deep case)", function() { it("passes for Objects that are equivalent (deep case)", function() {
expect(jasmineUnderTest.matchersUtil.equals({a: "foo", b: { c: "bar"}}, {a: "foo", b: { c: "bar"}})).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({a: "foo", b: { c: "bar"}}, {a: "foo", b: { c: "bar"}})).toBe(true);
}); });
it("fails for Objects that are not equivalent (deep case)", function() { it("fails for Objects that are not equivalent (deep case)", function() {
expect(jasmineUnderTest.matchersUtil.equals({a: "foo", b: { c: "baz"}}, {a: "foo", b: { c: "bar"}})).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({a: "foo", b: { c: "baz"}}, {a: "foo", b: { c: "bar"}})).toBe(false);
}); });
it("passes for Objects that are equivalent (with cycles)", function() { it("passes for Objects that are equivalent (with cycles)", function() {
var actual = { a: "foo" }, var actual = { a: "foo" },
expected = { a: "foo" }; expected = { a: "foo" },
matchersUtil = new jasmineUnderTest.MatchersUtil();
actual.b = actual; actual.b = actual;
expected.b = actual; expected.b = actual;
expect(jasmineUnderTest.matchersUtil.equals(actual, expected)).toBe(true); expect(matchersUtil.equals(actual, expected)).toBe(true);
}); });
it("fails for Objects that are not equivalent (with cycles)", function() { it("fails for Objects that are not equivalent (with cycles)", function() {
var actual = { a: "foo" }, var actual = { a: "foo" },
expected = { a: "bar" }; expected = { a: "bar" },
matchersUtil = new jasmineUnderTest.MatchersUtil();
actual.b = actual; actual.b = actual;
expected.b = actual; expected.b = actual;
expect(jasmineUnderTest.matchersUtil.equals(actual, expected)).toBe(false); expect(matchersUtil.equals(actual, expected)).toBe(false);
}); });
it("fails for Objects that have the same number of keys, but different keys/values", function () { it("fails for Objects that have the same number of keys, but different keys/values", function () {
var expected = { a: undefined }, var expected = { a: undefined },
actual = { b: 1 }; actual = { b: 1 },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(actual, expected)).toBe(false); expect(matchersUtil.equals(actual, expected)).toBe(false);
}); });
it("fails when comparing an empty object to an empty array (issue #114)", function() { it("fails when comparing an empty object to an empty array (issue #114)", function() {
var emptyObject = {}, var emptyObject = {},
emptyArray = []; emptyArray = [],
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(emptyObject, emptyArray)).toBe(false);
expect(jasmineUnderTest.matchersUtil.equals(emptyArray, emptyObject)).toBe(false); expect(matchersUtil.equals(emptyObject, emptyArray)).toBe(false);
expect(matchersUtil.equals(emptyArray, emptyObject)).toBe(false);
}); });
it("passes for equivalent frozen objects (GitHub issue #266)", function() { it("passes for equivalent frozen objects (GitHub issue #266)", function() {
var a = { foo: 1 }, var a = { foo: 1 },
b = {foo: 1 }; b = {foo: 1 },
matchersUtil = new jasmineUnderTest.MatchersUtil();
Object.freeze(a); Object.freeze(a);
Object.freeze(b); Object.freeze(b);
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true); expect(matchersUtil.equals(a,b)).toBe(true);
}); });
it("passes for equivalent Promises (GitHub issue #1314)", function() { it("passes for equivalent Promises (GitHub issue #1314)", function() {
if (typeof Promise === 'undefined') { return; } if (typeof Promise === 'undefined') { return; }
var p1 = new Promise(function () {}), var p1 = new Promise(function () {}),
p2 = new Promise(function () {}); p2 = new Promise(function () {}),
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(p1, p1)).toBe(true); expect(matchersUtil.equals(p1, p1)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(p1, p2)).toBe(false); expect(matchersUtil.equals(p1, p2)).toBe(false);
}); });
describe("when running in a browser", function() { describe("when running in a browser", function() {
@@ -185,6 +217,8 @@ describe("matchersUtil", function() {
return; return;
} }
var a = document.createElement("div"); var a = document.createElement("div");
var matchersUtil = new jasmineUnderTest.MatchersUtil();
a.setAttribute("test-attr", "attr-value"); a.setAttribute("test-attr", "attr-value");
a.appendChild(document.createTextNode('test')); a.appendChild(document.createTextNode('test'));
@@ -192,17 +226,18 @@ describe("matchersUtil", function() {
b.setAttribute("test-attr", "attr-value"); b.setAttribute("test-attr", "attr-value");
b.appendChild(document.createTextNode('test')); b.appendChild(document.createTextNode('test'));
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true); expect(matchersUtil.equals(a,b)).toBe(true);
}); });
it("passes for equivalent objects from different frames", function() { it("passes for equivalent objects from different frames", function() {
if (isNotRunningInBrowser()) { if (isNotRunningInBrowser()) {
return; return;
} }
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var iframe = document.createElement('iframe'); var iframe = document.createElement('iframe');
document.body.appendChild(iframe); document.body.appendChild(iframe);
iframe.contentWindow.eval('window.testObject = {}'); iframe.contentWindow.eval('window.testObject = {}');
expect(jasmineUnderTest.matchersUtil.equals({}, iframe.contentWindow.testObject)).toBe(true); expect(matchersUtil.equals({}, iframe.contentWindow.testObject)).toBe(true);
document.body.removeChild(iframe); document.body.removeChild(iframe);
}); });
@@ -210,6 +245,7 @@ describe("matchersUtil", function() {
if (isNotRunningInBrowser()) { if (isNotRunningInBrowser()) {
return; return;
} }
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var a = document.createElement("div"); var a = document.createElement("div");
a.setAttribute("test-attr", "attr-value"); a.setAttribute("test-attr", "attr-value");
a.appendChild(document.createTextNode('test')); a.appendChild(document.createTextNode('test'));
@@ -218,16 +254,16 @@ describe("matchersUtil", function() {
b.setAttribute("test-attr", "attr-value2"); b.setAttribute("test-attr", "attr-value2");
b.appendChild(document.createTextNode('test')); b.appendChild(document.createTextNode('test'));
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(false); expect(matchersUtil.equals(a,b)).toBe(false);
b.setAttribute("test-attr", "attr-value"); b.setAttribute("test-attr", "attr-value");
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true); expect(matchersUtil.equals(a,b)).toBe(true);
b.appendChild(document.createTextNode('2')); b.appendChild(document.createTextNode('2'));
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(false); expect(matchersUtil.equals(a,b)).toBe(false);
a.appendChild(document.createTextNode('2')); a.appendChild(document.createTextNode('2'));
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true); expect(matchersUtil.equals(a,b)).toBe(true);
}); });
}); });
@@ -240,43 +276,47 @@ describe("matchersUtil", function() {
if (isNotRunningInNode()) { if (isNotRunningInNode()) {
return; return;
} }
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var vm = require('vm'); var vm = require('vm');
var sandbox = { var sandbox = {
obj: null obj: null
}; };
vm.runInNewContext('obj = {a: 1, b: 2}', sandbox); vm.runInNewContext('obj = {a: 1, b: 2}', sandbox);
expect(jasmineUnderTest.matchersUtil.equals(sandbox.obj, {a: 1, b: 2})).toBe(true); expect(matchersUtil.equals(sandbox.obj, {a: 1, b: 2})).toBe(true);
}); });
it("passes for equivalent arrays from different vm contexts", function() { it("passes for equivalent arrays from different vm contexts", function() {
if (isNotRunningInNode()) { if (isNotRunningInNode()) {
return; return;
} }
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var vm = require('vm'); var vm = require('vm');
var sandbox = { var sandbox = {
arr: null arr: null
}; };
vm.runInNewContext('arr = [1, 2]', sandbox); vm.runInNewContext('arr = [1, 2]', sandbox);
expect(jasmineUnderTest.matchersUtil.equals(sandbox.arr, [1, 2])).toBe(true); expect(matchersUtil.equals(sandbox.arr, [1, 2])).toBe(true);
}); });
}); });
it("passes when Any is used", function() { it("passes when Any is used", function() {
var number = 3, var number = 3,
anyNumber = new jasmineUnderTest.Any(Number); anyNumber = new jasmineUnderTest.Any(Number),
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(number, anyNumber)).toBe(true); expect(matchersUtil.equals(number, anyNumber)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(anyNumber, number)).toBe(true); expect(matchersUtil.equals(anyNumber, number)).toBe(true);
}); });
it("fails when Any is compared to something unexpected", function() { it("fails when Any is compared to something unexpected", function() {
var number = 3, var number = 3,
anyString = new jasmineUnderTest.Any(String); anyString = new jasmineUnderTest.Any(String),
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(number, anyString)).toBe(false); expect(matchersUtil.equals(number, anyString)).toBe(false);
expect(jasmineUnderTest.matchersUtil.equals(anyString, number)).toBe(false); expect(matchersUtil.equals(anyString, number)).toBe(false);
}); });
it("passes when ObjectContaining is used", function() { it("passes when ObjectContaining is used", function() {
@@ -284,135 +324,209 @@ describe("matchersUtil", function() {
foo: 3, foo: 3,
bar: 7 bar: 7
}, },
containing = new jasmineUnderTest.ObjectContaining({foo: 3}); containing = new jasmineUnderTest.ObjectContaining({foo: 3}),
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(obj, containing)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(containing, obj)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true);
}); });
it("passes when MapContaining is used", function() { it("passes when MapContaining is used", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var obj = new Map(); var obj = new Map();
obj.set(1, 2); obj.set(1, 2);
obj.set('foo', 'bar'); obj.set('foo', 'bar');
var containing = new jasmineUnderTest.MapContaining(new Map()); var containing = new jasmineUnderTest.MapContaining(new Map());
containing.sample.set('foo', 'bar'); containing.sample.set('foo', 'bar');
expect(jasmineUnderTest.matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(obj, containing)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(containing, obj)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true);
}); });
it("passes when SetContaining is used", function() { it("passes when SetContaining is used", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var obj = new Set(); var obj = new Set();
obj.add(1); obj.add(1);
obj.add('foo'); obj.add('foo');
var containing = new jasmineUnderTest.SetContaining(new Set()); var containing = new jasmineUnderTest.SetContaining(new Set());
containing.sample.add(1); containing.sample.add(1);
expect(jasmineUnderTest.matchersUtil.equals(obj, containing)).toBe(true); expect(matchersUtil.equals(obj, containing)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(containing, obj)).toBe(true); expect(matchersUtil.equals(containing, obj)).toBe(true);
}); });
it("passes when an asymmetric equality tester returns true", function() { it("passes when an asymmetric equality tester returns true", function() {
var tester = { asymmetricMatch: function(other) { return true; } }; var tester = { asymmetricMatch: function(other) { return true; } },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(false, tester)).toBe(true); expect(matchersUtil.equals(false, tester)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(tester, false)).toBe(true); expect(matchersUtil.equals(tester, false)).toBe(true);
}); });
it("fails when an asymmetric equality tester returns false", function() { it("fails when an asymmetric equality tester returns false", function() {
var tester = { asymmetricMatch: function(other) { return false; } }; var tester = { asymmetricMatch: function(other) { return false; } },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(true, tester)).toBe(false); expect(matchersUtil.equals(true, tester)).toBe(false);
expect(jasmineUnderTest.matchersUtil.equals(tester, true)).toBe(false); expect(matchersUtil.equals(tester, true)).toBe(false);
}); });
it("passes when ArrayContaining is used", function() { it("passes when ArrayContaining is used", function() {
var arr = ["foo", "bar"]; var arr = ["foo", "bar"],
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(arr, new jasmineUnderTest.ArrayContaining(["bar"]))).toBe(true); expect(matchersUtil.equals(arr, new jasmineUnderTest.ArrayContaining(["bar"]))).toBe(true);
}); });
it("passes when a custom equality matcher returns true", function() { it("passes when a custom equality matcher passed to equals returns true", function() {
var tester = function(a, b) { return true; }; // TODO: remove this in the next major release.
var tester = function(a, b) { return true; },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(1, 2, [tester])).toBe(true); expect(matchersUtil.equals(1, 2, [tester])).toBe(true);
});
it("passes when a custom equality matcher passed to the constructor returns true", function() {
var tester = function(a, b) { return true; },
matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(matchersUtil.equals(1, 2)).toBe(true);
}); });
it("passes for two empty Objects", function () { it("passes for two empty Objects", function () {
expect(jasmineUnderTest.matchersUtil.equals({}, {})).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({}, {})).toBe(true);
}); });
describe("when a custom equality matcher is installed that returns 'undefined'", function () { describe("when a custom equality matcher is passed to equals that returns 'undefined'", function () {
// TODO: remove this in the next major release.
var tester = function(a, b) { return jasmine.undefined; }; var tester = function(a, b) { return jasmine.undefined; };
it("passes for two empty Objects", function () { it("passes for two empty Objects", function () {
expect(jasmineUnderTest.matchersUtil.equals({}, {}, [tester])).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals({}, {}, [tester])).toBe(true);
}); });
}); });
it("fails for equivalents when a custom equality matcher returns false", function() { describe("when a custom equality matcher is passed to the constructor that returns 'undefined'", function () {
var tester = function(a, b) { return false; }; var tester = function(a, b) { return jasmine.undefined; };
expect(jasmineUnderTest.matchersUtil.equals(1, 1, [tester])).toBe(false); it("passes for two empty Objects", function () {
var matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(matchersUtil.equals({}, {})).toBe(true);
});
}); });
it("passes for an asymmetric equality tester that returns true when a custom equality tester return false", function() { it("fails for equivalents when a custom equality matcher passed to equals returns false", function() {
// TODO: remove this in the next major release.
var tester = function(a, b) { return false; },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(1, 1, [tester])).toBe(false);
});
it("fails for equivalents when a custom equality matcher passed to the constructor returns false", function() {
var tester = function(a, b) { return false; },
matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]});
expect(matchersUtil.equals(1, 1)).toBe(false);
});
it("passes for an asymmetric equality tester that returns true when a custom equality tester passed to equals return false", function() {
// TODO: remove this in the next major release.
var asymmetricTester = { asymmetricMatch: function(other) { return true; } }, var asymmetricTester = { asymmetricMatch: function(other) { return true; } },
symmetricTester = function(a, b) { return false; }; symmetricTester = function(a, b) { return false; },
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(asymmetricTester, true, [symmetricTester])).toBe(true); expect(matchersUtil.equals(asymmetricTester, true, [symmetricTester])).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(true, asymmetricTester, [symmetricTester])).toBe(true); expect(matchersUtil.equals(true, asymmetricTester, [symmetricTester])).toBe(true);
}); });
it("passes custom equality matchers to asymmetric equality testers", function() { it("passes for an asymmetric equality tester that returns true when a custom equality tester passed to the constructor return false", function() {
var tester = function(a, b) {}; var asymmetricTester = { asymmetricMatch: function(other) { return true; } },
var asymmetricTester = { asymmetricMatch: jasmine.createSpy('asymmetricMatch') }; symmetricTester = function(a, b) { return false; },
asymmetricTester.asymmetricMatch.and.returnValue(true); matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [symmetricTester()]});
var other = {};
expect(jasmineUnderTest.matchersUtil.equals(asymmetricTester, other, [tester])).toBe(true); expect(matchersUtil.equals(asymmetricTester, true)).toBe(true);
expect(asymmetricTester.asymmetricMatch).toHaveBeenCalledWith(other, [tester]); expect(matchersUtil.equals(true, asymmetricTester)).toBe(true);
});
describe("The compatibility shim passed to asymmetric equality testers", function() {
describe("When equals is called with custom equality testers", function() {
it("is both a matchersUtil and the custom equality testers passed to equals", function() {
var asymmetricTester = jasmine.createSpyObj('tester', ['asymmetricMatch']),
symmetricTester = function() { } ,
matchersUtil = new jasmineUnderTest.MatchersUtil(),
shim;
matchersUtil.equals(true, asymmetricTester, [symmetricTester]);
shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1];
expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil));
expect(shim.length).toEqual(1);
expect(shim[0]).toEqual(symmetricTester);
});
});
describe("When equals is called with custom equality testers", function() {
it("is both a matchersUtil and the custom equality testers passed to the constructor", function() {
var asymmetricTester = jasmine.createSpyObj('tester', ['asymmetricMatch']),
symmetricTester = function() { } ,
matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [symmetricTester]}),
shim;
matchersUtil.equals(true, asymmetricTester);
shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1];
expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil));
expect(shim.length).toEqual(1);
expect(shim[0]).toEqual(symmetricTester);
});
});
}); });
it("passes when an Any is compared to an Any that checks for the same type", function() { it("passes when an Any is compared to an Any that checks for the same type", function() {
var any1 = new jasmineUnderTest.Any(Function), var any1 = new jasmineUnderTest.Any(Function),
any2 = new jasmineUnderTest.Any(Function); any2 = new jasmineUnderTest.Any(Function),
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.equals(any1, any2)).toBe(true); expect(matchersUtil.equals(any1, any2)).toBe(true);
}); });
it("passes for null prototype objects with same properties", function () { it("passes for null prototype objects with same properties", function () {
var objA = Object.create(null), var objA = Object.create(null),
objB = Object.create(null); objB = Object.create(null),
matchersUtil = new jasmineUnderTest.MatchersUtil();
objA.name = 'test'; objA.name = 'test';
objB.name = 'test'; objB.name = 'test';
expect(jasmineUnderTest.matchersUtil.equals(objA, objB)).toBe(true); expect(matchersUtil.equals(objA, objB)).toBe(true);
}); });
it("fails for null prototype objects with different properties", function () { it("fails for null prototype objects with different properties", function () {
var objA = Object.create(null), var objA = Object.create(null),
objB = Object.create(null); objB = Object.create(null),
matchersUtil = new jasmineUnderTest.MatchersUtil();
objA.name = 'test'; objA.name = 'test';
objB.test = 'name'; objB.test = 'name';
expect(jasmineUnderTest.matchersUtil.equals(objA, objB)).toBe(false); expect(matchersUtil.equals(objA, objB)).toBe(false);
}); });
it("passes when comparing two empty sets", function() { it("passes when comparing two empty sets", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
expect(jasmineUnderTest.matchersUtil.equals(new Set(), new Set())).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Set(), new Set())).toBe(true);
}); });
it("passes when comparing identical sets", function() { it("passes when comparing identical sets", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA = new Set(); var setA = new Set();
setA.add(6); setA.add(6);
setA.add(5); setA.add(5);
@@ -420,12 +534,13 @@ describe("matchersUtil", function() {
setB.add(6); setB.add(6);
setB.add(5); setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true); expect(matchersUtil.equals(setA, setB)).toBe(true);
}); });
it("passes when comparing identical sets with different insertion order and simple elements", function() { it("passes when comparing identical sets with different insertion order and simple elements", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA = new Set(); var setA = new Set();
setA.add(3); setA.add(3);
setA.add(6); setA.add(6);
@@ -433,12 +548,13 @@ describe("matchersUtil", function() {
setB.add(6); setB.add(6);
setB.add(3); setB.add(3);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true); expect(matchersUtil.equals(setA, setB)).toBe(true);
}); });
it("passes when comparing identical sets with different insertion order and complex elements 1", function() { it("passes when comparing identical sets with different insertion order and complex elements 1", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA1 = new Set(); var setA1 = new Set();
setA1.add(['a',3]); setA1.add(['a',3]);
setA1.add([6,1]); setA1.add([6,1]);
@@ -460,12 +576,13 @@ describe("matchersUtil", function() {
setB.add(setB1); setB.add(setB1);
setB.add(setB2); setB.add(setB2);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true); expect(matchersUtil.equals(setA, setB)).toBe(true);
}); });
it("passes when comparing identical sets with different insertion order and complex elements 2", function() { it("passes when comparing identical sets with different insertion order and complex elements 2", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA = new Set(); var setA = new Set();
setA.add([[1,2], [3,4]]); setA.add([[1,2], [3,4]]);
setA.add([[5,6], [7,8]]); setA.add([[5,6], [7,8]]);
@@ -473,11 +590,12 @@ describe("matchersUtil", function() {
setB.add([[5,6], [7,8]]); setB.add([[5,6], [7,8]]);
setB.add([[1,2], [3,4]]); setB.add([[1,2], [3,4]]);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true); expect(matchersUtil.equals(setA, setB)).toBe(true);
}); });
it("fails for sets with different elements", function() { it("fails for sets with different elements", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA = new Set(); var setA = new Set();
setA.add(6); setA.add(6);
setA.add(3); setA.add(3);
@@ -487,11 +605,12 @@ describe("matchersUtil", function() {
setB.add(4); setB.add(4);
setB.add(5); setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false); expect(matchersUtil.equals(setA, setB)).toBe(false);
}); });
it("fails for sets of different size", function() { it("fails for sets of different size", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setA = new Set(); var setA = new Set();
setA.add(6); setA.add(6);
setA.add(3); setA.add(3);
@@ -500,36 +619,40 @@ describe("matchersUtil", function() {
setB.add(4); setB.add(4);
setB.add(5); setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false); expect(matchersUtil.equals(setA, setB)).toBe(false);
}); });
it("passes when comparing two empty maps", function() { it("passes when comparing two empty maps", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
expect(jasmineUnderTest.matchersUtil.equals(new Map(), new Map())).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.equals(new Map(), new Map())).toBe(true);
}); });
it("passes when comparing identical maps", function() { it("passes when comparing identical maps", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var mapA = new Map(); var mapA = new Map();
mapA.set(6, 5); mapA.set(6, 5);
var mapB = new Map(); var mapB = new Map();
mapB.set(6, 5); mapB.set(6, 5);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(true); expect(matchersUtil.equals(mapA, mapB)).toBe(true);
}); });
it("passes when comparing identical maps with different insertion order", function() { it("passes when comparing identical maps with different insertion order", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var mapA = new Map(); var mapA = new Map();
mapA.set("a", 3); mapA.set("a", 3);
mapA.set(6, 1); mapA.set(6, 1);
var mapB = new Map(); var mapB = new Map();
mapB.set(6, 1); mapB.set(6, 1);
mapB.set("a", 3); mapB.set("a", 3);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(true); expect(matchersUtil.equals(mapA, mapB)).toBe(true);
}); });
it("fails for maps with different elements", function() { it("fails for maps with different elements", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var mapA = new Map(); var mapA = new Map();
mapA.set(6, 3); mapA.set(6, 3);
mapA.set(5, 1); mapA.set(5, 1);
@@ -537,17 +660,18 @@ describe("matchersUtil", function() {
mapB.set(6, 4); mapB.set(6, 4);
mapB.set(5, 1); mapB.set(5, 1);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false); expect(matchersUtil.equals(mapA, mapB)).toBe(false);
}); });
it("fails for maps of different size", function() { it("fails for maps of different size", function() {
jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningMaps();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var mapA = new Map(); var mapA = new Map();
mapA.set(6, 3); mapA.set(6, 3);
var mapB = new Map(); var mapB = new Map();
mapB.set(6, 4); mapB.set(6, 4);
mapB.set(5, 1); mapB.set(5, 1);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false); expect(matchersUtil.equals(mapA, mapB)).toBe(false);
}); });
describe("when running in an environment with array polyfills", function() { describe("when running in an environment with array polyfills", function() {
@@ -593,71 +717,119 @@ describe("matchersUtil", function() {
expect(['foo']).toEqual(['foo']); expect(['foo']).toEqual(['foo']);
}); });
}); });
it('uses a diffBuilder if one is provided as the fourth argument', function() {
// TODO: remove this in the next major release.
var diffBuilder = new jasmineUnderTest.DiffBuilder(),
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(diffBuilder, 'record');
spyOn(diffBuilder, 'withPath').and.callThrough();
matchersUtil.equals([1], [2], [], diffBuilder);
expect(diffBuilder.withPath).toHaveBeenCalledWith('length', jasmine.any(Function));
expect(diffBuilder.withPath).toHaveBeenCalledWith(0, jasmine.any(Function));
expect(diffBuilder.record).toHaveBeenCalledWith(1, 2);
});
it('uses a diffBuilder if one is provided as the third argument', function() {
var diffBuilder = new jasmineUnderTest.DiffBuilder(),
matchersUtil = new jasmineUnderTest.MatchersUtil();
spyOn(diffBuilder, 'record');
spyOn(diffBuilder, 'withPath').and.callThrough();
matchersUtil.equals([1], [2], diffBuilder);
expect(diffBuilder.withPath).toHaveBeenCalledWith('length', jasmine.any(Function));
expect(diffBuilder.withPath).toHaveBeenCalledWith(0, jasmine.any(Function));
expect(diffBuilder.record).toHaveBeenCalledWith(1, 2);
});
}); });
describe("contains", function() { describe("contains", function() {
it("passes when expected is a substring of actual", function() { it("passes when expected is a substring of actual", function() {
expect(jasmineUnderTest.matchersUtil.contains("ABC", "BC")).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains("ABC", "BC")).toBe(true);
}); });
it("fails when expected is a not substring of actual", function() { it("fails when expected is a not substring of actual", function() {
expect(jasmineUnderTest.matchersUtil.contains("ABC", "X")).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains("ABC", "X")).toBe(false);
}); });
it("passes when expected is an element in an actual array", function() { it("passes when expected is an element in an actual array", function() {
expect(jasmineUnderTest.matchersUtil.contains(['foo', 'bar'], 'foo')).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains(['foo', 'bar'], 'foo')).toBe(true);
}); });
it("fails when expected is not an element in an actual array", function() { it("fails when expected is not an element in an actual array", function() {
expect(jasmineUnderTest.matchersUtil.contains(['foo', 'bar'], 'baz')).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains(['foo', 'bar'], 'baz')).toBe(false);
}); });
it("passes with mixed-element arrays", function() { it("passes with mixed-element arrays", function() {
expect(jasmineUnderTest.matchersUtil.contains(["foo", {some: "bar"}], "foo")).toBe(true); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.contains(["foo", {some: "bar"}], {some: "bar"})).toBe(true); expect(matchersUtil.contains(["foo", {some: "bar"}], "foo")).toBe(true);
expect(matchersUtil.contains(["foo", {some: "bar"}], {some: "bar"})).toBe(true);
}); });
it("uses custom equality testers if passed in and actual is an Array", function() { it("uses custom equality testers if passed to contains and actual is an Array", function() {
var customTester = function(a, b) {return true;}; // TODO: remove this in the next major release.
var customTester = function(a, b) {return true;},
matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(jasmineUnderTest.matchersUtil.contains([1, 2], 3, [customTester])).toBe(true); expect(matchersUtil.contains([1, 2], 3, [customTester])).toBe(true);
});
it("uses custom equality testers if passed to the constructor and actual is an Array", function() {
var customTester = function(a, b) {return true;},
matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [customTester]});
expect(matchersUtil.contains([1, 2], 3)).toBe(true);
}); });
it("fails when actual is undefined", function() { it("fails when actual is undefined", function() {
expect(jasmineUnderTest.matchersUtil.contains(undefined, 'A')).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains(undefined, 'A')).toBe(false);
}); });
it("fails when actual is null", function() { it("fails when actual is null", function() {
expect(jasmineUnderTest.matchersUtil.contains(null, 'A')).toBe(false); var matchersUtil = new jasmineUnderTest.MatchersUtil();
expect(matchersUtil.contains(null, 'A')).toBe(false);
}); });
it("passes with array-like objects", function() { it("passes with array-like objects", function() {
var capturedArgs = null; var capturedArgs = null,
matchersUtil = new jasmineUnderTest.MatchersUtil();
function testFunction(){ function testFunction(){
capturedArgs = arguments; capturedArgs = arguments;
} }
testFunction('foo', 'bar'); testFunction('foo', 'bar');
expect(jasmineUnderTest.matchersUtil.contains(capturedArgs, 'bar')).toBe(true); expect(matchersUtil.contains(capturedArgs, 'bar')).toBe(true);
}); });
it("passes for set members", function() { it("passes for set members", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var setItem = {'foo': 'bar'}; var setItem = {'foo': 'bar'};
var set = new Set(); var set = new Set();
set.add(setItem); set.add(setItem);
expect(jasmineUnderTest.matchersUtil.contains(set, setItem)).toBe(true); expect(matchersUtil.contains(set, setItem)).toBe(true);
}); });
// documenting current behavior // documenting current behavior
it("fails (!) for objects that equal to a set member", function() { it("fails (!) for objects that equal to a set member", function() {
jasmine.getEnv().requireFunctioningSets(); jasmine.getEnv().requireFunctioningSets();
var matchersUtil = new jasmineUnderTest.MatchersUtil();
var set = new Set(); var set = new Set();
set.add({'foo': 'bar'}); set.add({'foo': 'bar'});
expect(jasmineUnderTest.matchersUtil.contains(set, {'foo': 'bar'})).toBe(false); expect(matchersUtil.contains(set, {'foo': 'bar'})).toBe(false);
}); });
}); });
@@ -666,7 +838,8 @@ describe("matchersUtil", function() {
it("builds an English sentence for a failure case", function() { it("builds an English sentence for a failure case", function() {
var actual = "foo", var actual = "foo",
name = "toBar", name = "toBar",
message = jasmineUnderTest.matchersUtil.buildFailureMessage(name, false, actual); matchersUtil = new jasmineUnderTest.MatchersUtil(),
message = matchersUtil.buildFailureMessage(name, false, actual);
expect(message).toEqual("Expected 'foo' to bar."); expect(message).toEqual("Expected 'foo' to bar.");
}); });
@@ -675,7 +848,8 @@ describe("matchersUtil", function() {
var actual = "foo", var actual = "foo",
name = "toBar", name = "toBar",
isNot = true, isNot = true,
message = message = jasmineUnderTest.matchersUtil.buildFailureMessage(name, isNot, actual); matchersUtil = new jasmineUnderTest.MatchersUtil(),
message = message = matchersUtil.buildFailureMessage(name, isNot, actual);
expect(message).toEqual("Expected 'foo' not to bar."); expect(message).toEqual("Expected 'foo' not to bar.");
}); });
@@ -683,7 +857,8 @@ describe("matchersUtil", function() {
it("builds an English sentence for an arbitrary array of expected arguments", function() { it("builds an English sentence for an arbitrary array of expected arguments", function() {
var actual = "foo", var actual = "foo",
name = "toBar", name = "toBar",
message = jasmineUnderTest.matchersUtil.buildFailureMessage(name, false, actual, "quux", "corge"); matchersUtil = new jasmineUnderTest.MatchersUtil(),
message = matchersUtil.buildFailureMessage(name, false, actual, "quux", "corge");
expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'."); expect(message).toEqual("Expected 'foo' to bar 'quux', 'corge'.");
}); });

View File

@@ -1,6 +1,7 @@
describe("toBe", function() { describe("toBe", function() {
it("passes with no message when actual === expected", function() { it("passes with no message when actual === expected", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result; result;
result = matcher.compare(1, 1); result = matcher.compare(1, 1);
@@ -8,7 +9,8 @@ describe("toBe", function() {
}); });
it("passes with a custom message when expected is an array", function() { it("passes with a custom message when expected is an array", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result, result,
array = [1]; array = [1];
@@ -18,7 +20,8 @@ describe("toBe", function() {
}); });
it("passes with a custom message when expected is an object", function() { it("passes with a custom message when expected is an object", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result, result,
obj = {foo: "bar"}; obj = {foo: "bar"};
@@ -28,7 +31,8 @@ describe("toBe", function() {
}); });
it("fails with no message when actual !== expected", function() { it("fails with no message when actual !== expected", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result; result;
result = matcher.compare(1, 2); result = matcher.compare(1, 2);
@@ -37,7 +41,8 @@ describe("toBe", function() {
}); });
it("fails with a custom message when expected is an array", function() { it("fails with a custom message when expected is an array", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result; result;
result = matcher.compare([1], [1]); result = matcher.compare([1], [1]);
@@ -46,7 +51,8 @@ describe("toBe", function() {
}); });
it("fails with a custom message when expected is an object", function() { it("fails with a custom message when expected is an object", function() {
var matcher = jasmineUnderTest.matchers.toBe(jasmineUnderTest.matchersUtil), var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toBe(util),
result; result;
result = matcher.compare({foo: "bar"}, {foo: "bar"}); result = matcher.compare({foo: "bar"}, {foo: "bar"});

View File

@@ -7,20 +7,19 @@ describe("toContain", function() {
result; result;
result = matcher.compare("ABC", "B"); result = matcher.compare("ABC", "B");
expect(util.contains).toHaveBeenCalledWith("ABC", "B", []); expect(util.contains).toHaveBeenCalledWith("ABC", "B");
expect(result.pass).toBe(true); expect(result.pass).toBe(true);
}); });
it("delegates to jasmineUnderTest.matchersUtil.contains, passing in equality testers if present", function() { it("works with custom equality testers", function() {
var util = { var tester = function (a, b) {
contains: jasmine.createSpy('delegated-contains').and.returnValue(true) return a.toString() === b.toString();
}, },
customEqualityTesters = ['a', 'b'], matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: [tester]}),
matcher = jasmineUnderTest.matchers.toContain(util, customEqualityTesters), matcher = jasmineUnderTest.matchers.toContain(matchersUtil),
result; result;
result = matcher.compare("ABC", "B"); result = matcher.compare(['1', '2'], 2);
expect(util.contains).toHaveBeenCalledWith("ABC", "B", ['a', 'b']);
expect(result.pass).toBe(true); expect(result.pass).toBe(true);
}); });
}); });

View File

@@ -2,7 +2,7 @@ describe("toEqual", function() {
"use strict"; "use strict";
function compareEquals(actual, expected) { function compareEquals(actual, expected) {
var util = jasmineUnderTest.matchersUtil, var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toEqual(util); matcher = jasmineUnderTest.matchers.toEqual(util);
var result = matcher.compare(actual, expected); var result = matcher.compare(actual, expected);
@@ -16,32 +16,27 @@ describe("toEqual", function() {
buildFailureMessage: function() { buildFailureMessage: function() {
return 'does not matter' return 'does not matter'
}, },
DiffBuilder: jasmineUnderTest.matchersUtil.DiffBuilder DiffBuilder: new jasmineUnderTest.DiffBuilder()
}, },
matcher = jasmineUnderTest.matchers.toEqual(util), matcher = jasmineUnderTest.matchers.toEqual(util),
result; result;
result = matcher.compare(1, 1); result = matcher.compare(1, 1);
expect(util.equals).toHaveBeenCalledWith(1, 1, [], jasmine.anything()); expect(util.equals).toHaveBeenCalledWith(1, 1, jasmine.anything());
expect(result.pass).toBe(true); expect(result.pass).toBe(true);
}); });
it("delegates custom equality testers, if present", function() { it("works with custom equality testers", function() {
var util = { var tester = function (a, b) {
equals: jasmine.createSpy('delegated-equals').and.returnValue(true), return a.toString() === b.toString();
buildFailureMessage: function() {
return 'does not matter'
},
DiffBuilder: jasmineUnderTest.matchersUtil.DiffBuilder
}, },
customEqualityTesters = ['a', 'b'], util = new jasmineUnderTest.MatchersUtil({customTesters: [tester]}),
matcher = jasmineUnderTest.matchers.toEqual(util, customEqualityTesters), matcher = jasmineUnderTest.matchers.toEqual(util),
result; result;
result = matcher.compare(1, 1); result = matcher.compare(1, '1');
expect(util.equals).toHaveBeenCalledWith(1, 1, ['a', 'b'], jasmine.anything());
expect(result.pass).toBe(true); expect(result.pass).toBe(true);
}); });

View File

@@ -15,18 +15,16 @@ describe("toHaveBeenCalledWith", function() {
expect(result.message()).toEqual("Expected spy called-spy not to have been called with:\n [ 'a', 'b' ]\nbut it was."); expect(result.message()).toEqual("Expected spy called-spy not to have been called with:\n [ 'a', 'b' ]\nbut it was.");
}); });
it("passes through the custom equality testers", function() { it("supports custom equality testers", function() {
var util = { var customEqualityTesters = [function() { return true; }],
contains: jasmine.createSpy('delegated-contains').and.returnValue(true) matchersUtil = new jasmineUnderTest.MatchersUtil({customTesters: customEqualityTesters}),
}, matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(matchersUtil),
customEqualityTesters = [function() { return true; }], calledSpy = new jasmineUnderTest.Env().createSpy('called-spy'),
matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(util, customEqualityTesters), result;
calledSpy = new jasmineUnderTest.Env().createSpy('called-spy');
calledSpy('a', 'b'); calledSpy('a', 'b');
matcher.compare(calledSpy, 'a', 'b'); result = matcher.compare(calledSpy, 'a', 'b');
expect(result.pass).toBe(true);
expect(util.contains).toHaveBeenCalledWith([['a', 'b']], ['a', 'b'], customEqualityTesters);
}); });
it("fails when the actual was not called", function() { it("fails when the actual was not called", function() {
@@ -43,7 +41,7 @@ describe("toHaveBeenCalledWith", function() {
}); });
it("fails when the actual was called with different parameters", function() { it("fails when the actual was called with different parameters", function() {
var util = jasmineUnderTest.matchersUtil, var util = new jasmineUnderTest.MatchersUtil(),
matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(util), matcher = jasmineUnderTest.matchers.toHaveBeenCalledWith(util),
calledSpy = new jasmineUnderTest.Env().createSpy('called spy'), calledSpy = new jasmineUnderTest.Env().createSpy('called spy'),
result; result;

View File

@@ -1,10 +1,7 @@
(function(env) { (function(env) {
env.registerIntegrationMatchers = function() { env.registerIntegrationMatchers = function() {
jasmine.addMatchers({ jasmine.addMatchers({
toHaveFailedExpectationsForRunnable: function( toHaveFailedExpectationsForRunnable: function(util) {
util,
customeEqualityTesters
) {
return { return {
compare: function(actual, fullName, expectedFailures) { compare: function(actual, fullName, expectedFailures) {
var foundRunnable = false, var foundRunnable = false,

View File

@@ -23,7 +23,7 @@ describe('npm package', function() {
beforeEach(function() { beforeEach(function() {
jasmine.addMatchers({ jasmine.addMatchers({
toExistInPath: function(util, customEquality) { toExistInPath: function(util) {
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
var fullPath = path.resolve(expected, actual); var fullPath = path.resolve(expected, actual);

View File

@@ -276,6 +276,7 @@ getJasmineRequireObj().Env = function(j$) {
} }
var customMatchers = var customMatchers =
runnableResources[currentRunnable().id].customMatchers; runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) { for (var matcherName in matchersToAdd) {
customMatchers[matcherName] = matchersToAdd[matcherName]; customMatchers[matcherName] = matchersToAdd[matcherName];
} }
@@ -289,6 +290,7 @@ getJasmineRequireObj().Env = function(j$) {
} }
var customAsyncMatchers = var customAsyncMatchers =
runnableResources[currentRunnable().id].customAsyncMatchers; runnableResources[currentRunnable().id].customAsyncMatchers;
for (var matcherName in matchersToAdd) { for (var matcherName in matchersToAdd) {
customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
} }
@@ -308,9 +310,12 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var expectationFactory = function(actual, spec) { var expectationFactory = function(actual, spec) {
var customEqualityTesters =
runnableResources[spec.id].customEqualityTesters;
return j$.Expectation.factory({ return j$.Expectation.factory({
util: j$.matchersUtil, util: new j$.MatchersUtil({ customTesters: customEqualityTesters }),
customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customEqualityTesters: customEqualityTesters,
customMatchers: runnableResources[spec.id].customMatchers, customMatchers: runnableResources[spec.id].customMatchers,
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
@@ -322,8 +327,11 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var asyncExpectationFactory = function(actual, spec) { var asyncExpectationFactory = function(actual, spec) {
var customEqualityTesters =
runnableResources[spec.id].customEqualityTesters;
return j$.Expectation.asyncFactory({ return j$.Expectation.asyncFactory({
util: j$.matchersUtil, util: new j$.MatchersUtil({ customTesters: customEqualityTesters }),
customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
actual: actual, actual: actual,

View File

@@ -7,6 +7,8 @@ getJasmineRequireObj().Spy = function(j$) {
}; };
})(); })();
var matchersUtil = new j$.MatchersUtil();
/** /**
* _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj} * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
* @constructor * @constructor
@@ -202,7 +204,7 @@ getJasmineRequireObj().Spy = function(j$) {
var i; var i;
for (i = 0; i < this.strategies.length; i++) { for (i = 0; i < this.strategies.length; i++) {
if (j$.matchersUtil.equals(args, this.strategies[i].args)) { if (matchersUtil.equals(args, this.strategies[i].args)) {
return this.strategies[i].strategy; return this.strategies[i].strategy;
} }
} }

View File

@@ -0,0 +1,105 @@
getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
/*
Older versions of Jasmine passed an array of custom equality testers as the
second argument to each asymmetric equality tester's `asymmetricMatch`
method. Newer versions will pass a `MatchersUtil` instance. The
asymmetricEqualityTesterArgCompatShim allows for a graceful migration from
the old interface to the new by "being" both an array of custom equality
testers and a `MatchersUtil` at the same time.
This code should be removed in the next major release.
*/
var likelyArrayProps = [
'concat',
'constructor',
'copyWithin',
'entries',
'every',
'fill',
'filter',
'find',
'findIndex',
'flat',
'flatMap',
'forEach',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf',
'length',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toSource',
'toString',
'unshift',
'values'
];
function asymmetricEqualityTesterArgCompatShim(
matchersUtil,
customEqualityTesters
) {
var self = Object.create(matchersUtil),
props,
i,
k;
copy(self, customEqualityTesters, 'length');
for (i = 0; i < customEqualityTesters.length; i++) {
copy(self, customEqualityTesters, i);
}
var props = arrayProps();
for (i = 0; i < props.length; i++) {
k = props[i];
if (k !== 'length') {
copy(self, Array.prototype, k);
}
}
return self;
}
function copy(dest, src, propName) {
Object.defineProperty(dest, propName, {
get: function() {
return src[propName];
}
});
}
function arrayProps() {
var props, a, k;
if (!Object.getOwnPropertyDescriptors) {
return likelyArrayProps.filter(function(k) {
return Array.prototype.hasOwnProperty(k);
});
}
props = Object.getOwnPropertyDescriptors(Array.prototype);
a = [];
for (k in props) {
a.push(k);
}
return a;
}
return asymmetricEqualityTesterArgCompatShim;
};

View File

@@ -3,7 +3,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) { ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isArray_(this.sample)) { if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.'); throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
} }
@@ -17,7 +17,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
for (var i = 0; i < this.sample.length; i++) { for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i]; var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) { if (!matchersUtil.contains(other, item)) {
return false; return false;
} }
} }

View File

@@ -4,7 +4,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
this.sample = sample; this.sample = sample;
} }
ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) { ArrayWithExactContents.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isArray_(this.sample)) { if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.'); throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
} }
@@ -15,7 +15,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
for (var i = 0; i < this.sample.length; i++) { for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i]; var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) { if (!matchersUtil.contains(other, item)) {
return false; return false;
} }
} }

View File

@@ -7,7 +7,7 @@ getJasmineRequireObj().MapContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
MapContaining.prototype.asymmetricMatch = function(other, customTesters) { MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isMap(other)) return false; if (!j$.isMap(other)) return false;
var hasAllMatches = true; var hasAllMatches = true;
@@ -17,8 +17,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
var hasMatch = false; var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) { j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
if ( if (
j$.matchersUtil.equals(oKey, key, customTesters) matchersUtil.equals(oKey, key)
&& j$.matchersUtil.equals(oValue, value, customTesters) && matchersUtil.equals(oValue, value)
) { ) {
hasMatch = true; hasMatch = true;
oBreakLoop(); oBreakLoop();

View File

@@ -28,12 +28,12 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
return hasProperty(getPrototype(obj), property); return hasProperty(getPrototype(obj), property);
} }
ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) { ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); } if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
for (var property in this.sample) { for (var property in this.sample) {
if (!hasProperty(other, property) || if (!hasProperty(other, property) ||
!j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) { !matchersUtil.equals(this.sample[property], other[property])) {
return false; return false;
} }
} }

View File

@@ -7,17 +7,17 @@ getJasmineRequireObj().SetContaining = function(j$) {
this.sample = sample; this.sample = sample;
} }
SetContaining.prototype.asymmetricMatch = function(other, customTesters) { SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isSet(other)) return false; if (!j$.isSet(other)) return false;
var hasAllMatches = true; var hasAllMatches = true;
j$.util.forEachBreakable(this.sample, function(breakLoop, item) { j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
// for each item in `sample` there should be at least one matching item in `other` // for each item in `sample` there should be at least one matching item in `other`
// (not using `j$.matchersUtil.contains` because it compares set members by reference, // (not using `matchersUtil.contains` because it compares set members by reference,
// not by deep value equality) // not by deep value equality)
var hasMatch = false; var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oItem) { j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
if (j$.matchersUtil.equals(oItem, item, customTesters)) { if (matchersUtil.equals(oItem, item)) {
hasMatch = true; hasMatch = true;
oBreakLoop(); oBreakLoop();
} }

View File

@@ -11,7 +11,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
* @example * @example
* return expectAsync(aPromise).toBeRejectedWith({prop: 'value'}); * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
*/ */
return function toBeRejectedWith(util, customEqualityTesters) { return function toBeRejectedWith(util) {
return { return {
compare: function(actualPromise, expectedValue) { compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) { if (!j$.isPromiseLike(actualPromise)) {
@@ -32,7 +32,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
}; };
}, },
function(actualValue) { function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) { if (util.equals(actualValue, expectedValue)) {
return { return {
pass: true, pass: true,
message: prefix(true) + '.' message: prefix(true) + '.'

View File

@@ -11,7 +11,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
* @example * @example
* return expectAsync(aPromise).toBeResolvedTo({prop: 'value'}); * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
*/ */
return function toBeResolvedTo(util, customEqualityTesters) { return function toBeResolvedTo(util) {
return { return {
compare: function(actualPromise, expectedValue) { compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) { if (!j$.isPromiseLike(actualPromise)) {
@@ -26,7 +26,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
return actualPromise.then( return actualPromise.then(
function(actualValue) { function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) { if (util.equals(actualValue, expectedValue)) {
return { return {
pass: true, pass: true,
message: prefix(true) + '.' message: prefix(true) + '.'

View File

@@ -1,63 +1,67 @@
getJasmineRequireObj().matchersUtil = function(j$) { getJasmineRequireObj().MatchersUtil = function(j$) {
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
return { function MatchersUtil(options) {
equals: equals, options = options || {};
this.customTesters_ = options.customTesters || [];
contains: function(haystack, needle, customTesters) { if (!j$.isArray_(this.customTesters_)) {
customTesters = customTesters || []; throw new Error("MatchersUtil requires custom equality testers");
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (equals(haystack[i], needle, customTesters)) {
return true;
}
}
return false;
}
return !!haystack && haystack.indexOf(needle) >= 0;
},
buildFailureMessage: function() {
var args = Array.prototype.slice.call(arguments, 0),
matcherName = args[0],
isNot = args[1],
actual = args[2],
expected = args.slice(3),
englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
var message = 'Expected ' +
j$.pp(actual) +
(isNot ? ' not ' : ' ') +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + j$.pp(expected[i]);
}
}
return message + '.';
} }
}
MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (this.equals(haystack[i], needle, customTesters)) {
return true;
}
}
return false;
}
return !!haystack && haystack.indexOf(needle) >= 0;
};
MatchersUtil.prototype.buildFailureMessage = function() {
var args = Array.prototype.slice.call(arguments, 0),
matcherName = args[0],
isNot = args[1],
actual = args[2],
expected = args.slice(3),
englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
var message = 'Expected ' +
j$.pp(actual) +
(isNot ? ' not ' : ' ') +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + j$.pp(expected[i]);
}
}
return message + '.';
}; };
function isAsymmetric(obj) { function isAsymmetric(obj) {
return obj && j$.isA_('Function', obj.asymmetricMatch); return obj && j$.isA_('Function', obj.asymmetricMatch);
} }
function asymmetricMatch(a, b, customTesters, diffBuilder) { MatchersUtil.prototype.asymmetricMatch_ = function(a, b, customTesters, diffBuilder) {
var asymmetricA = isAsymmetric(a), var asymmetricA = isAsymmetric(a),
asymmetricB = isAsymmetric(b), asymmetricB = isAsymmetric(b),
shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters),
result; result;
if (asymmetricA && asymmetricB) { if (asymmetricA && asymmetricB) {
@@ -65,7 +69,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
if (asymmetricA) { if (asymmetricA) {
result = a.asymmetricMatch(b, customTesters); result = a.asymmetricMatch(b, shim);
if (!result) { if (!result) {
diffBuilder.record(a, b); diffBuilder.record(a, b);
} }
@@ -73,27 +77,36 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
if (asymmetricB) { if (asymmetricB) {
result = b.asymmetricMatch(a, customTesters); result = b.asymmetricMatch(a, shim);
if (!result) { if (!result) {
diffBuilder.record(a, b); diffBuilder.record(a, b);
} }
return result; return result;
} }
} };
function equals(a, b, customTesters, diffBuilder) { MatchersUtil.prototype.equals = function(a, b, customTestersOrDiffBuilder, diffBuilderOrNothing) {
customTesters = customTesters || []; var customTesters, diffBuilder;
if (isDiffBuilder(customTestersOrDiffBuilder)) {
diffBuilder = customTestersOrDiffBuilder;
} else {
customTesters = customTestersOrDiffBuilder;
diffBuilder = diffBuilderOrNothing;
}
customTesters = customTesters || this.customTesters_;
diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder = diffBuilder || j$.NullDiffBuilder();
return eq(a, b, [], [], customTesters, diffBuilder); return this.eq_(a, b, [], [], customTesters, diffBuilder);
} };
// Equality function lovingly adapted from isEqual in // Equality function lovingly adapted from isEqual in
// [Underscore](http://underscorejs.org) // [Underscore](http://underscorejs.org)
function eq(a, b, aStack, bStack, customTesters, diffBuilder) { MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, customTesters, diffBuilder) {
var result = true, i; var result = true, self = this, i;
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder); var asymmetricResult = this.asymmetricMatch_(a, b, customTesters, diffBuilder);
if (!j$.util.isUndefined(asymmetricResult)) { if (!j$.util.isUndefined(asymmetricResult)) {
return asymmetricResult; return asymmetricResult;
} }
@@ -230,7 +243,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter); diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
result = false; result = false;
} else { } else {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result; result = self.eq_(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
} }
}); });
} }
@@ -271,12 +284,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// otherwise explicitly look up the mapKey in the other Map since we want keys with unique // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
// obj identity (that are otherwise equal) to not match. // obj identity (that are otherwise equal) to not match.
if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) && if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
mapValueB = b.get(cmpKey); mapValueB = b.get(cmpKey);
} else { } else {
mapValueB = b.get(mapKey); mapValueB = b.get(mapKey);
} }
result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder()); result = this.eq_(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
} }
} }
@@ -320,7 +333,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
otherValue = otherValues[l]; otherValue = otherValues[l];
prevStackSize = baseStack.length; prevStackSize = baseStack.length;
// compare by value equality // compare by value equality
found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder()); found = this.eq_(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
if (!found && prevStackSize !== baseStack.length) { if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize); baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize); otherStack.splice(prevStackSize);
@@ -369,7 +382,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
diffBuilder.withPath(key, function() { diffBuilder.withPath(key, function() {
if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) { if(!self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
result = false; result = false;
} }
}); });
@@ -384,7 +397,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
bStack.pop(); bStack.pop();
return result; return result;
} };
function keys(obj, isArray) { function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) : var allKeys = Object.keys ? Object.keys(obj) :
@@ -467,4 +480,10 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
return formatted; return formatted;
} }
function isDiffBuilder(obj) {
return obj && typeof obj.record === 'function';
}
return MatchersUtil;
}; };

View File

@@ -12,7 +12,7 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) {
* expect(3).toBeInstanceOf(Number); * expect(3).toBeInstanceOf(Number);
* expect(new Error()).toBeInstanceOf(Error); * expect(new Error()).toBeInstanceOf(Error);
*/ */
function toBeInstanceOf(util, customEqualityTesters) { function toBeInstanceOf() {
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual), var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual),

View File

@@ -9,14 +9,12 @@ getJasmineRequireObj().toContain = function() {
* expect(array).toContain(anElement); * expect(array).toContain(anElement);
* expect(string).toContain(substring); * expect(string).toContain(substring);
*/ */
function toContain(util, customEqualityTesters) { function toContain(util) {
customEqualityTesters = customEqualityTesters || [];
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
return { return {
pass: util.contains(actual, expected, customEqualityTesters) pass: util.contains(actual, expected)
}; };
} }
}; };

View File

@@ -8,9 +8,7 @@ getJasmineRequireObj().toEqual = function(j$) {
* @example * @example
* expect(bigObject).toEqual({"foo": ['bar', 'baz']}); * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
*/ */
function toEqual(util, customEqualityTesters) { function toEqual(util) {
customEqualityTesters = customEqualityTesters || [];
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
var result = { var result = {
@@ -18,7 +16,7 @@ getJasmineRequireObj().toEqual = function(j$) {
}, },
diffBuilder = j$.DiffBuilder(); diffBuilder = j$.DiffBuilder();
result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder); result.pass = util.equals(actual, expected, diffBuilder);
// TODO: only set error message if test fails // TODO: only set error message if test fails
result.message = diffBuilder.getMessage(); result.message = diffBuilder.getMessage();

View File

@@ -11,7 +11,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
* @example * @example
* expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2); * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
*/ */
function toHaveBeenCalledWith(util, customEqualityTesters) { function toHaveBeenCalledWith(util) {
return { return {
compare: function() { compare: function() {
var args = Array.prototype.slice.call(arguments, 0), var args = Array.prototype.slice.call(arguments, 0),
@@ -32,7 +32,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
return result; return result;
} }
if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) { if (util.contains(actual.calls.allArgs(), expectedArgs)) {
result.pass = true; result.pass = true;
result.message = function() { result.message = function() {
return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' + return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' +
@@ -47,7 +47,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) { var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) {
var diffBuilder = new j$.DiffBuilder(); var diffBuilder = new j$.DiffBuilder();
util.equals(argsForCall, expectedArgs, customEqualityTesters, diffBuilder); util.equals(argsForCall, expectedArgs, diffBuilder);
return 'Call ' + callIx + ':\n' + return 'Call ' + callIx + ':\n' +
diffBuilder.getMessage().replace(/^/mg, ' '); diffBuilder.getMessage().replace(/^/mg, ' ');
}); });

View File

@@ -10,7 +10,7 @@ getJasmineRequireObj().toHaveClass = function(j$) {
* el.className = 'foo bar baz'; * el.className = 'foo bar baz';
* expect(el).toHaveClass('bar'); * expect(el).toHaveClass('bar');
*/ */
function toHaveClass(util, customEqualityTesters) { function toHaveClass() {
return { return {
compare: function(actual, expected) { compare: function(actual, expected) {
if (!isElement(actual)) { if (!isElement(actual)) {

View File

@@ -51,7 +51,12 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.buildExpectationResult = jRequire.buildExpectationResult(); j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.noopTimer = jRequire.noopTimer(); j$.noopTimer = jRequire.noopTimer();
j$.JsApiReporter = jRequire.JsApiReporter(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$);
j$.matchersUtil = jRequire.matchersUtil(j$); j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim(
j$
);
j$.MatchersUtil = jRequire.MatchersUtil(j$);
j$.matchersUtil = new j$.MatchersUtil({ customTesters: [] });
j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$);
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);