Reputation: 226
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
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