如何让 Protractor 不等待 $timeout?
我正在使用 Protractor 测试我的 Angular 应用程序.一旦用户登录到我的应用程序,我设置一个 $timeout 在一小时内完成一些工作(所以如果用户在 13:00 登录,$timeout 将在 14:00 运行).我不断收到这些失败:
I'm testing my angular application with Protractor. Once the user is logged in to my app, I set a $timeout to do some job in one hour (so if the user was logged-in in 13:00, the $timeout will run at 14:00). I keep getting these failures:
"Timed out waiting for Protractor to synchronize with the page after 20 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md. The following tasks were pending: - $timeout: function onTimeoutDone(){....."
我已阅读此超时页面:https://github.com/angular/protractor/blob/master/docs/timeouts.md所以我知道量角器会等到页面完全加载,这意味着他正在等待 $timeout 完成......
I've read this timeouts page: https://github.com/angular/protractor/blob/master/docs/timeouts.md so I understand Protractor waits till the page is fully loaded which means he's waiting for the $timeout to complete...
如何让 Protractor 不等待 $timeout?我不想使用:
How can I make Protractor NOT wait for that $timeout? I don't want to use:
browser.ignoreSynchronization = true;
因为那样我的测试将因其他原因而失败(其他角度组件仍然需要时间来加载...)
Because then my tests will fail for other reasons (other angular components still needs the time to load...)
推荐答案
解决方案是刷新活动超时(@MBielski 在评论中提到它),但原始刷新方法本身仅在 anuglar-mocks 中可用.要直接使用 angular-mocks,您必须将其作为 <script>
标记包含在页面中,并且您必须处理它创建的所有覆盖,它会产生很多副作用.通过侦听创建的任何超时,然后按需重置它们,我能够在不使用 angular-mocks 的情况下重新创建刷新.
The solution will be to flush active timeouts (as @MBielski mentioned it in comments), but original flush method itself is available only in anuglar-mocks. To use angular-mocks directly you will have to include it on the page as a <script>
tag and also you'll have to deal with all overrides it creates, it produces a lot of side effects. I was able to re-create flush without using angular-mocks by listening to any timeouts that get created and then reseting them on demand.
例如,如果您的 Angular 应用程序超时:
For example, if you have a timeout in your Angular app:
$timeout(function () {
alert('Hello World');
}, 10000); // say hello in 10 sec
测试将如下所示:
it('should reset timeouts', function () {
browser.addMockModule('e2eFlushTimeouts', function () {
angular
.module('e2eFlushTimeouts', [])
.run(function ($browser) {
// store all created timeouts
var timeouts = [];
// listen to all timeouts created by overriding
// a method responsible for that
var originalDefer = $browser.defer;
$browser.defer = function (fn, delay) {
// originally it returns timeout id
var timeoutId = originalDefer.apply($browser, arguments);
// store it to be able to remove it later
timeouts.push({ id: timeoutId, delay: delay });
// preserve original behavior
return timeoutId;
};
// compatibility with original method
$browser.defer.cancel = originalDefer.cancel;
// create a global method to flush timeouts greater than @delay
// call it using browser.executeScript()
window.e2eFlushTimeouts = function (delay) {
timeouts.forEach(function (timeout) {
if (timeout.delay >= delay) {
$browser.defer.cancel(timeout.id);
}
});
};
});
});
browser.get('example.com');
// do test stuff
browser.executeScript(function () {
// flush everything that has a delay more that 6 sec
window.e2eFlushTimeouts(6000);
});
expect(something).toBe(true);
});
这有点实验性,我不确定它是否适用于您的情况.也可以通过将 browser.addMockModule
移动到单独的 node.js 模块来简化此代码.如果您想删除短超时(如 100 毫秒)也可能会出现问题,它可以取消当前正在运行的 Angular 进程,因此测试会中断.
It's kinda experimental, I am not sure if it will work for your case. This code can also be simplified by moving browser.addMockModule
to a separate node.js module. Also there may be problems if you'd want to remove short timeouts (like 100ms), it can cancel currently running Angular processes, therefore the test will break.
相关文章