Provide better diffs for object graphs that include objectContaining
Turns this output:
Expected $[0].foo = Object({ a: 4, b: 5 }) to equal <jasmine.objectContaining(Object({ a: 1, c: 3 }))>.
into this:
Expected $[0].foo.a = 4 to equal 1.
Expected $[0].foo.c = undefined to equal 3.
And turns this output:
Expected spy jasmineDone to have been called with:
[ ... snipped very long expected call ]
but actual calls were:
[ ... snipped very long actual call ]
Call 0:
Expected $[0] = Object({ overallStatus: 'failed', totalTime: 1, incompleteReason: undefined, order: Order({ random: true, seed: '88732', sort: Function }), failedExpectations: [ Object({ matcherName: 'toBeResolved', passed: false, message: 'Suite "a suite" ran a "toBeResolved" expectation after it finished.
Did you forget to return or await the result of expectAsync?', error: undefined, errorForStack: Error, actual: [object Promise], expected: [ ], globalErrorType: 'lateExpeztation' }) ], deprecationWarnings: [ ] }) to equal <jasmine.objectContaining(Object({ failedExpectations: [ <jasmine.objectContaining(Object({ passed: false, globalErrorType: 'lateExpectation', message: 'Suite "a suite" ran a "toBeResolved" expectation after it finished.
Did you forget to return or await the result of expectAsync?', matcherName: 'toBeResolved' }))> ] }))>.
into this:
Expected spy jasmineDone to have been called with:
[ ... snipped very long expected call ]
but actual calls were:
[ ... snipped very long actual call ]
Call 0:
Expected $[0].failedExpectations[0].globalErrorType = 'lateExpeztation' to equal 'lateExpectation'.
This commit is contained in:
@@ -2519,6 +2519,27 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ObjectContaining.prototype.valuesForDiff_ = function(other) {
|
||||||
|
if (!j$.isObject_(other)) {
|
||||||
|
return {
|
||||||
|
self: this.jasmineToString(),
|
||||||
|
other: other
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var filteredOther = {};
|
||||||
|
Object.keys(this.sample).forEach(function (k) {
|
||||||
|
// eq short-circuits comparison of objects that have different key sets,
|
||||||
|
// so include all keys even if undefined.
|
||||||
|
filteredOther[k] = other[k];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
self: this.sample,
|
||||||
|
other: filteredOther
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
ObjectContaining.prototype.jasmineToString = function() {
|
ObjectContaining.prototype.jasmineToString = function() {
|
||||||
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
@@ -4192,7 +4213,16 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
return obj && j$.isA_('Function', obj.asymmetricMatch);
|
return obj && j$.isA_('Function', obj.asymmetricMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
function asymmetricMatch(a, b, customTesters, diffBuilder) {
|
function asymmetricDiff(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
|
if (j$.isFunction_(b.valuesForDiff_)) {
|
||||||
|
var values = b.valuesForDiff_(a);
|
||||||
|
eq(values.other, values.self, aStack, bStack, customTesters, diffBuilder);
|
||||||
|
} else {
|
||||||
|
diffBuilder.record(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function asymmetricMatch(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
var asymmetricA = isAsymmetric(a),
|
var asymmetricA = isAsymmetric(a),
|
||||||
asymmetricB = isAsymmetric(b),
|
asymmetricB = isAsymmetric(b),
|
||||||
result;
|
result;
|
||||||
@@ -4204,6 +4234,8 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
if (asymmetricA) {
|
if (asymmetricA) {
|
||||||
result = a.asymmetricMatch(b, customTesters);
|
result = a.asymmetricMatch(b, customTesters);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
// TODO: Do we want to build an asymmetric diff when the actual was an
|
||||||
|
// asymmeteric equality tester? Might be confusing.
|
||||||
diffBuilder.record(a, b);
|
diffBuilder.record(a, b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -4212,7 +4244,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
if (asymmetricB) {
|
if (asymmetricB) {
|
||||||
result = b.asymmetricMatch(a, customTesters);
|
result = b.asymmetricMatch(a, customTesters);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
diffBuilder.record(a, b);
|
asymmetricDiff(a, b, aStack, bStack, customTesters, diffBuilder);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -4230,7 +4262,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
|
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
var result = true, i;
|
var result = true, i;
|
||||||
|
|
||||||
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
|
var asymmetricResult = asymmetricMatch(a, b, aStack, bStack, customTesters, diffBuilder);
|
||||||
if (!j$.util.isUndefined(asymmetricResult)) {
|
if (!j$.util.isUndefined(asymmetricResult)) {
|
||||||
return asymmetricResult;
|
return asymmetricResult;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,4 +96,65 @@ describe("ObjectContaining", function() {
|
|||||||
|
|
||||||
expect(containing.asymmetricMatch({foo: "fooBar"}, [tester])).toBe(true);
|
expect(containing.asymmetricMatch({foo: "fooBar"}, [tester])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("valuesForDiff_", function() {
|
||||||
|
describe("when other is not an object", function() {
|
||||||
|
it("sets self to jasmineToString()", function () {
|
||||||
|
var containing = new jasmineUnderTest.ObjectContaining({}),
|
||||||
|
result = containing.valuesForDiff_('a');
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
self: '<jasmine.objectContaining(Object({ }))>',
|
||||||
|
other: 'a'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when other is an object", function() {
|
||||||
|
it("includes keys that are present in both other and sample", function() {
|
||||||
|
var sample = {a: 1, b: 2},
|
||||||
|
other = {a: 3, b: 4},
|
||||||
|
containing = new jasmineUnderTest.ObjectContaining(sample),
|
||||||
|
result = containing.valuesForDiff_(other);
|
||||||
|
|
||||||
|
expect(result.self).not.toBeInstanceOf(jasmineUnderTest.ObjectContaining);
|
||||||
|
expect(result).toEqual({
|
||||||
|
self: sample,
|
||||||
|
other: other
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes keys that are present in only sample", function() {
|
||||||
|
var sample = {a: 1, b: 2},
|
||||||
|
other = {a: 3},
|
||||||
|
containing = new jasmineUnderTest.ObjectContaining(sample),
|
||||||
|
result = containing.valuesForDiff_(other);
|
||||||
|
|
||||||
|
expect(result.self).not.toBeInstanceOf(jasmineUnderTest.ObjectContaining);
|
||||||
|
expect(containing.valuesForDiff_(other)).toEqual({
|
||||||
|
self: sample,
|
||||||
|
other: {
|
||||||
|
a: 3,
|
||||||
|
b: undefined
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits keys that are present only in other", function() {
|
||||||
|
var sample = {a: 1, b: 2},
|
||||||
|
other = {a: 3, b: 4, c: 5},
|
||||||
|
containing = new jasmineUnderTest.ObjectContaining(sample),
|
||||||
|
result = containing.valuesForDiff_(other);
|
||||||
|
|
||||||
|
expect(result.self).not.toBeInstanceOf(jasmineUnderTest.ObjectContaining);
|
||||||
|
expect(result).toEqual({
|
||||||
|
self: sample,
|
||||||
|
other: {
|
||||||
|
a: 3,
|
||||||
|
b: 4
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -593,6 +593,42 @@ describe("matchersUtil", function() {
|
|||||||
expect(['foo']).toEqual(['foo']);
|
expect(['foo']).toEqual(['foo']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Building diffs for asymmetric equality testers", function() {
|
||||||
|
it("diffs the values returned by valuesForDiff_", function() {
|
||||||
|
var tester = {
|
||||||
|
asymmetricMatch: function() { return false; },
|
||||||
|
valuesForDiff_: function() {
|
||||||
|
return {
|
||||||
|
self: 'asymmetric tester value',
|
||||||
|
other: 'other value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
diffBuilder = jasmine.createSpyObj('diffBuilder', ['record', 'withPath']);
|
||||||
|
diffBuilder.withPath.and.callFake(function(p, block) { block() });
|
||||||
|
debugger;
|
||||||
|
jasmineUnderTest.matchersUtil.equals({x: 42}, {x: tester}, [], diffBuilder);
|
||||||
|
|
||||||
|
expect(diffBuilder.withPath).toHaveBeenCalledWith('x', jasmine.any(Function));
|
||||||
|
expect(diffBuilder.record). toHaveBeenCalledWith(
|
||||||
|
'other value', 'asymmetric tester value'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("records both objects when the tester does not implement valuesForDiff", function() {
|
||||||
|
var tester = {
|
||||||
|
asymmetricMatch: function() { return false; },
|
||||||
|
},
|
||||||
|
diffBuilder = jasmine.createSpyObj('diffBuilder', ['record', 'withPath']);
|
||||||
|
diffBuilder.withPath.and.callFake(function(p, block) { block() });
|
||||||
|
debugger;
|
||||||
|
jasmineUnderTest.matchersUtil.equals({x: 42}, {x: tester}, [], diffBuilder);
|
||||||
|
|
||||||
|
expect(diffBuilder.withPath).toHaveBeenCalledWith('x', jasmine.any(Function));
|
||||||
|
expect(diffBuilder.record). toHaveBeenCalledWith(42, tester);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("contains", function() {
|
describe("contains", function() {
|
||||||
|
|||||||
@@ -350,6 +350,20 @@ describe("toEqual", function() {
|
|||||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("reports mismatches involving objectContaining", function() {
|
||||||
|
var actual = {x: {a: 1, b: 4, c: 3, extra: 'ignored'}};
|
||||||
|
var expected = {x: jasmineUnderTest.objectContaining({a: 1, b: 2, c: 3})};
|
||||||
|
expect(compareEquals(actual, expected).message).toEqual('Expected $.x.b = 4 to equal 2.')
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports mismatches between a non-object and objectContaining", function() {
|
||||||
|
var actual = {x: 1};
|
||||||
|
var expected = {x: jasmineUnderTest.objectContaining({a: 1})};
|
||||||
|
expect(compareEquals(actual, expected).message).toEqual(
|
||||||
|
"Expected $.x = 1 to equal '<jasmine.objectContaining(Object({ a: 1 }))>'."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// == Sets ==
|
// == Sets ==
|
||||||
|
|
||||||
it("reports mismatches between Sets", function() {
|
it("reports mismatches between Sets", function() {
|
||||||
|
|||||||
@@ -41,6 +41,27 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ObjectContaining.prototype.valuesForDiff_ = function(other) {
|
||||||
|
if (!j$.isObject_(other)) {
|
||||||
|
return {
|
||||||
|
self: this.jasmineToString(),
|
||||||
|
other: other
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var filteredOther = {};
|
||||||
|
Object.keys(this.sample).forEach(function (k) {
|
||||||
|
// eq short-circuits comparison of objects that have different key sets,
|
||||||
|
// so include all keys even if undefined.
|
||||||
|
filteredOther[k] = other[k];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
self: this.sample,
|
||||||
|
other: filteredOther
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
ObjectContaining.prototype.jasmineToString = function() {
|
ObjectContaining.prototype.jasmineToString = function() {
|
||||||
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,7 +55,16 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
return obj && j$.isA_('Function', obj.asymmetricMatch);
|
return obj && j$.isA_('Function', obj.asymmetricMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
function asymmetricMatch(a, b, customTesters, diffBuilder) {
|
function asymmetricDiff(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
|
if (j$.isFunction_(b.valuesForDiff_)) {
|
||||||
|
var values = b.valuesForDiff_(a);
|
||||||
|
eq(values.other, values.self, aStack, bStack, customTesters, diffBuilder);
|
||||||
|
} else {
|
||||||
|
diffBuilder.record(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function asymmetricMatch(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
var asymmetricA = isAsymmetric(a),
|
var asymmetricA = isAsymmetric(a),
|
||||||
asymmetricB = isAsymmetric(b),
|
asymmetricB = isAsymmetric(b),
|
||||||
result;
|
result;
|
||||||
@@ -67,6 +76,8 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
if (asymmetricA) {
|
if (asymmetricA) {
|
||||||
result = a.asymmetricMatch(b, customTesters);
|
result = a.asymmetricMatch(b, customTesters);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
// TODO: Do we want to build an asymmetric diff when the actual was an
|
||||||
|
// asymmeteric equality tester? Might be confusing.
|
||||||
diffBuilder.record(a, b);
|
diffBuilder.record(a, b);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -75,7 +86,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
if (asymmetricB) {
|
if (asymmetricB) {
|
||||||
result = b.asymmetricMatch(a, customTesters);
|
result = b.asymmetricMatch(a, customTesters);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
diffBuilder.record(a, b);
|
asymmetricDiff(a, b, aStack, bStack, customTesters, diffBuilder);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -93,7 +104,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
|
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||||
var result = true, i;
|
var result = true, i;
|
||||||
|
|
||||||
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
|
var asymmetricResult = asymmetricMatch(a, b, aStack, bStack, customTesters, diffBuilder);
|
||||||
if (!j$.util.isUndefined(asymmetricResult)) {
|
if (!j$.util.isUndefined(asymmetricResult)) {
|
||||||
return asymmetricResult;
|
return asymmetricResult;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user