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-link
和 post-link
函数按预期执行。
我有一个通过 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-link
和 post-link
函数按预期执行。