1

I've struggling the whole day already figuring out how to test the result of a $http.GET request which is returning data from a .json file. I hope any of you can be of any help here.. Practical the app is running perfectly and is returning the correct json I expected.

I have a controller named 'ProgramController' and a service ; 'DataService'.

Controller:

function ProgramController(DataService) {
    var vm = this;
    vm.timeline = {};

    activate();

    ////////////////
    function activate() {
        DataService.getTimelineData().then(function (data) {
            console.log(data);
        });
    }
}

Service:

function DataService($http) {
    var service = {
        getTimelineData: getTimelineData
    };

    return service;

    ///////////////
    function getTimelineData() {
        return $http.get('data/program.json').then(function (httpResult) {
            return httpResult.data;
        });
    }
}

Tests for testing the controller and service response;

describe('Program', function () {

var controller, scope, dataserviceMock, httpBackend;

beforeEach(module('mymodule'));

beforeEach(inject(function ($rootScope, $controller, $injector, $q, $httpBackend, $http) {
    scope = $rootScope.$new();
    httpBackend = $httpBackend;
    
    dataserviceMock = {
        getTimelineData: function () {
            return $http.get('data/program.json').then(function (httpResult) {
                return httpResult.data;
            });
        }
    };

    controller = $controller('ProgramController', { 'DataService': dataserviceMock });
}));

describe('when initializing the controller', function () {
    it('object timeline should be something', function () {
        httpBackend.whenGET('data/program.json').respond(mockedTimelineData);
        httpBackend.flush();
        expect(controller.timeline).toEqual(mockedTimelineData);
    });
});

});

The test is failing when I try this out. Although the 'controller.timeline' property is defined as '{}' in the controller. The spec doesn't even get to that point.. It fails on the .flush() of the httpBackend.

The result in the brower show the following error;

Error: Unexpected request: GET js/app/program/program.template.html

No more request expected

Which references to the template which belongs with the ProgramController defined at the $stateProvider definition.

Do any of you have an idea what i'm doing wrong here? I really have no clue. I've already done some stuff with $q.defer and promise resolving in tests, but I really can't get my head around this...

Community
  • 1
  • 1
Lars Meijdam
  • 1,177
  • 1
  • 10
  • 18

2 Answers2

2

@myself.. and @Xnake

Managed to fix it eventually!! Finally! I stumbled upon this article; http://gonehybrid.com/how-to-write-automated-tests-for-your-ionic-app-part-2/ where in the bottom the writer also has the same sort of problems I received... Disabling the template caching was my working solution!

// disable template caching
beforeEach(module(function($provide, $urlRouterProvider) {  
    $provide.value('$ionicTemplateCache', function(){} );
    $urlRouterProvider.deferIntercept();
}));

Other solutions are also written here; https://github.com/angular-ui/ui-router/issues/212#issuecomment-69974072

Lars Meijdam
  • 1,177
  • 1
  • 10
  • 18
1

What's the value that you provided for mockedTimelineData? The problem is your getTimelineData() calls the actual endpoint hence it throws the request error. You should mock the returned data when it tries to call 'data/program.json', e.g:

dataserviceMock = {
        getTimelineData: function () {
            return $http.get('data/program.json').then(function (httpResult) {
                return [{'id':'1'},{'id':'2'}];
            });
        }
    };

That way, when DataService.getTimelineData() is called, it's actually calling the mock you provided.

Update:

You can either supply the return value of the mocked data like in my original post or given your original code I've provided the working example: http://plnkr.co/edit/rrBfJOdq9igy3UeMlK21?p=preview.

Also I notice that in your controller, you never set the vm.timeline in the response handler, but instead it does console.log(data);

Xnake
  • 940
  • 7
  • 8
  • Okay okay thanks! will try that out! The mockedTimelineData is something similar as you described in the 'return [{'id':'1'},{'id':'2'}];'... just some plain json data. – Lars Meijdam Jun 03 '16 at 06:43
  • hmm.. still when I do httpBackend.flush() it is requesting the 'js/app/program/program.template.html' :( but another addition.. shouldn't ' httpBackend.whenGET('data/program.json').respond(mockedTimelineData);' be enough to mock the result in the http request? – Lars Meijdam Jun 03 '16 at 06:46
  • when leaving the .flush out.. the 'then' in the Controller > Dataservice.getTimelineData() doesn't get triggered at all.. the expect is also failing because it checks {} toBe {data: "data"} – Lars Meijdam Jun 03 '16 at 06:50
  • Thanks man! Although i really believe your implementation works I still get the same 'GET js/app/program/program.template.html' response when httpbackend.flush() or scope.$apply() is being called.. Do you think it has anything to do due the fact I try to implement this using Ionic and not a plain Angular app? – Lars Meijdam Jun 06 '16 at 06:31