Karma / Jasmine指令测试dom编译但无法访问它

时间:2016-11-08 17:57:10

标签: angularjs unit-testing karma-jasmine

我一直试图找出一种方法来测试我的指令的focusElement函数。但不知何故,每当我在测试中调用该函数时,classElements变量都是未定义的。有人有线索吗?

这是指令功能

        $scope.focusElement = function() {
            if (attrs.focusToClass) {
                $scope.classElements = angular.element(document.querySelectorAll('.' + attrs.focusToClass));

                if (attrs.focusToClassIndex) {
                    // Focus to the class with the specified index.
                    // Index should be within the length of elements and must not be a negative number.
                    if (attrs.focusToClassIndex < $scope.classElements.length && attrs.focusToClassIndex >= 0) {
                        $scope.elementToFocus = $scope.classElements[attrs.focusToClassIndex];
                    }
                } else {
                    // Goes to the first index if the index is not specified.
                    $scope.elementToFocus = $scope.classElements[0];
                }
            } else if (attrs.focusToId) {
                // Focus to the given ID
               $scope.elementToFocus = angular.element(document.querySelector('#' + attrs.focusToId))[0];
            }

            if ($scope.elementToFocus) {
                $scope.elementToFocus.focus();
            }
        }

这是单元测试代码。

describe('focusElement function', function () {
    var targetElement;
    var element;
    var elementScope;
    var elementToFocus;

    beforeEach(function() {
        targetElement = $compile('<div id="targetDiv" class="targetClass"><span id="targetSpan" class="targetClass"></span></div>')($rootScope);
        $rootScope.$apply();
    });

    it('should return the class element with index 0', function() {
        element = $compile('<div next-focus focus-to-class="targetClass"></div>')($rootScope);
    });

    it('should return the class element with the specific index within the range', function() {
        element = $compile('<div next-focus focus-to-class="targetClass" focus-to-class-index="1"></div>')($rootScope);
    });

    it('should return the class element with the specific index outside the range', function() {
        element = $compile('<div next-focus focus-to-class="targetClass" focus-to-class-index="-1"></div>')($rootScope);
    });

    it('should return the id element', function() {
        element = $compile('<div next-focus focus-to-id="targetDiv"></div>')($rootScope);
    });

    afterEach(function() {
        elementScope = element.scope();
        spyOn(elementScope, 'focusElement').and.callThrough();
        elementScope.focusElement();
        console.log(elementScope.classElements);

        expect(elementScope.focusElement).toHaveBeenCalled();
        expect(elementScope.elementToFocus).toBeDefined();
        expect(elementScope.elementToFocus.focus).toHaveBeenCalled();
    });
});

Here is the error

1 个答案:

答案 0 :(得分:0)

错误是您在包含被测单元的代码中直接使用document的结果。解决方案是重构代码以不直接使用document,而是使用jQuery样式$()语法来获得相同的行为,使$()操作的上下文成为可注入的依赖,然后在你的单元测试中使用诸如fixtures之类的东西来在测试期间注入一个众所周知的上下文。由于您已经使用了Jasmine,因此您可能希望查看jasmine-jquery以获得方便的API以便轻松完成此操作。

(或者,在此特定情况下,您还可以在document.querySelectorAll回调中设置存根/模拟beforeEach()。)

这就是问题所在的问题,以及如何解决问题(高级别),但在继续之前了解Karma会有所帮助。

跳过许多更精细的点,基本上业力包括三个组合成一个单独的应用程序:

  1. 用于提供内容的可扩展“虚拟”HTTP服务器(在files中配置)。此服务器的结构为Express JS应用程序,如果您想要集成自定义中间件,这将非常有用。例如。在服务器上公开其他路径,以便为您的Angular应用程序代码提供虚拟API服务器以进行交互。要记住的特定路径是'/ base',它对应于您的Karma配置(工作目录)中定义的项目目录。
  2. 一个驱动程序,用于将浏览器指向HTTP服务器上的合成虚拟“index.html”类页面(这是files中加载included: true的所有条目的方式,基本上为{ {1}}标签)。
  3. 用于集成单元测试逻辑,报告等的API /框架。这是<script>类型插件交互的地方,也是Karma如何能够恢复输出并确定测试是否成功的地方。
  4. 第2点和第3点有影响,特别是环境(karma-jasmine)和HTML(window)应该基本上被视为Karma的内部实现细节,而不是在测试期间依赖。这意味着您的测试代码也不应该依赖于这些细节。这就是为什么你应该重构你的代码以传递document作为依赖项的上下文,然后你可以在测试中传递一个众所周知的fixture,并在你的实际应用程序中传递正常的上下文。