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:
我正在使用Protractor测试我的角度应用程序。一旦用户登录到我的应用程序,我设置$ timeout以在一小时内完成某项工作(因此,如果用户在13:00登录,则$ timeout将在14:00运行)。我一直遇到这些失败:
"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(){....."
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...
我已经阅读了这个超时页面:https://github.com/angular/protractor/blob/master/docs/timeouts.md所以我理解量角器等待页面完全加载,这意味着他正在等待$ 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...)
因为那时我的测试会因其他原因而失败(其他角度组件仍然需要加载的时间......)
2 个解决方案
#1
3
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.
解决方案是刷新活动超时(正如@MBielski在评论中提到的那样),但原始的flush方法本身仅在anuglar-mocks中可用。要直接使用角度模拟,您必须将其作为
For example, if you have a timeout in your Angular app:
例如,如果您的Angular应用中有超时:
$timeout(function () {
alert('Hello World');
}, 10000); // say hello in 10 sec
The test will look like:
测试看起来像:
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);
});
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.
这有点实验性,我不确定它是否适用于您的情况。通过将browser.addMockModule移动到单独的node.js模块,也可以简化此代码。如果你想删除短暂的超时(如100ms),也可能会有问题,它可以取消当前运行的Angular进程,因此测试会中断。
#2
0
The solution is to use interceptors and modify the http request which is getting timeout and set custom timeout to some milliseconds(your desired) to that http request so that after sometime long running http request will get closed(because of new timeout) and then you can test immediate response.
解决方案是使用拦截器并修改http请求,该请求正在超时并将自定义超时设置为该http请求的某个毫秒(您的期望),以便在某个时间之后长时间运行的http请求将被关闭(因为新的超时)然后您可以测试立即响应。
This is working well and promising.
这很好,也很有前景。
#1
3
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.
解决方案是刷新活动超时(正如@MBielski在评论中提到的那样),但原始的flush方法本身仅在anuglar-mocks中可用。要直接使用角度模拟,您必须将其作为
For example, if you have a timeout in your Angular app:
例如,如果您的Angular应用中有超时:
$timeout(function () {
alert('Hello World');
}, 10000); // say hello in 10 sec
The test will look like:
测试看起来像:
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);
});
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.
这有点实验性,我不确定它是否适用于您的情况。通过将browser.addMockModule移动到单独的node.js模块,也可以简化此代码。如果你想删除短暂的超时(如100ms),也可能会有问题,它可以取消当前运行的Angular进程,因此测试会中断。
#2
0
The solution is to use interceptors and modify the http request which is getting timeout and set custom timeout to some milliseconds(your desired) to that http request so that after sometime long running http request will get closed(because of new timeout) and then you can test immediate response.
解决方案是使用拦截器并修改http请求,该请求正在超时并将自定义超时设置为该http请求的某个毫秒(您的期望),以便在某个时间之后长时间运行的http请求将被关闭(因为新的超时)然后您可以测试立即响应。
This is working well and promising.
这很好,也很有前景。