【问题标题】:How to mock a d3.json() call in Angular app with Jasmine tests with Karma task runner如何使用 Karma 任务运行器在带有 Jasmine 测试的 Angular 应用程序中模拟 d3.json() 调用
【发布时间】:2015-06-23 21:35:14
【问题描述】:

我正在尝试使用 Jasmine 和 Karma 任务运行器测试我的 d3 和 Angular 应用程序。当我在浏览器中使用该应用程序时它可以工作,但我在设置测试时遇到问题。我也在用browserify。

工厂服务加载世界地图服务使用的 d3 依赖项(而不是将 d3 放在脚本标签中),此 控制器 和指令(如下):

.factory('d3Service', ['$document', '$q', '$rootScope', '$window', d3Service])
.service('Category', ['$http', categoryService])
//most of the d3 methods are in this service
.service('WorldMap', ['d3Service', worldMapService])
.controller('MapCtrl', ['$scope', 'd3Service', 'Category', '$http',
    function($scope, d3Service, Category, $http) {
        // waits until d3 is loaded then gets the world
        // data json file and set to controller's scope
        d3Service.d3().then(function(d3){
            $http.get("world.json").success(function(world) {
               $scope.countries = topojson.feature(world, world.objects.countries).features;
            });
        });
    }
])
//the directive is what contains the d3 map
.directive('wmMap', ['d3Service', 'Category', '$window', 'ngDialog', 'WorldMap', wmMap]);

指令同样等待d3依赖加载:

var wmMap = function(d3Service, Category, $window, ngDialog, WorldMap){
    return {
        restrict: 'EA',
        link: function(scope, ele, attrs){
            d3Service.d3().then(function(d3) {              

                //do some stuff

                // when world data json is loaded and scope is set 
                // call render to set map on page
                scope.$watch('countries', function(countries){

                    if(countries !== undefined){
                        WorldMap.render(ele[0], zoom, countries, Category, ngDialog);
                    }
                });
            });
        }
    }
}

测试 - 使用 $httpBackend.expectGet() 设置一些数据,然后使用 $httpBackend.flush() 将其加载到“it”块中的测试中。应该为 $scope.countries 加载的 $scope 数据不存在...?

describe('d3', function(){
        var data, $q, $rootScope, $compile, $window, $httpBackend, html, element;       

        beforeEach(function(){
            mockd3Service = {};
            mockMapService = {};
            module('WorldMaps');
            //provide services
            module(function($provide){
                $provide.value('d3Service', mockd3Service);
                $provide.value('WorldMap', mockMapService);
            });

            inject(function($injector,_$compile_, _$rootScope_, _$window_, _$q_, _$controller_, _$httpBackend_){
                $window = _$window_;
                $compile = _$compile_;
                $rootScope = _$rootScope_;
                $controller = _$controller_;
                $q = _$q_;
                $httpBackend = _$httpBackend_;

                // load in some mock data for http request
                $httpBackend.expectGET('world.json')
                .respond({arcs: ['abc'],
                        objects: {countries: {geometries: [{arcs:[], id: "Netherlands", type: "Polygon"}]}},
                        transform: {scale: [], translate: []},
                        type: "Topology"}
                        );

                $scope = $rootScope.$new();
            });

            mockd3Service.d3 = function(){
                var deferred = $q.defer();
                deferred.resolve($window.d3);           
                return deferred.promise;
            }
        });

        it('created', function(){
            //check d3 service is running
            html = '<wm-map></wm-map>';
            element = angular.element(html);
            element = $compile(html)($rootScope);
            $rootScope.$digest();

            expect($scope.countries).toBeUndefined();
            ctrl = $controller('MapCtrl', {'$scope' : $scope});
            $httpBackend.flush();

            //$scope is logged out with a countries property 
            //but countries is undefined
            console.log($scope);
        });

    })

【问题讨论】:

    标签: javascript angularjs d3.js jasmine karma-jasmine


    【解决方案1】:

    您可以改为使用 $http 获取 JSON 文件并使用 $httpBackend 模拟该文件,然后将 JSON 数据传递给 D3。

    当然,如果您尝试测试 D3 渲染,这种方法并不能解决这个问题,但如果您只想确保发出 HTTP 请求,则可以采用这种方法。

    【讨论】:

    • 谢谢 - 是的,我可以这样做,但正如你所说,我正在尝试测试 d3.json 调用
    • 我已编辑上述问题以符合您 (@Tina) 的回答。有谁知道为什么 $scope.countries 未定义?
    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 2017-05-01
    • 1970-01-01
    相关资源
    最近更新 更多