philomath
philomath

Reputation: 2209

Write tests for an angular REST app

I've been clueless so far. Say I have this very simple app module:

var app = angular.module('myApp', []);

app.service('searchService',  ['$http', function($http){
    var baseURL="https://someonehost.com/product/search&query=";
    return  {
        search: function(query){
            return  $http.get(baseURL+query);
        }
    };
}]);

app.controller('mainCtrl', ['$scope','searchService',function($scope, searchService) {
  searchService.search($scope.searchWords).success(function(data) {
        $scope.responseData=data;
  });   
}]);

It works on the browser. Now I tried to test it using karma, mocha & chai. Say I want to write a test case to test the success path of the request. How should I write that? Here is what I'm trying sofar:

describe('',function(){
    var $httpBackend = null;
    var locationService = null;
    var baseURL="https://someonehost.com/product/search&query=";

    beforeEach(function(){
        module('myApp');
        inject(function(_$httpBackend_,_locationService_){
            $httpBackend    =   _$httpBackend_;
            locationService =   _locationService_;
        });
    });

    it('test case 1',function(){
        var searchWord = 'car';
        $httpBackend.when('GET',baseURL+searchWord).respond(200,'');
        $httpBackend.expectGET(baseURL+searchWord);
        searchService.search(searchWord).success(function(data) {
          console.log('data: '+data);
        });
        $httpBackend.flush();
    });

});

But it returns no data, which it should, in the console:

LOG: 'data: '
Firefox 37.0.0 (Ubuntu): Executed 1 of 1 SUCCESS (0.033 secs / 0.006 secs)

Upvotes: 1

Views: 256

Answers (1)

sebastienbarbier
sebastienbarbier

Reputation: 6832

By default, Angular do not accept $http on external services during unit test. You are suppose to provide mocks to fake data and only test the integrity of your code.

What you are trying to do is not unit-test but integration test, and I had the exact same issue few weeks ago. I found this file which override ngMocks and perform a normal query.

https://gist.github.com/kyro38/3371aaac54bf6583852f

In your Karma/Mocha/WhatEver test configuration you import it after angular (example bellow is for Karma) :

// Karma configuration
module.exports = function (config) {
config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: './',

    // frameworks to use
    // some available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine', 'chai'],

    // list of files / patterns to load in the browser
    files: [
        './bower_components/jquery/dist/jquery.js',
        './bower_components/angular/angular.js',
        './src/client/test-helpers/angular-mocks-with-real-backend.js', [...]

And then you can run your test as you want. Let me know if any trouble.

Do not forget making your test asynchronous ;)

https://jasmine.github.io/edge/introduction.html#section-Asynchronous_Support

Be careful with $httpBackend

As describe in documentation :

Fake HTTP backend implementation suitable for unit testing applications that use the $http service.

Try using $http instead.

it('should get nok 8 one single contact', function(done) {
    var promise = $http({
        method: 'get',
        url: baseurl + '/contact/list',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Accept': '*/*'
        },
        params: {
            nokid: 8
        }
    });
    promise.then(function(result) {
        expect(result.status).toEqual(200);
    }, function(error) {
        expect(error.status).toEqual(200);
    }).
    finally(done);
});

https://docs.angularjs.org/api/ngMock/service/$httpBackend#!

Last tips : In your current test, you give a wrong url to expectGET :

var searchWord = 'car';
$httpBackend.expectGET(searchWord);

I would try this

it('test case 1',function(done){
    $http({
        method: 'get',
        url: baseURL + 'car',
        ...
    }).then(function (success) {
        console.log('data: ' + success.data);
        done(); // stop test from waiting
    }, function (fail) {
        console.log('data: ' + fail);
        done(); // stop test from waiting
    });
});

Upvotes: 2

Related Questions