2

I'm running a Karma spec to test the functionality of an Angular BaseClass for my models that is outlined in an Egghead.io tutorial.

The behavior seems to be working, but I'm running into a weird error:

PhantomJS 1.9.7 (Mac OS X) BCCache adds a cache to the model FAILED
  Expected {  } to equal {  }.
  Error: Expected {  } to equal {  }.

What I could find of this error (it's hard to search, given the characters -- suggests that toEqual should be able to recognize the two objects' equivalence -- so I'm a little stumped.

Here's the spec code (coffeescript) :

describe 'BCCache', ->
  it "adds a cache to the model", ->
    expect(Post.cached).toEqual({})

And here's what it's testing:

base.coffee

angular.module("BaseClass")
  .factory "BCBase", ['BCCache', (Cache) ->
    Base = (attributes) ->
      _constructor = this
      _prototype = _constructor.prototype

      _constructor.cached = new Cache()

    return Base
  ]

cache.coffee

angular.module('BaseClass')
  .factory 'BCCache', -> 
    Cache = ->    
    return Cache

The spec is basically asserting that the cached method (currently) returns a new empty object, which the cache.coffee file seems to successfully do. But somehow, Karma doesn't see the two empty objects as equivalent. Any idea why? I'm a little stumped.

Sasha
  • 6,224
  • 10
  • 55
  • 102
  • 2
    2 objects are equal only if their references are same. – PSL Oct 13 '14 at 22:55
  • 3
    @PSL This is not a dupe, this is a Jasmine issue. `toEqual` should work in this instance: https://groups.google.com/forum/#!topic/jasmine-js/INma5VrV2Xs – SomeKittens Oct 13 '14 at 22:59
  • @SomeKittens That is why i did not mark the question as duplicate, but this is missing concept.. the concept in the question is a duplicate of the above. How to get around that is another part of the question. – PSL Oct 13 '14 at 23:00
  • 2
    @PSL No, it's not. `toEqual` is NOT `===`. It iterates through an object and checks the properties. – SomeKittens Oct 13 '14 at 23:01
  • OP: Can you provide a complete example in a Plunkr? (as well as using regular JavaScript)? – SomeKittens Oct 13 '14 at 23:03
  • @SomeKittens, example:- `expect(new Cache()).toEqual(new Cache());` is true but `expect(new Cache()).toEqual({});` is false.. You dont need a complete example for that. – PSL Oct 13 '14 at 23:04
  • Thanks, guys. So I looked into this (followed @PSL's link), and a) my attempt with lodash (`expect( _.isEqual(Post.cached, {}) ).toBe(true)`) also failed, and b) it looks like `isEqual()` [should do this](http://stackoverflow.com/questions/16401237/checking-object-equality-in-jasmine). Is there no easier way to compute object equality in Jasmine? – Sasha Oct 13 '14 at 23:06
  • 2
    @Sasha Because first object's costructor is `Cache` and second ones is not. SO it fails the expectation. `var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && isFunction(bCtor) && (bCtor instanceof bCtor))) { return false; }`. So set your comparison to `expect(Post.cached).toEqual(new Cache())` – PSL Oct 13 '14 at 23:08
  • so @SomeKittens your 3 votes comment is wrong as i told before.. I don't think it is an issue with jasmine as well. It is clearly commented in jasmine codebase `// Objects with different constructors are not equivalent, but `Object`s // from different frames are.` – PSL Oct 13 '14 at 23:10
  • @PSL heh - good work proving that the issue lies with Jasmine all along (which is what my comment states) – SomeKittens Oct 13 '14 at 23:12
  • 2
    To add to @PSLs answer, the source of equals https://github.com/pivotal/jasmine/blob/master/src/core/matchers/matchersUtil.js shows the behavior being described. Check line 143. Note that if you had `expect({}).toEqual({})` that would work. It's the error message that is a little misleading. – Jeff Storey Oct 13 '14 at 23:12
  • @SomeKittens i do not know why you think it is an issue. You could do `expect(Post.cached).toEqual(new Cache())` no? – PSL Oct 13 '14 at 23:13

1 Answers1

4

Post.cached is an instance of Cache, while your {} is just a boring ol' Object. Jasmine considers having a different constructor a valid reason to fail a toEquals comparison.

If you want to check equality as above, you can do something like:

var mockCache = new Cache();
expect(Post.cached).toEqual(mockCache);

Alternatively, you could just check if it's an empty object:

expect(Object.keys(Post.cached).length).toBe(0);

Thanks to Jeff Storey for the link to the code: https://github.com/pivotal/jasmine/blob/master/src/core/matchers/matchersUtil.js#L143

SomeKittens
  • 38,868
  • 19
  • 114
  • 143
  • 2
    @PSL Yep, turns out the issue was a misunderstanding of Jasmine's `toEqual` all along. – SomeKittens Oct 13 '14 at 23:17
  • That is what i commented in the question, way back your answer.. :D, probably i could have answered without commenting and clarifying.. lol.. huff it is a competitive environment.. :D – PSL Oct 13 '14 at 23:17
  • Thanks everybody! That's an interesting one. – Sasha Oct 13 '14 at 23:29
  • @sasha Yeah pretty much. But I think this should have been answered by jeff storey or myself... since instead of arguing jasmine is wrong we investigated and pasted relevant parts that led to the answer. – PSL Oct 13 '14 at 23:41