我正在努力测试使用 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吗?

  • 是的当然!链接到 Plunker

    最佳答案

    问题很简单。 $apply 中的 mapsReadyPromise 不是必需的,因此当您在测试中执行另一个 $apply 时,它​​会变得疯狂。删除 $apply 解决了 $digest 问题,然后您只需要修复几个问题就可以了:)

    http://plnkr.co/edit/wRdJNqAk9RZ7vg3Dli6K?p=preview

    关于javascript - 如何避免在测试期间已经进行的 $digest,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22222040/

    10-12 12:39
    查看更多