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?

Community
  • 1
  • 1
Dan
  • 11,077
  • 20
  • 84
  • 119

6 Answers6

191

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

edi9999
  • 19,701
  • 13
  • 88
  • 127
lukas.pukenis
  • 13,057
  • 12
  • 47
  • 81
71

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

originalhat
  • 1,676
  • 16
  • 18
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;
    }
  });
});
Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
3

I found that lodash _.isEqual is good for that

expect(_.isEqual(result, expectedResult)).toBeTruthy()
Oleksandr Poshtaruk
  • 2,062
  • 15
  • 18
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

Ssh-uunen
  • 313
  • 1
  • 9
-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();
Baer
  • 3,690
  • 25
  • 24
  • 9
    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. http://jsfiddle.net/9mrmyrs6/ – Ruan Mendes Feb 05 '15 at 15:51
  • @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? – pherris Oct 16 '15 at 15:35
  • @pherris 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 `equals` – Ruan Mendes Oct 19 '15 at 12:58
  • `a == b` will still give false if `a` and `b` are different instances, you might want to edit your answer – Louie Almeda Mar 29 '16 at 02:26