Testing backend API via $http in AngularJS/karma/jasmine tests?

A T picture A T · Dec 22, 2013 · Viewed 14.8k times · Source

How do I test my API backend using AngularJS/karma/jasmine tests?

I have tried to create the smallest test-case showing my error:

echo_server.py

from bottle import response, route, run

@route('/echo/<echo>')
def echo_echo(echo):
    response.headers['Access-Control-Allow-Origin'] = '*'
    return {'echo': echo}    # Served as JSON

if __name__ == '__main__':
    run()

test/unit/apiSpec.js

// Should this be in `test/e2e/apiSpec.js`?
describe('echo', function () {
    var scope, http;

    beforeEach(inject(function ($rootScope, $http) {
        $http.defaults.useXDomain = true;    // CORS
        scope = $rootScope.$new();
        http = $http;
    }));


    it("should echo from server", function () {
        scope.$apply(function () {
            var ret;
            http.get("http://localhost:8080/echo/foo")
                .success(function (data, status, headers, config) {
                             ret = data;
                         })
                .error(function (data, status, headers, config) {
                           ret = data;
                       });
            console.log('ret = ' + ret);
            expect(ret.echo).toBe("foo");
        });
    });
});

Output of karma start configs/karma.conf.js

INFO [karma]: Karma v0.10.8 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.2 (Linux)]: Connected on socket m7imfgmhXdOY9JVKJh8r
LOG: 'ret = undefined'
PhantomJS 1.9.2 (Linux) echo should echo from server FAILED
    Error: Unexpected request: GET http://localhost:8080/echo/foo
    No more request expected
        at $httpBackend (~Projects/~karma-tests/test/lib/angular/angular-mocks.js:1178)
    ...

Answer

Kenneth Lynne picture Kenneth Lynne · Dec 22, 2013

The mentioned testing stack is not intended for use this way. The request never gets dispatched because of the $httpMockBackend that has been decorated on top of your original $httpBackend.

To allow requests to pass trough you either need to exclude angular-mocks.js, or specify that some urls should pass through like this:

angular.module('yourModule').run(function ($httpBackend) {
    $httpBackend.whenGET(/.*/).passThrough();
}

Read the documentation for $httpMockBackend here

Also, your test is synchronous, and the server response is asyncronous, so it will not work as expected.