Checking object equality in Jasmine
Asked Answered
A

6

98

Jasmine has built-in matchers toBe and toEqual. If I have an object like this:

function Money(amount, currency){
    this.amount = amount;
    this.currency = currency;

    this.sum = function (money){
        return new Money(200, "USD");
    }
}

and try to compare new Money(200, "USD") and the result of sum, these built-in matchers will not work as expected. I have managed to implement a work-around based on a custom equals method and custom matcher, but it just seems to much work.

What is the standard way to compare objects in Jasmine?

Adaline answered 6/5, 2013 at 14:45 Comment(0)
W
191

I was looking for the same thing and found an existing way to do so without any custom code or matchers. Use toEqual().

Wrinkle answered 5/7, 2013 at 8:45 Comment(0)
C
73

If you're looking to compare partial objects, you might consider:

describe("jasmine.objectContaining", function() {
  var foo;

  beforeEach(function() {
    foo = {
      a: 1,
      b: 2,
      bar: "baz"
    };
  });

  it("matches objects with the expect key/value pairs", function() {
    expect(foo).toEqual(jasmine.objectContaining({
      bar: "baz"
    }));
  });
});

cf. jasmine.github.io/partial-matching

Caesarean answered 11/2, 2015 at 19:50 Comment(0)
R
3

Its the expected behavior, as two instances of an object are not the same in JavaScript.

function Money(amount, currency){
  this.amount = amount;
  this.currency = currency;

  this.sum = function (money){
    return new Money(200, "USD");
  }
}

var a = new Money(200, "USD")
var b = a.sum();

console.log(a == b) //false
console.log(a === b) //false

For a clean test you should write your own matcher that compares amount and currency:

beforeEach(function() {
  this.addMatchers({
    sameAmountOfMoney: function(expected) {
      return this.actual.currency == expected.currency && this.actual.amount == expected.amount;
    }
  });
});
Roundly answered 6/5, 2013 at 19:36 Comment(0)
F
3

I found that lodash _.isEqual is good for that

expect(_.isEqual(result, expectedResult)).toBeTruthy()
Futilitarian answered 25/9, 2019 at 7:40 Comment(0)
O
0

I managed to compare two objects without any custom code via :

import { deepStrictEqual } from 'assert'
// ...
expect(deepStrictEqual.bind(null, objectA, objectB)).not.toThrow()

note : assert is a native node module, no need to install anything here

Ocam answered 21/6, 2021 at 14:3 Comment(0)
T
-5

Your problem is with truthyness. You are trying to compare two different instances of an object which is true for regular equality ( a == b ) but not true for strict equality ( a === b). The comparator that jasmine uses is jasmine.Env.equals_() which looks for strict equality.

To accomplish what you need without changing your code you can use the regular equality by checking for truthyness with something a little like the following:

expect(money1.sum() == money2.sum()).toBeTruthy();
Trifle answered 9/5, 2013 at 5:46 Comment(4)
What you said about == and === is completely wrong. Two different instances of an object with the same content will both return false. For any non-primitives, == and === behave identically. jsfiddle.net/9mrmyrs6Rixdollar
@JuanMendes check out the answer by Andreas K. ... you guys are saying two different things. Is this a difference in newing up an object vs an object literal?Trona
@Trona mmm....yes we are saying different things: I'm saying that when comparing non-primitives, it doesn't matter whether you use == or ===, there is no coercion involved. Andreas is saying that you can create a custom matcher. The last statement on how to fix this problem is "correct" but the explanation in the first paragraph is just incorrect. jasmine will actually check object contents if you use toBe() instead of equalsRixdollar
a == b will still give false if a and b are different instances, you might want to edit your answerSquires

© 2022 - 2024 — McMap. All rights reserved.