I'm trying to get unit tests running with mocked responses in separate json files. The tests were working when I used $q to return promises resolved manually in my OpsService, but when I tried to make them into actual $http requests to return the actual json files, they no longer worked.
edit: I've tried $httpBackend.flush()
, $rootScope.$apply()
, and $rootScope.$digest()
but none of those seem to resolve the promises.
My service:
OpsService.service('OpsService', function ($q, $http) {
this.get = {
bigTen : function () {
// var defer = $q.defer();
// defer.resolve({"data":{"alltime":125077,"record":{"date":"2016-07-19","count":825},"today":281}});
// return defer.promise;
return $http({
method: 'GET',
url: '/jsonMocks/api/big-ten.json'
}).then(function (response) {
console.log('bigTen data');
console.log(response);
return response;
}, function (error) {
console.log('ERROR');
console.log(error);
});
},
dashboardData : function () {
console.log('blahhhhh');
return $http({
method: 'GET',
url: '/jsonMocks/api/dashboard-data.json'
}).then(function (response) {
console.log('dasbhoard data');
console.log(response);
return response;
}, function (error) {
console.log('ERROR');
console.log(error);
});
}
};
return this;
});
My controller:
homeModule.controller('HomeController', function ($scope, OpsService) {
var ctrl = this;
ctrl.loading = {
topMetrics: true,
dashboardData: true
};
function init() {
ctrl.topMetricData();
ctrl.getDashboardData();
ctrl.initialized = true;
}
ctrl.topMetricData = function () {
ctrl.loading.topMetrics = true;
console.log('in topMetricData()');
return OpsService.get.bigTen().then(function (bigTen) {
console.log('bigTenControllerCallback');
ctrl.loading.topMetrics = false;
return bigTen;
});
};
ctrl.getDashboardData = function () {
ctrl.loading.dashboardData = true;
console.log('in getDashboardData()');
return OpsService.get.dashboardData().then(function (response) {
console.log('getDashboardDataController Callback');
ctrl.loading.dashboardData = false;
return dashboardData;
});
};
init();
});
My test:
describe('home section', function () {
beforeEach(module('ngMockE2E'));
beforeEach(module('templates-app'));
beforeEach(module('templates-common'));
beforeEach(module('LROps.home'));
var $rootScope, $scope, $httpBackend, createController, requestHandler;
beforeEach(inject(function($injector, _$rootScope_, _$controller_, _OpsService_) {
$rootScope = _$rootScope_;
$httpBackend = $injector.get('$httpBackend');
var bigTenJson = readJSON('jsonMocks/api/big-ten.json');
console.log(bigTenJson);
$httpBackend.when('GET', '/jsonMocks/api/big-ten.json')
.respond(200, { data: bigTenJson });
// .respond(200, { data: 'test1' });
var dashboardDataJson = readJSON('jsonMocks/api/dashboard-data.json');
console.log(dashboardDataJson);
$httpBackend.when('GET', '/jsonMocks/api/dashboard-data.json')
.respond(200, { data: dashboardDataJson });
// .respond(200, { data: 'test2' });
var $controller = _$controller_;
createController = function() {
$scope = $rootScope.$new();
return $controller('HomeController', {
$scope : $scope,
OpsService : _OpsService_
});
};
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should retrieve big ten data', inject(function () {
$httpBackend.expect('GET', '/jsonMocks/api/big-ten.json');
$httpBackend.expect('GET', '/jsonMocks/api/dashboard-data.json');
// Controller Setup
var ctrl = createController();
// Initialize
$rootScope.$apply();
$rootScope.$digest();
expect(ctrl.topMetrics.display.messages.count).toEqual(745);
}));
});
So, none of my console.log() are firing in the .then() callbacks. If I change back to returning a $q.defer().resolve(response).promise
object, it seems to work fine.
Note: I'm using karma-read-json to read the JSON files and respond accordingly in my tests. As far as I can tell, they're being read properly, it's just the promises aren't being resolved so the .then() callbacks can execute.
The first thing is that each asserted request should be mocked request. The requests should be flushed with
$httpBackend.flush()
, it triggers a digest,$rootScope.$apply()
and$rootScope.$digest()
(they duplicate each other) shouldn't be called.The second thing is that it shouldn't be done in controller spec! Controller is a separate unit that depends on a service, it should be tested in isolation with mocked service.
OpsService
is a different unit.EDIT: Looking at the documentation for $httpBackend, the
expect
andwhen
methods don't work together. They're different options for setting up the backend.expect
looks like it adds an expectation that the call will happen, and gives you a .respond() you call call on the result to give what to respond with.when
just lets you set up a response for a particular response without actually saying you expect it.So in your tests the
expect
calls are overwriting thewhen
definition you did, and don't return any response because you didn't configure one.So, I think you can just get rid of the expects and put a
flush
after your controller like so:Or change your
when
s in thebeforeEach
toexpect
s and then you probably won't need theflush
.