I have an AngularJS service that returns a promise.
Although the code works fine, the test gives me some difficulties, since the "then" promise method is never called in my unit test.
The general answer is a call $rootScope.$apply(), as mentioned in the post “ Continuous AngularJS Callback in JasmineJS Test ”. However, if I do, my test tries to load load templates/home.html, which is not expected:
PhantomJS 1.9.7 (Linux) Controller: ScanCtrl should invoke the barcode scanner when it is available FAILED
Error: Unexpected request: GET templates/home.html
No more request expected
If I don’t include it $rootScope.$apply(), the then method of this promise is never called, and I get an error that my spy is not being called as expected:
PhantomJS 1.9.7 (Linux) Controller: ScanCtrl should invoke the barcode scanner when it is available FAILED
Expected spy go to have been called with [ 'enterQuantity', { barcodeId : '888888888888' } ] but it was never called.
, : , ? $rootScope.$apply()? , templates/home.html, $rootScope.$apply()?
.factory('BarcodeScannerService', ['$q', function ($q) {
return {
scanBarcode: function () {
var deferred = $q.defer();
plugins.barcodeScanner.scan(
function (result) {
console.log("We got a barcode\n" +
"Result: " + result.text + "\n" +
"Format: " + result.format + "\n" +
"Cancelled: " + result.cancelled);
deferred.resolve({"error": false, "barcode": result.text});
},
function (error) {
deferred.resolve({"error": true});
});
return deferred.promise;
}
};
}]
)
Unit Test
it('should invoke the barcode scanner when it is available', function () {
inject(function ($controller, $rootScope, $q) {
scope = $rootScope.$new();
$rootScopeHolder = $rootScope;
var deferred = $q.defer();
barcodeScannerServiceMock.scanBarcode = jasmine.createSpy('scanBarcode').andReturn(deferred.promise);
deferred.resolve({"error": false, "barcode": fakeBarcode2});
barcodeScannerServiceMock.isAvailable = jasmine.createSpy('isAvailable').andReturn(true);
ScanCtrl = $controller('ScanCtrl', {
$scope: scope,
$window: windowMock,
Items: itemMock,
BarcodeScannerService: barcodeScannerServiceMock,
$state: stateMock
});
});
expect(barcodeScannerServiceMock.isAvailable).toHaveBeenCalled();
expect(barcodeScannerServiceMock.scanBarcode).toHaveBeenCalled();
expect(stateMock.go).toHaveBeenCalledWith('enterQuantity', { barcodeId: fakeBarcode2 });
});
.controller('ScanCtrl', function ($scope, $timeout, $ionicModal, $state, BarcodeScannerService, $window) {
$scope.handleBarcodeScanError = function () {
var r = $window.confirm("Scanning failed. Try again?");
if (r === true) {
$state.go('scan');
}
else {
$state.go('home');
}
};
console.log("Scanner Avaialble?" + BarcodeScannerService.isAvailable());
if (BarcodeScannerService.isAvailable() === true) {
var barcodeResult = {};
BarcodeScannerService.scanBarcode()
.then(function(result){
barcodeResult = result;
if (barcodeResult.error === false) {
$state.go('enterQuantity', {barcodeId: barcodeResult.barcode});
}
else {
$scope.handleBarcodeScanError();
}
}, function(error){
$scope.handleBarcodeScanError();
});
}
else {
var tempBarcode = $window.prompt('Enter barcode:');
$state.go('enterQuantity', {barcodeId: tempBarcode});
}
}
)
:
https://github.com/derekdata/barcode-cart-builder/
: www/js/app.js
: www/js/services/services.js
: www_test/spec/controllers/ScanCtrlTest.js
, .