AngularJS v1.6+Jasmine单元测试percentage指令输入触发问题
解决Angular 1.6 Percentage指令测试触发问题
Hey Carl, 我明白你在测试这个percentage指令时遇到的困扰——明明指令在应用里正常运行,但单元测试就是触发不了它的转换逻辑。别担心,这通常是因为测试中没有正确模拟Angular的数据流和脏检查机制。咱们一步步来解决:
首先,先回顾下你的指令逻辑:它通过ngModel.$parsers把用户输入的百分比(比如50)转成小数(0.5)给模型,用ngModel.$formatters把模型里的小数(0.456)转成四舍五入后的百分比(46)显示在视图。测试时要分别覆盖这两个方向的转换,还要确保触发Angular的更新流程。
正确的测试代码示例
先确保你的测试加载了包含指令的模块,然后按照以下方式编写测试:
describe('percentage directive', () => { let $compile; let $rootScope; // 加载包含指令的应用模块(替换成你实际的模块名) beforeEach(module('yourAppModule')); // 注入编译和根scope服务 beforeEach(inject((_$compile_, _$rootScope_) => { $compile = _$compile_; $rootScope = _$rootScope_; })); // 测试:用户输入百分比 → 模型转为小数 it('parses input percentage to decimal model value', () => { // 编译带指令的input元素 const inputElement = $compile('<input type="text" percentage ng-model="testVal">')($rootScope); $rootScope.$digest(); // 触发初始编译后的脏检查 // 设置输入值并触发Angular监听的input事件 inputElement.val('75').triggerHandler('input'); $rootScope.$digest(); // 让Angular处理模型更新 // 验证模型值是否正确转换 expect($rootScope.testVal).toBe(0.75); }); // 测试:模型小数 → 视图显示四舍五入的百分比 it('formats model decimal to rounded percentage in view', () => { const inputElement = $compile('<input type="text" percentage ng-model="testVal">')($rootScope); // 设置模型值 $rootScope.testVal = 0.333; $rootScope.$digest(); // 触发formatters运行 // 验证视图显示值是否正确 expect(inputElement.val()).toBe('33'); }); });
你可能忽略的关键环节
- 必须触发
input事件:Angular的ngModel是通过监听input元素的input事件来捕获用户输入的,只设置val()不会触发模型更新,必须调用triggerHandler('input')。 - 别忘了
$digest():Angular的脏检查机制需要手动触发(在测试环境中),不管是编译后、设置输入值后还是修改模型值后,都要调用$rootScope.$digest()来让指令的$parsers或$formatters执行。 - 模块加载要正确:如果测试时没加载包含这个指令的模块,Angular根本不知道有这个指令存在,自然不会生效。
可选优化:处理边界值
你的指令目前没处理空值、NaN等情况,建议补充下,避免测试或实际使用中出现异常:
.directive('percentage', function() { return { restrict: 'A', require: 'ngModel', link: function(scope, element, attr, ngModel) { function fromUser(value) { // 处理空值、非数字情况 if (value == null || isNaN(parseFloat(value))) { return value; } return parseFloat(value) / 100; } function toUser(value) { if (value == null || isNaN(parseFloat(value))) { return ''; } return Math.round(parseFloat(value) * 100).toString(); } ngModel.$parsers.push(fromUser); ngModel.$formatters.push(toUser); } }; });
这样测试空输入或无效值时也能正常运行啦。
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

