8

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)
    ...
A T
  • 13,008
  • 21
  • 97
  • 158
  • Why would you use angularJS and karma to test a backend. AngularJS and Karma are all about the front-end. You don't need a browser to send an HTTP request to a server. And angular-mocks is precisely used to mock a backend, so you can't use it to test your real backend. – JB Nizet Dec 22 '13 at 07:40
  • 1
    Advantage of putting all my tests in the one place is that when they pass; I can deploy to staging. I.e.: keep the test-server running during all development. – A T Dec 22 '13 at 07:53
  • 1
    I have unit tests and integration tests written in Java for my backend, unit tests written in JavaScript with Karma and e2e tests written in JavaScript with angular protractor for the angular frontend, and I can build and test everything (using gradle) with a single command. My CI server also does it at every push. Using the right tool for the right job shouldn't prevent uoi from running all the tests and only deploying if all the tests pass. – JB Nizet Dec 22 '13 at 08:03
  • 1
    Sure, but if I'm doing only generic RESTful testing, JavaScript should be fine... – A T Dec 22 '13 at 08:29
  • 1
    I'm not saying not to use JavaScript. Karma and angular mocks aren't appropriate though. I'm pretty sure something exists in the NodeJS ecosystem to test a RESTful backend, but I don't know it well enough to suggest something. – JB Nizet Dec 22 '13 at 08:31
  • Oh okay, just did a quick Google Search and http://frisbyjs.com/ came up. – A T Dec 22 '13 at 09:39

1 Answers1

14

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.

Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79
  • 2
    But `$httpBackend.whenGET(/.*/)` doesn't has a `.passThrough()` method ?! – victorwoo May 15 '15 at 09:26
  • $httpBackend can be used via `ngMock` or `ngMockE2E` ..but it behaves differently. ngMockE2E has .passThrough() . You might have a look at the [differences](http://chariotsolutions.com/blog/post/angularjs-corner-ngmock-ngmocke2e-libraries/) – Markus Oct 14 '15 at 14:57