Search code examples
javascriptangularjsjasminerestangular

Test spec executing before $rootScope.$apply() is done resolving promise


I'm writing angular unit tests using Jasmine with angular-mocks' httpBackend.
I've managed to properly mock my backend but some one of my tests has some issues with an http call where a value is set to scope after the request is done (in then()).

Controller: $scope.startShift is binded to a button click.

 app.controller('ShiftStartCntl', function($scope, $rootScope, $location, Restangular, $http, shifts) {
    $scope.shifts = shifts;

    $scope.startShift = function (category) {
        $scope.startingShift = true;
        baseShifts.post({category_number: 2})
            .then(function (shift) {
                $scope.shift = shift;
                // breaks here if run as the endpoint isn't mocked
                $http.post('endpointThatIsNotMocked').then(function() {});
                $location.path($scope.rootURL + '/shift/' + shift.id + '/');
                $scope.startingShift = false;
        });
});

Test:

// module definition and stuff
// 
// [...]
// 

describe('ShiftStartCntl', function() {
    var scope, rootScope, httpBackend, ShiftStartCntl;

    beforeEach(angular.mock.inject(function($rootScope, $controller, $httpBackend) {
        scope = $rootScope.$new();
        rootScope = $rootScope;
        httpBackend = $httpBackend;

        // mimics the controller's ng-route `resolve` dependency
        shifts = getJSONFixture('leave_shifts.json');
        scope.baseShifts = baseApi.all('shifts');
        // used in the controller
        scope.categories = getJSONFixture('leave_categories.json');

        httpBackend.expectPOST('/api/shifts/', {category_number: 2})
            .respond(203, {"id": 4,                                                                                                                                                                  "user": 1,
                "category_number": 2,
                "sign_in": "2015-02-10T21:29:06.110Z",
                "sign_out": null
            });

        $controller('ShiftStartCntl', {$scope: scope, shifts: []});
    }));

    it('should start a shift', function() {
        expect(shifts.length).toEqual(2);
        expect(scope.startingShift).toBe(undefined);
        scope.startShift(scope.categories[1]);
        rootScope.$apply();
        expect(scope.shift.id).toEqual(4);
        httpBackend.flush();
    });

});

The produced error is the following:

PhantomJS 1.9.8 (Mac OS X) Shifts ShiftStartCntl should start a shift FAILED
        Expected undefined to equal 4.
            at [...]/js/tests/unit/controllers/main.js:100  
        Error: Unexpected request: POST yoyoyo

which is the line where expect(scope.shift.id).toEqual(4);

My problem is that the error about the unexpected request should happen before expect(scope.shift.id).toEqual(4); is executed.

As read in several Stackoverflow answers and various blogposts, I've tried using $rootScope.apply(); with no success.

Any ideas on how this could be solved?


Solution

  • Can you try to move the httpBackend.flush(); two lines above

            scope.startShift(scope.categories[1]);
            httpBackend.flush();
            rootScope.$apply();
            expect(scope.shift.id).toEqual(4);