gpt4 book ai didi

angularjs - 如何测试父元素对组件绑定(bind)的更改?

转载 作者:行者123 更新时间:2023-12-04 15:18:14 25 4
gpt4 key购买 nike

我有一个如下组件,想测试 $onChange方法在绑定(bind) 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;
}
);
}
}
}
}
}

我希望我的测试表现得像改变绑定(bind)值的组件父级一样。
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 组件与测试指令没有太大区别。

要测试 Controller 的方法/属性,您可以使用 element.controller("componentName") method 访问组件 Controller 的实例。 ( componentName - 是一个驼峰式指令/组件名称)。

这是使用 $compile service 的示例测试组件和$onChanges钩:

angular.module('myApp', [])
.component('myComponent', {
bindings: {
myBinding: '<'
},
template: '<div>{{$ctrl.result}}</div>',
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 测试您的组件。 .但在这种情况下,您需要在测试中显式调用生命周期 Hook ,例如:
ctrl = $componentController('myComponent', {$scope: scope}, { myBinding: 10 });
ctrl.$onInit();

测试 $onChanges钩子(Hook),您将需要传递一个“正确”构造的更改对象作为参数:

angular.module('myApp', [])
.component('myComponent', {
bindings: {
myBinding: '<'
},
template: '<div>{{$ctrl.result}}</div>',
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 $componentController', function () {
var scope;
var controller;

beforeEach(inject(function ($rootScope, $componentController) {
scope = $rootScope.$new();
scope.myBinding = 10;

controller = $componentController('myComponent', {$scope: scope}, {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>


附: $onChange不是组件生命周期 Hook 的有效名称。它 should be $onChanges .

关于angularjs - 如何测试父元素对组件绑定(bind)的更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48101798/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com