angularjsjasminegulp-karma

toEqualData matcher breaks tests in AngularJS app


I have the following very simple test written for an AngularJS application's services:

describe('Services', function () { 

    beforeEach(function(){
        this.addMatchers({
            toEqualData: function(expected) { 
                return angular.equals(this.actual, expected);
            }
        });
    });

    beforeEach(module('myapp.services'));

    describe('Album service', function(){
        var Album;

        beforeEach(inject(function (_Album_) { 
            Album = _Album_;
        }));

        it('can get an instance of the Album factory', inject(function (Album) { 
            expect(Album).toBeDefined();
        }));
    });
});

I've just added the custom toEqualData matcher as advised in the AngularJS documentation. However, this breaks the test. I'm using Gulp to run the test with gulp-karma (although the same issue occurs if I use Karma directly), and I see the following error message:

$ gulp test
[10:00:04] Using gulpfile ~/Projects/myapp/gulpfile.js
[10:00:04] Starting 'jshint'...
[10:00:04] Starting 'karma'...
WARN `start` method is deprecated since 0.13. It will be removed in 0.14. Please use
  server = new Server(config, [done])
  server.start()
instead.
31 07 2015 10:00:04.362:INFO [karma]: Karma v0.13.3 server started at http://localhost:9876/
31 07 2015 10:00:04.368:INFO [launcher]: Starting browser PhantomJS
[10:00:04] Finished 'jshint' after 277 ms
31 07 2015 10:00:04.631:INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket sFxRfQ6bJtqM_utNAAAA with id 27252937
PhantomJS 1.9.8 (Linux 0.0.0) Services Album service can get an instance of the Album factory FAILED
        TypeError: 'undefined' is not a function (evaluating 'this.addMatchers')
            at /home/matthew/Projects/myapp/tests/services.tests.js:7
PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 (1 FAILED) (0.04 secs / 0.022 secs)
[10:00:04] Finished 'karma' after 558 ms
[10:00:04] Starting 'test'...
[10:00:04] Finished 'test' after 11 μs

I can't see where I've gone awry. Any ideas? It actually works fine if I take out the custom matcher, which I don't actually use yet, but plan to do so. So it seems like the matcher is the culprit, but since it's literally copied and pasted from the Angular documentation, I'm at a loss as to why it isn't working.


Solution

  • Solved the problem in the end. Turns out that the Jasmine API has changed between 1.3 and 2.0 and the AngularJS documentation doesn't seem to give any information about this. Here's how I fixed the issue so that hopefully anyone else who's stuck on this can find a working solution:

    describe('Services', function () { 
    
        beforeEach(function(){
            jasmine.addMatchers({
                toEqualData: function(util, customEqualityTesters) { 
                    return { 
                        compare: function(actual, expected) { 
                            return { 
                                pass: angular.equals(actual, expected)
                            };
                        } 
                    };
                } 
            });
        });
    
        beforeEach(module('myapp.services'));
    
        describe('Album service', function(){
            var Album;
    
            beforeEach(inject(function (_Album_, _$httpBackend_) { 
                Album = _Album_;
                mockBackend = _$httpBackend_;
            }));
    
            it('can get an instance of the Album factory', inject(function (Album) { 
                mockBackend.expectGET('https://myapp.com/api/albums').respond([{id: 1}, {id: 2}]);
                expect(Album).toBeDefined();
                var albums = Album.query();
                mockBackend.flush();
                expect(albums).toEqualData([{id: 1}, {id: 2}]);
            }));
        });
    });
    

    Basically, all you do is change this for jasmine when you add the matcher, pass through actual and expected as arguments to the function, and use them rather than this. Seems to work as expected now.

    EDIT: Turns out that didn't work, it just failed silently. I've now corrected it.