Lukasz Ożóg
Lukasz Ożóg

Reputation: 226

TypeScript Angular Jasmine+Karma test

I spend hours trying to figure this out. I'm trying to test my Angular controller (wrote in typeScript) with tests also in Typescript. I'm stuck on mocking service into my controller. Here is the code :

Controller :

export class ProductsController {     
    static $inject = ["ProductService", "$scope"];
    constructor(productsServices: AngularTest.Interfaces.IProductsService, $scope: any) {


            productsServices.getAllProducts().then((response: ng.IHttpPromiseCallbackArg<AngularTest.Interfaces.IProducts[]>): any => {
            $scope.currentPage = 1;
            $scope.allProducts = <AngularTest.Interfaces.IProducts[]> response.data

                    $scope.cartItems = [];
                    $scope.modalAlerts = [];

                    $scope.maxItems = 3;
                    $scope.totalItems = $scope.allProducts.length;

                    $scope.itemsOnPage = $scope.allProducts.slice(0, $scope.maxItems);
        });

        $scope.pageChanged = function () {
            $scope.itemsOnPage = $scope.allProducts.slice(($scope.currentPage - 1) * $scope.maxItems, $scope.currentPage * $scope.maxItems);
        };
    }
}

Service :

    module AngularTest.Services{
    class ProductServices implements AngularTest.Interfaces.IProductsService{
        httpService: ng.IHttpService

        static $inject = ["$http"];
        constructor($http: ng.IHttpService)
        {
            this.httpService = $http;

        }

        getAllProducts(): ng.IPromise<AngularTest.Interfaces.IProducts[]> {
            return this.httpService.get('/api/Angular');
            };
    }

    factory.$inject = ['$http'];
    function factory($http : ng.IHttpService) {
        return new ProductServices($http);
    }

    angular
        .module('app.AngularTS')
        .factory('ProductService', factory);

}

Test :

    describe("TestService", () => {

    var mock: ng.IMockStatic;
    var $httpBackend: ng.IHttpBackendService;
    var service; //AngularTest.Interfaces.IProductsService;
    var rootScopeFake;
    var controller;
    var $controller: ng.IControllerService;

    mock = angular.mock;
    beforeEach(mock.module('app.AngularTS'));

    beforeEach(() => inject(function (_$httpBackend_, $injector, $rootScope, _$controller_) {
        $httpBackend = _$httpBackend_;
        rootScopeFake = $rootScope.$new();
        service = $injector.get('ProductService');    
        $controller = _$controller_;
    }));

    afterEach(function () {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it("Should Call API", function () {
        controller = $controller('ProductsController', { ProductService: service, $scope: rootScopeFake});

        spyOn(service, "getAllProducts");

        expect($httpBackend.expectGET('/api/Angular').respond([
            { "x": "xx", "xxx": "xxxx", "xxxxx": 5 },
            { "x": "xx", "xxx": "xxxx", "xxxxx": 5.5 },
            { "x": "xx", "xxx": "xxxx", "xxxxx": 6 },
            { "x": "xx", "xxx": "xxxx", "xxxxx": 0 }
        ])).toHaveBeenCalled;

        expect(service.getAllProducts).toHaveBeenCalled();  // this fails why ?
        $httpBackend.flush();

    });
});

I don't know why this isn't working i recive.Expected spy getAllProducts to have been called.

Upvotes: 1

Views: 3813

Answers (1)

Koen
Koen

Reputation: 549

You should create your spy before the method you're spying on is used. Since the method is used in the controller constructor. The spy should be created before initiating your controller.

it("Should Call API", function () {        
    spyOn(service, "getAllProducts").and.callFake(function(){
        //return promise
    });

    controller = $controller('ProductsController', { ProductService: service, $scope: rootScopeFake});

    ....

Upvotes: 1

Related Questions