我正在测试使用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
我正在嘲笑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
答案 0 :(得分:4)
问题很简单。不需要$apply
内的mapsReadyPromise
,因此当您在测试中执行另一个$apply
时,它会变得疯狂。删除$apply
解决了$digest
问题,然后您只需解决几个问题并准备就绪:)