我正在努力测试使用 Google Maps Geoencoding 服务的服务。认为这会很容易,因为它是非常简单的代码。但似乎不是。
这是服务:
(function () {
'use strict';
var GoogleGeocodingService = function ($q, GoogleAPILoaderService, $rootScope) {
var geocoder,
mapsReadyPromise;
mapsReadyPromise = GoogleAPILoaderService.load('maps', '3', {other_params: 'sensor=false'}).then(function() {
geocoder = new google.maps.Geocoder();
});
var getLatLng = function (searchKeyword) {
var deferred = $q.defer();
mapsReadyPromise.then(function () {
geocoder.geocode({'address': searchKeyword}, function (results, status) {
$rootScope.$apply(function () {
if (status === google.maps.GeocoderStatus.OK) {
deferred.resolve(results);
} else {
deferred.reject(status);
}
});
});
});
return deferred.promise;
};
return {
getLatLng: getLatLng
};
};
app.factory('GoogleGeocodingService', ['$q', 'GoogleAPILoaderService', '$rootScope', GoogleGeocodingService]);
}());
为了不使用真正的
google.maps
我正在 mock GoogleAPILoaderService 和 google.maps
。但是,当我尝试对其进行测试时,我进入了
$digest already in progress
。我试过 safeApply
但不起作用。it('Should call geocoder.geocode to retrieve results', function () {
GoogleGeocoding.getLatLng('Canada');
$rootScope.$apply();
expect(GeoCoderMock.prototype.geocode).toHaveBeenCalledWith({ address : 'Canada'});
});
这是完整的规范:
(function () {
"use strict";
var GeoCodingOK, GeoCodingError, GeoCoderMock, GoogleAPILoaderMock, $rootScope, $q, $timeout, GoogleGeocoding;
describe('Google Geocoding Service', function () {
beforeEach(angular.mock.module('app', function($provide){
GoogleAPILoaderMock = jasmine.createSpyObj('GoogleAPILoaderService',['load']);
$provide.value('GoogleAPILoaderService',GoogleAPILoaderMock);
}));
beforeEach(inject(function (_$q_,_$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
GoogleAPILoaderMock.load.andCallFake(function () {
var deferred = $q.defer();
deferred.resolve('Library Loaded');
return deferred.promise;
});
}));
beforeEach(inject(function (GoogleGeocodingService) {
GoogleGeocoding = GoogleGeocodingService;
window.google = jasmine.createSpy('google');
window.google.maps = jasmine.createSpy('maps');
window.google.maps.GeocoderStatus = jasmine.createSpy('GeocoderStatus');
window.google.maps.GeocoderStatus.OK = 'OK';
GeoCodingOK = function (params, callback) {
callback({data: 'Fake'}, 'OK');
};
GeoCodingError = function (params, callback) {
callback({data: 'Fake'}, 'ERROR');
};
GeoCoderMock = window.google.maps.Geocoder = jasmine.createSpy('Geocoder');
GeoCoderMock.prototype.geocode = jasmine.createSpy('geocode').andCallFake(GeoCodingOK);
}));
it('Should expose some functions', function(){
expect(typeof GoogleGeocoding.getLatLng).toBe('function');
});
describe('getLatLng function', function () {
it('Shouldn\'t call anything if the promise hasn\'t been resolved', function () {
GoogleGeocoding.getLatLng('Canada');
expect(GeoCoderMock.prototype.geocode).not.toHaveBeenCalled();
});
it('Should return a promise', function () {
var promise = GoogleGeocoding.getLatLng('Canada');
expect(typeof promise.then).toBe('function');
});
it('Should call geocoder.geocode to retrieve results', function () {
GoogleGeocoding.getLatLng('Canada');
$rootScope.$apply();
expect(GeoCoderMock.prototype.geocode).toHaveBeenCalledWith({ address : 'Canada'});
});
it('Should resolve the promise when receiving data', function () {
var okMock = jasmine.createSpy();
GoogleGeocoding.getLatLng('Canada').then(okMock);
$rootScope.$apply();
expect(okMock).toHaveBeenCalledWith({ address : 'Canada'});
});
});
});
}());
常见问题解答 :
$$phase
检查吗? 是的。不起作用。不知何故,此时相位为零。我担心通过调用
$apply
我会释放其中的两个,这会导致问题。是的当然!链接到 Plunker
最佳答案
问题很简单。 $apply
中的 mapsReadyPromise
不是必需的,因此当您在测试中执行另一个 $apply
时,它会变得疯狂。删除 $apply
解决了 $digest
问题,然后您只需要修复几个问题就可以了:)
http://plnkr.co/edit/wRdJNqAk9RZ7vg3Dli6K?p=preview
关于javascript - 如何避免在测试期间已经进行的 $digest,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22222040/