我有一条指令,该指令的行为应有所不同,具体取决于自初始化以来经过的时间:
am.directive('showText', () => ({ restrict: 'E', replace: true, scope: { value: '@' }, controller: ($scope, $timeout) => { console.log('timeout triggered'); $scope.textVisible = false; let visibilityCheckTimeout = $timeout(() => { if (parseInt($scope.value, 10) < 100) { $scope.textVisible = true; } }, 330); // Clear timeout upon directive destruction $scope.$on('$destroy', $timeout.cancel(visibilityCheckTimeout)); }, }));
问题是,当我尝试使用Jasmine进行测试时,我似乎找不到以任何方式触发此超时的方法。已经尝试了$timeout.flush()和$timeout.verifyNoPendingTasks()(如果我要注释flush调用,实际上会引发错误)。但是它仍然没有触发超时的回调执行
$timeout.flush()
$timeout.verifyNoPendingTasks()
flush
describe('showText.', () => { let $compile; let $rootScope; let $scope; let $timeout; const compileElement = (rootScope, value = 0) => { $scope = rootScope.$new(); $scope.value = value; const element = $compile(` <show-text value="value" ></show-text> `)($scope); $scope.$digest(); return element; }; beforeEach(() => { module('app.directives.showText'); inject((_$compile_, _$rootScope_, _$timeout_) => { $compile = _$compile_; $rootScope = _$rootScope_; $timeout = _$timeout_; }); }); it(`Process lasts > 0.33s. Should show text.`, () => { const VALUE = 30; const element = compileElement($rootScope, VALUE); const elementContent = element.find('.show-text__content'); $timeout.flush(1000); $timeout.verifyNoPendingTasks(); $rootScope.$digest(); expect(element.isolateScope().textVisible).toBeTruthy(); expect(elementContent.length).toEqual(1); expect(elementContent.text().trim()).toBe('Example text'); }); });
测试失败。
找不到我在做什么错。关于如何正确测试这种情况的任何提示?
谢谢。
UPD 经过一番调查,我发现在此特定的测试用例中,在compileElement功能上,服务value没有对属性进行评估$compile。和等于"value"。我已经使用同一个函数十次了,但无法$scope.value理解,为什么它不像以前那样具有的属性。
compileElement
value
$compile
"value"
$scope.value
发生这种情况的原因是$timeout.cancel(visibilityCheckTimeout)无条件立即启动。相反,它应该是
$timeout.cancel(visibilityCheckTimeout)
$scope.$on('$destroy', () => $timeout.cancel(visibilityCheckTimeout));
可以做一些事情来提高可测试性(除了在$timeout这里充当一次性示波器观察员并要求用它代替之类的事实之外)。
$timeout
$timeout可以成功[\监视\:
beforeEach(module('app', ($provide) => { $provide.decorator('$timeout', ($delegate) => { var timeoutSpy = jasmine.createSpy().and.returnValue($delegate); angular.extend(timeoutSpy, $delegate); spyOn(timeoutSpy, 'cancel').and.callThrough(); return timeoutSpy; }); }));
私有$timeout回调可以暴露给作用域。
$scope._visibilityCheckHandler = () => { if (parseInt($scope.value, 10) < 100) { $scope.textVisible = true; } }; $timeout($scope._visibilityCheckHandler, 330);
这样,可以监听所有呼叫并获得全部覆盖:
let directiveScope; ... const element = $compile(`...`)($scope); directiveScope = element.isolateScope(); spyOn(directiveScope, '_visibilityCheckHandler').and.callThrough(); $scope.$digest(); ... expect($timeout).toHaveBeenCalledWith(directiveScope._visibilityCheckHandler, 330); expect($timeout.cancel).not.toHaveBeenCalled();
在这种情况下,这里不需要为带有flush延迟参数的’> = \0.33s’和’<0.33s’制定单独的规范,其$timeout内部工作已经在Angular规范中进行了测试。此外,回调逻辑可以与$timeout规范分开进行测试。