javascript - How to avoid $digest already in progress during testing -
i'm banging head around testing service uses google maps geoencoding service. thought going easy since it's straightforward code. seems it's not.
here service:
(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]); }());
in order not use real google.maps
i'm mocking both googleapiloaderservice , google.maps
.
however, when try test it, $digest in progress
. i've tried safeapply
won't work.
it('should call geocoder.geocode retrieve results', function () { googlegeocoding.getlatlng('canada'); $rootscope.$apply(); expect(geocodermock.prototype.geocode).tohavebeencalledwith({ address : 'canada'}); });
this full spec:
(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 functions', function(){ expect(typeof googlegeocoding.getlatlng).tobe('function'); }); describe('getlatlng function', function () { it('shouldn\'t call if promise hasn\'t been resolved', function () { googlegeocoding.getlatlng('canada'); expect(geocodermock.prototype.geocode).not.tohavebeencalled(); }); it('should return promise', function () { var promise = googlegeocoding.getlatlng('canada'); expect(typeof promise.then).tobe('function'); }); it('should call geocoder.geocode retrieve results', function () { googlegeocoding.getlatlng('canada'); $rootscope.$apply(); expect(geocodermock.prototype.geocode).tohavebeencalledwith({ address : 'canada'}); }); it('should resolve promise when receiving data', function () { var okmock = jasmine.createspy(); googlegeocoding.getlatlng('canada').then(okmock); $rootscope.$apply(); expect(okmock).tohavebeencalledwith({ address : 'canada'}); }); }); }); }());
faq:
- have tried
$$phase
checking?
yes. doesn't work. somehow phase null @ point. fear calling $apply
i'm unleashing 2 of them how, causing issue.
- can provide plunker this?
yes of course! link plunker
the problem simple. $apply
inside mapsreadypromise
not needed when $apply
on test, gets crazy. removing $apply
resolved $digest
problem, needed fix couple of issues , ready :)
Comments
Post a Comment