Include symbol properties in matcher diffs

* #1966
This commit is contained in:
Steve Gravrock
2022-05-07 13:26:15 -07:00
parent 9d80377fe3
commit 468e9577cd
7 changed files with 81 additions and 36 deletions

View File

@@ -663,15 +663,9 @@ getJasmineRequireObj().util = function(j$) {
};
util.objectDifference = function(obj, toRemove) {
var diff = {};
for (var key in obj) {
if (util.has(obj, key) && !util.has(toRemove, key)) {
diff[key] = obj[key];
}
}
return diff;
return j$.MatchersUtil.keys(obj)
.filter(key => !util.has(toRemove, key))
.map(key => [key, obj[key]]);
};
util.has = function(obj, key) {
@@ -5667,11 +5661,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
);
}
function formatKeyValuePairs(pp, obj) {
var formatted = '';
for (var key in obj) {
formatted += '\n ' + key + ': ' + pp(obj[key]);
function formatKeyValuePairs(pp, keyValuePairs) {
let formatted = '';
for (const [key, value] of keyValuePairs) {
formatted += '\n ' + key.toString() + ': ' + pp(value);
}
return formatted;
}
@@ -5849,8 +5845,8 @@ getJasmineRequireObj().ObjectPath = function(j$) {
};
function formatPropertyAccess(prop) {
if (typeof prop === 'number') {
return '[' + prop + ']';
if (typeof prop === 'number' || typeof prop === 'symbol') {
return '[' + prop.toString() + ']';
}
if (isValidIdentifier(prop)) {

View File

@@ -196,10 +196,34 @@ describe('util', function() {
quux: 7
};
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({
foo: 3,
baz: 5
});
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual([
['foo', 3],
['baz', 5]
]);
});
it('includes Symbol keys', function() {
const missing = Symbol('missing');
const both = Symbol('both');
const symbolDuplicated1 = Symbol('symbolDuplicated');
const symbolDuplicated2 = Symbol('symbolDuplicated');
const added = Symbol('added');
const a = {
[missing]: 1,
[both]: 2,
[symbolDuplicated1]: 3
};
const b = {
[both]: 'anything',
[symbolDuplicated2]: 4,
[added]: 5
};
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual([
[missing, 1],
[symbolDuplicated1, 3]
]);
});
it('only looks at own properties of both objects', function() {
@@ -214,8 +238,8 @@ describe('util', function() {
const b = new Foo();
b.y = 2;
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({ x: 1 });
expect(jasmineUnderTest.util.objectDifference(b, a)).toEqual({ y: 2 });
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual([['x', 1]]);
expect(jasmineUnderTest.util.objectDifference(b, a)).toEqual([['y', 2]]);
});
});

View File

@@ -25,6 +25,10 @@ describe('ObjectPath', function() {
expect(new ObjectPath(['1hello']).toString()).toEqual("$['1hello']");
});
it('renders symbols with squre bracket notation', function() {
expect(new ObjectPath([Symbol('a')]).toString()).toEqual('$[Symbol(a)]');
});
it('renders as the empty string when empty', function() {
expect(new ObjectPath().toString()).toEqual('');
});

View File

@@ -51,6 +51,15 @@ describe('toEqual', function() {
expect(compareEquals(actual, expected).message).toEqual(message);
});
it('reports differences between symbol properties', function() {
const x = Symbol('x'),
actual = { [x]: 1, y: 3 },
expected = { [x]: 2, y: 3 },
message = 'Expected $[Symbol(x)] = 1 to equal 2.';
expect(compareEquals(actual, expected).message).toEqual(message);
});
it('reports the difference between nested objects that are not equal', function() {
const actual = { x: { y: 1 } },
expected = { x: { y: 2 } },
@@ -75,6 +84,22 @@ describe('toEqual', function() {
expect(compareEquals(actual, expected).message).toEqual(message);
});
it('reports missing symbol properties', function() {
const actual = { x: {} },
expected = { x: { [Symbol('y')]: 1 } },
message = 'Expected $.x to have properties\n' + ' Symbol(y): 1';
expect(compareEquals(actual, expected).message).toEqual(message);
});
it('reports extra symbol properties', function() {
const actual = { x: { [Symbol('y')]: 1 } },
expected = { x: {} },
message = 'Expected $.x not to have properties\n' + ' Symbol(y): 1';
expect(compareEquals(actual, expected).message).toEqual(message);
});
it('reports extra properties', function() {
const actual = { x: { y: 1, z: 2 } },
expected = { x: {} },

View File

@@ -24,8 +24,8 @@ getJasmineRequireObj().ObjectPath = function(j$) {
};
function formatPropertyAccess(prop) {
if (typeof prop === 'number') {
return '[' + prop + ']';
if (typeof prop === 'number' || typeof prop === 'symbol') {
return '[' + prop.toString() + ']';
}
if (isValidIdentifier(prop)) {

View File

@@ -610,11 +610,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
);
}
function formatKeyValuePairs(pp, obj) {
var formatted = '';
for (var key in obj) {
formatted += '\n ' + key + ': ' + pp(obj[key]);
function formatKeyValuePairs(pp, keyValuePairs) {
let formatted = '';
for (const [key, value] of keyValuePairs) {
formatted += '\n ' + key.toString() + ': ' + pp(value);
}
return formatted;
}

View File

@@ -76,15 +76,9 @@ getJasmineRequireObj().util = function(j$) {
};
util.objectDifference = function(obj, toRemove) {
var diff = {};
for (var key in obj) {
if (util.has(obj, key) && !util.has(toRemove, key)) {
diff[key] = obj[key];
}
}
return diff;
return j$.MatchersUtil.keys(obj)
.filter(key => !util.has(toRemove, key))
.map(key => [key, obj[key]]);
};
util.has = function(obj, key) {