【问题标题】:AngularJS: Unit Testing Directive w/ Promise returned from a ServiceAngularJS:带有从服务返回的 Promise 的单元测试指令
【发布时间】:2014-02-27 06:04:08
【问题描述】:

我有一个使用 Service 的指令,调用返回 Promise 的服务方法,并在后续的“then”(下面的 myTestDirective)中修改 DOM。

我正在尝试对该指令进行单元测试,但当我运行测试时,'then' 内部的任何内容都没有被调用:promise 被拒绝或解决方案未传播?

我按照this post 中的所有步骤设置我的单元测试

当我在浏览器中加载指令时,我看到两条消息,OUTSIDE D3 然后 INSIDE D3,如您所料。

但在单元测试中,元素仅使用第一条消息更新,如下所示:
<my-test-directive>***OUTSIDE D3***</my-test-directive>.
在浏览器中,我看到了两条消息。

有人知道这里发生了什么吗,我需要注入 mock 或 spyOn 的东西吗?这是在脚本标签完成加载之前运行测试的异步问题吗?我看到单元测试访问 d3.v3.js,所以它似乎发生了脚本标记。我还对 d3Service 自己进行了单元测试,并且可以正常工作。偶尔,我实际上在完全不更改测试的情况下看到了正确的结果。

我在这个问题中看到了线索,但无法理解如何在我的情况下应用它:Angularjs promise not being resolved in unit test

代码如下:

d3Service

var d3 = angular.module('d3', []);

d3.factory('d3Service', ['$document', '$q', '$rootScope', '$window',
    function($document, $q, $rootScope, $window) {
        var d = $q.defer();

        function onScriptLoad() {
            $rootScope.$apply(function() { d.resolve(window.d3); });
        }

        var scriptTag = $document[0].createElement('script');
        scriptTag.type = 'text/javascript'; 
        scriptTag.async = true;
        scriptTag.src = 'lib/d3.v3.js';

        scriptTag.onreadystatechange = function () {
            if (this.readyState == 'complete') onScriptLoad();
        }

        scriptTag.onload = onScriptLoad;

        var s = $document[0].getElementsByTagName('body')[0];
        s.appendChild(scriptTag);

        return {
            d3: function() { return d.promise; }
        };

    }]);

指令

var myDirectives = angular.module('myDirectives', ['d3']);

myDirectives.directive('myTestDirective', ['d3Service', '$window', 
    function(d3Service, $window) {
        return {
            restrict: 'EA',

            link: function(scope, ele, attrs) {

                var f = angular.element(ele[0])
                f.append('**OUTSIDE D3***')

                d3Service.d3().then(function(d3){    // Nothing here runs at all.
                    var e = angular.element(ele[0])  // In browser it works, but
                    e.append('***INSIDE D3***')      // not in the unit test.
                })
            }
        }           
    }])

单元测试

describe('Test Directive', function(){

    var $scope, elem, compiled, html;

  beforeEach(function (){      
    module('myDirectives');    
    html = '<my-test-directive></my-test-directive>'; 
    inject(function($compile, $rootScope) {
      $scope = $rootScope;
      elem = angular.element(html);
      compiled = $compile(elem)($scope);

      $scope.$digest();      
    });
  });   

    it('should create an svg element with its data', function(){
        console.log(elem) //outputs the element with only ***OUTSIDE D3***
    })

})

感谢您提供任何提示或信息!!!!!!

【问题讨论】:

    标签: javascript angularjs unit-testing d3.js


    【解决方案1】:

    我所做的是在我的 karma.conf 中加载 d3.v3.js,然后在返回承诺的单元测试中创建 mockd3Service。如果有人知道更好的解决方案,请告诉我。

    这是正在运行的新单元测试:

        describe('d3 Directives', function(){
    
            var $compile, $rootScope, $window, mockd3Service, $q, html, element, data;
    
            //setup test
            beforeEach(function(){
                mockd3Service = {}
                module('myDirectives')
    
                module(function($provide){
                    $provide.value('d3Service', mockd3Service)
                })
    
                inject(function(_$compile_, _$rootScope_, _$window_, _$q_) {
                    $window = _$window_;
                    $compile = _$compile_;
                    $rootScope = _$rootScope_;
                    $q = _$q_
                });
    
                mockd3Service.d3 = function() {
                    var deferred = $q.defer();
                    deferred.resolve($window.d3)
                    return deferred.promise;
                }
    
            });
    
            //run test
            it('make test', function(){
                html = '<my-directive data="testData"></my-directive>'
                element = angular.element(html)
                element = $compile(html)($rootScope)        
                $rootScope.testData = somedata
                $rootScope.$digest();
    
                expect(element...)
    
            })
        })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-12
      • 2014-05-19
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多