我有一个像下面这样的组件,并希望测试$onChange方法在绑定myBinding更改时的作用.
我整个上午都试过,但找不到办法解决这个问题.
angular .module('project.myComponent',[]) .component('myComponent',{ bindings: { myBinding: '<' },template: '<div>{{$ctrl.result}}</div>',controller: myComponentController }); function myComponentController($filter,someService) { var ctrl = this; ctrl.result = 0; $ctrl.$onChange = function (changes) { if(angular.isDefined(changes.myBinding)) { if(angular.isDefined(changes.myBinding.currentValue)) { if(angular.isDefined(changes.myBinding.currentValue != changes.myBinding.prevIoUsValue)) { myService.doSomething(changes.myBinding.currentValue).then( function(data) { ctrl.result = changes.myBinding.currentValue * 3; } ); } } } } }
我希望我的测试表现得像是更改绑定值的组件父级.
require('angular-mocks'); describe('myComponment',function() { var element,scope; beforeEach(inject(function(_$rootScope_,_$compile_) { })); fit('should display the controller defined title',function() { // prepare test and set myBinding to 10 expect(component.result).toBe(30); }); });
那可能吗?怎么样?
任何提示? Plunker,CodePen还是其他例子?
解决方法
测试AngularJS组件与测试指令没有太大差别.
要测试控制器的方法/属性,可以使用element.controller("componentName")
method访问组件控制器的实例(componentName – 是camelCase指令/组件名称).
下面是使用$compile
service测试组件和$onChanges钩子的示例:
angular.module('myApp',[]) .component('myComponent',{ bindings: { myBinding: '<' },controller: 'myComponentController' }) .controller('myComponentController',['$filter','myService',function myComponentController($filter,myService) { var ctrl = this; ctrl.$onInit = onInit; ctrl.$onChanges = onChanges; function onInit() { ctrl.result = ctrl.myBinding; } function onChanges(changes) { if (angular.isDefined(changes.myBinding)) { if (angular.isDefined(changes.myBinding.currentValue)) { if (!angular.equals(changes.myBinding.currentValue,changes.myBinding.prevIoUsValue)) { myService.doSomething(changes.myBinding.currentValue).then( function (data) { ctrl.result = data; } ); } } } } }]) .service('myService',['$timeout',function ($timeout) { return { doSomething: function (x) { return $timeout(function () { return x * 3; },500); } }; }]); /* TEST GO HERE */ describe('Testing a component controller',function() { var $scope,ctrl,$timeout,myService; beforeEach(module('myApp',function ($provide) { })); beforeEach(inject(function ($injector) { myService = $injector.get('myService'); $timeout = $injector.get('$timeout'); })); describe('with $compile',function () { var element; var scope; var controller; beforeEach(inject(function ($rootScope,$compile) { scope = $rootScope.$new(); scope.myBinding = 10; element = angular.element('<my-component my-binding="myBinding"></my-component>'); element = $compile(element)(scope); controller = element.controller('myComponent'); scope.$apply(); })); it('should render template',function () { expect(element[0].innerText).toBe('10'); //initial $timeout.flush(); //onchanges happened and promise resolved from the service //undefined -> 10 expect(element[0].innerText).toBe('30'); }); it('should reflect to changes',function () { spyOn(myService,"doSomething").and.callThrough(); scope.myBinding = 15; //change the binding scope.$apply(); //we need to call $apply to pass the changes down to the component $timeout.flush(); expect(myService.doSomething).toHaveBeenCalled(); // check if service method was called expect(controller.result).toBe(45); // check controller's result value }); }) });
.as-console-wrapper { height:0; }
<!DOCTYPE html> <html> <head> <!-- jasmine --> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.js"></script> <!-- jasmine's html reporting code and css --> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine-html.js"></script> <link href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.css" rel="stylesheet" /> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/boot.js"></script> <!-- angular itself --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script> <!-- angular's testing helpers --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-mocks.js"></script> </head> <body> <!-- bootstrap jasmine! --> <script> var jasmineEnv = jasmine.getEnv(); // Tell it to add an Html Reporter // this will add detailed HTML-formatted results // for each spec ran. jasmineEnv.addReporter(new jasmine.HtmlReporter()); // Execute the tests! jasmineEnv.execute(); </script> </body> </html>
您还可以使用$componentController
service测试组件.但在这种情况下,您需要在测试中显式调用生命周期钩子,例如:
ctrl = $componentController('myComponent',{$scope: scope},{ myBinding: 10 }); ctrl.$onInit();
要测试$onChanges钩子,您需要传递一个“正确”构造的更改对象作为参数:
angular.module('myApp',controller: 'myComponentController' }) .controller('myComponentController',myService) { var ctrl = this; ctrl.$onInit = onInit; ctrl.$onChanges = onChanges; function onInit() { ctrl.result = ctrl.myBinding; } function onChanges(changes) { if (angular.isDefined(changes.myBinding)) { if (angular.isDefined(changes.myBinding.currentValue)) { if (!angular.equals(changes.myBinding.currentValue,changes.myBinding.prevIoUsValue)) { myService.doSomething(changes.myBinding.currentValue).then( function (data) { ctrl.result = data; } ); } } } } }]) .service('myService',function ($timeout) { return { doSomething: function (x) { return $timeout(function () { return x * 3; },500); } }; }]); /* TEST GO HERE */ describe('Testing a component controller',function () { var $scope,myService; beforeEach(module('myApp',function ($provide) { })); beforeEach(inject(function ($injector) { myService = $injector.get('myService'); $timeout = $injector.get('$timeout'); })); describe('with $componentController',function () { var scope; var controller; beforeEach(inject(function ($rootScope,$componentController) { scope = $rootScope.$new(); scope.myBinding = 10; controller = $componentController('myComponent',{myBinding: 10}); controller.$onInit(); })); it('should reflect to changes',function () { spyOn(myService,"doSomething").and.callThrough(); controller.$onChanges({myBinding: {currentValue: 15,prevIoUsValue: 10}}); $timeout.flush(); // resolve service promise expect(myService.doSomething).toHaveBeenCalled(); // check if service method was called expect(controller.result).toBe(45); // check controller's result value }); }) });
.as-console-wrapper { height:0; }
<!DOCTYPE html> <html> <head> <!-- jasmine --> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.js"></script> <!-- jasmine's html reporting code and css --> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine-html.js"></script> <link href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.css" rel="stylesheet" /> <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/boot.js"></script> <!-- angular itself --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script> <!-- angular's testing helpers --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-mocks.js"></script> </head> <body> <!-- bootstrap jasmine! --> <script> var jasmineEnv = jasmine.getEnv(); // Tell it to add an Html Reporter // this will add detailed HTML-formatted results // for each spec ran. jasmineEnv.addReporter(new jasmine.HtmlReporter()); // Execute the tests! jasmineEnv.execute(); </script> </body> </html>
P.S.:$onChange不是组件生命周期钩子的有效名称.它should be $onChanges
.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。