Jasmine’s default equality matcher is really good (it’s an adapted version of underscore’s isEqual
) but when you work with complex objects, you may want to have more control on what can be equal to what.
Let’s see an example:
var Person = (name, surname) {
this.name = name;
this.surname = surname;
};
Person.prototype.render = function() {
if (!this._cached) {
this._cached = this.name + " " + this.surname;
};
};
describe('Person', function() {
var p1, p2;
beforeEach(function() {
p1 = new Person('Indiana', 'Jones');
p2 = new Person('Indiana', 'Jones');
});
it('they are equal', function() {
p1.render();
expect(p1).toEqual(p2);
});
});
In this case the spec will fail because even if the two objects are representing the same person, they have different properties (p1
has a _cached property that has been set during the invocation of render).
My solution in this case is to create the following custom equality matcher for jasmine:
beforeEach(function() {
jasmine.addCustomEqualityTester(function(actual, expected) {
var toPrimitive = function(o) {
if (o == null) { return o; }
if (o instanceof Array) {
result = [];
o.forEach(function(i) { result.push(toPrimitive(i)); });
return result;
}
return o.toPrimitive ? o.toPrimitive() : o;
},
actualPrimitive = toPrimitive(actual),
expectedPrimitive = toPrimitive(expected);
return jasmine.matchersUtil.equals(actualPrimitive, expectedPrimitive);
});
});
and to change the example code as the following:
var Person = (name, surname) {
this.name = name;
this.surname = surname;
};
Person.prototype.render = function() {
if (!this._cached) {
this._cached = this.name + " " + this.surname;
};
};
Person.prototype.toPrimitive = function() {
return { name: this.name, surname: this.surname };
};
describe('Person', function() {
var p1, p2;
beforeEach(function() {
p1 = new Person('Indiana', 'Jones');
p2 = new Person('Indiana', 'Jones');
});
it('they are equal', function() {
p1.render();
expect(p1).toEqual(p2);
});
it('a person is equal to a plain object', function() {
expect(p1).toEqual({name: 'Indiana', surname: 'Jones'});
});
});
Spec passing.
When the object contains the toPrimitive
function, the equality matcher will rely on this one to obtain a more simple object to use to check the equality.
Leave a Reply