angularjs:测试基于控制器的指令

angularjs: Testing Controller-based Directive

我有一个通过 ngController 绑定到控制器的指令,如下所示:

app.directive('myDirective', ['myService',
    function(myService) {
        return {
            restrict: 'E',
            replace: true,
            scope: true,
            require: "^ngController",
            templateUrl: 'template.html',
            link: {
                pre: function (scope, elem, attrs, controller) {
                    scope.list = [];
                    myService.getData().then(function (response) {
                        scope.list = response.data;
                    });
                },
                post: function (scope) {
                    for (var rec = 0; rec < scope.list.length; rec++) {
                        if (scope.list[rec].key2 == 'd') {
                            // Do something here..
                        }
                    }
                }
            }
        };
    }
]);

使用了示例控制器(因为这个指令在多个地方使用):

app.controller('testController', [
    function () {
        var testCtrl = this;
    }
]);

指令的测试用例是:

describe('myDirective', function () {
    var element, scope, ctrl;
    beforeEach(angular.module('myModule'));
    beforeEach(inject(function ($rootScope, $compile, $controller, $httpBackend) {
        mockBackEnd = $httpBackend;

        // Call to myService.getData()
        mockBackEnd.expectGET('/module/service/api').respond({
            values: [{key1: a, key2: b}, {key1: c, key2: d}]
        });

        element = angular.element('<div ng-controller="testController"><my-directive></my-directive></div>');
        ctrl = $controller('testController', {});
        scope = $rootScope.$new();
        compile(element)(scope);
        mockBackEnd.flush();
        scope.$digest();
    }));

    it('Test for response', function () {
        expect(scope.list.length).toBe(2);
    });
});

我收到一条错误消息:PhantomJS 1.9.8 myDirective FAILED TypeError: 'undefined' is not an object (evaluating 'scope.list.length')

进一步检查:在检查 $digest() 发生的位置时,发现在 post: link 函数中, scope.list 对象显示为 [] 其中 as应该是服务的返回值。

该指令在模块中工作正常,但在测试用例中抛出问题。

我在这里做错了什么?在业力方面需要一些帮助。

抱歉@curlyreggie,当我看你的代码时,我真的不明白为什么它这么复杂?

为什么不将数据作为数组或 JSON 对象传递到指令范围?

为什么要在 ng-controller 中使用指令?

无论如何,要在测试中向您的指令添加一些 AngularJS 函数,请使用 angular.element()。

var compile = $compile; // is missing in your code
scope = $rootScope.$new();

var element = angular.element('<my-directive ng-controller="testController">Add all parameters, as you usually do in your html, if missing anything</my-directive>');
compile(element)(scope);
scope.$digest();

// Get the isolate scope for the directive
var isolatedScope = element.isolateScope();
console.log("isolatedScope", isolatedScope);

而'mockBackEnd' 通常我是这样注入的:

beforeEach(inject(function ($rootScope, $compile, $controller, $injector) {
   mockBackEnd = $injector.get('$httpBackend');
   .....
}

不确定这是否有效,但至少我尽力帮助了你 :)

好吧,我借助一些帮助解决了它 from the community

事实是,根据此处 comments/answers,我做的测试不正确。实际的测试用例设置应该是。

describe('myDirective', function () {
   var element, scope, ctrl, directiveScope;
   beforeEach(angular.module('myModule'));
   beforeEach(inject(function ($rootScope, $compile, $controller, $httpBackend) {
      mockBackEnd = $httpBackend;

      // Call to myService.getData()
      mockBackEnd.expectGET('/module/service/api').respond({
        values: [{key1: a, key2: b}, {key1: c, key2: d}]
      });

      ctrl = $controller('testController', {});
      scope = $rootScope.$new();
      element = $compile(angular.element('<div ng-controller="testController"><my-directive></my-directive></div>'))(scope);
      directiveScope = element.find('my-directive').scope();
      scope.$digest();
      mockBackEnd.flush();
}));

it('Test for response', function () {
    expect(directiveScope.list.length).toBe(2);
});

我在这里摆弄父作用域,无法从外部访问指令的作用域。使用 element.find().scope() 首先获取该范围并方便地使用它。

在我修改为这个新代码后,pre-linkpost-link 函数按预期执行。