我有一个中等大小的Angular应用程序,由于某些原因,我的一些量角器测试在我的实时生产环境中运行时超时。
我很确定超时发生是因为量角器等待某个异步任务。我知道区域,我试图将所有长时间运行的异步任务保留在ngZone之外(根据the FAQ),但由于某种原因,量角器仍然超时。
我可能错过了一些东西,但我不知道如何调试问题。 有没有办法找出代码量角器的哪一部分正在等待?
NgZone只公开函数来确定是否有微任务或macrotasks在运行,但是没有告诉我哪一个。
编辑:量角器显示此类超时错误的典型示例:
失败:等待异步Angular任务在11秒后完成超时。这可能是因为当前页面不是Angular应用程序。有关详细信息,请参阅常见问题解答:https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
在使用定位器等待元素时 - 定位器:按(css选择器,[data-e2e ='滚动到商品'])
页面上存在元素(我已手动验证过),但量角器仍然超时。
答案 0 :(得分:12)
我有一个类似的问题,Testability不稳定,我只知道我有一些pendingMacroTasks
。本地化这些任务确实有点棘手(您不会遍历整个代码库并寻找setTimeout
)。
但是我最终还是做到了。
您可以做的第一件事是在Chrome中打开开发工具,按Ctrl+O
,键入 zone.js ,然后按Enter
。
这将打开 zone.js 源文件(不是Typescript,还是什么)。
在 zone.js 内查找Zone.prototype.runTask
并在此方法内放置一个断点。
在加载应用程序后启用断点 ,否则断点将被击中太多次。
如果您的可测试性不稳定,则可能意味着您有一些重复宏任务重新安排了自己的时间。至少那是我的情况。
如果是这种情况,则在加载应用程序后每X次就会命中一个断点。
一旦遇到断点,请转到task.callback.[[FunctionLocation]]
,这将带您(最可能是)一些setTimeout
或setInterval
。
要对其进行修复,请运行outside of Angular zone。
这涉及到调整Zone.js代码,但为您提供了更持久的调试信息。
node_modules/zone.js/dist/zone.js
。function Zone(parent, zoneSpec)
this._tasks = {}
let counter = 0
查找Zone.prototype.scheduleTask
并在调用this._updateTaskCount(task,1)
之前添加以下内容:
task.id = counter++;
this._tasks[task.id] = task;
查找Zone.prototype.scheduleTask
,并在调用this._updateTaskCount(task,-1)
之前添加以下内容:
delete this._tasks[task.id]
假设您做了上述调整,您始终可以像这样访问待处理的任务:
tasks = Object.values(window.getAllAngularTestabilities()[0]._ngZone._inner._tasks)
要获取所有影响可测试性状态的待处理宏任务:
tasks.filter(t => t.type === 'macroTask' && t._state === 'scheduled')
之后,与之前的解决方案类似,签出.callback.[[FunctionLocation]]
并通过在Angular区域之外运行进行修复。
答案 1 :(得分:1)
跟踪量角器的异步任务没有特别的方法。您可能会做的是调查哪些异步任务可能会阻止您的流量。如果您正在测试,则有两个主要的调试提示:应用程序代码中的异步任务和测试中的异步任务。
在你的测试中,如果你使用像Jasmine这样的东西,你是否尝试过改变export function getCurrUser(window,user) {
...
_req.onsuccess=function(event){
let cursor=event.target.result;
//confirm in this line that user object does has some value
if(cursor) {user = Object.assign({}, cursor);return;}
else {return;}
};
...
}
之类的东西?
无论如何,除了在开始和回调时开始记录所有异步任务之外,我没有看到更好的调试方法。
答案 2 :(得分:1)
JeB在建议他的way方面做得很好(某种解决方案总比没有好。)实际上,有一种方法可以获取未修补zone.js
文件的待处理任务列表。
在查看角度源时,我有了这个主意:https://github.com/angular/angular/blob/master/packages/core/src/zone/ng_zone.ts#L134
这是操作方法:
node_modules/zone.js/dist/task-tracking.js
之后导入zone.js
文件NgZone
实例并像import * as _ from "lodash";
...
const ngZone = moduleInstance.injector.get(NgZone);
setInterval(() => {
var taskTrackingZone = (<any>ngZone)._inner.getZoneWith("TaskTrackingZone");
if (!taskTrackingZone) {
throw new Error("'TaskTrackingZone' zone not found! Have you loaded 'node_modules/zone.js/dist/task-tracking.js'?");
}
var tasks: any[] = taskTrackingZone._properties.TaskTrackingZone.getTasksFor("macroTask");
tasks = _.clone(tasks);
if (_.size(tasks) > 0) {
console.log("ZONE pending tasks=", tasks);
}
}, 1000);
答案 3 :(得分:0)
berkov,
我真的需要您的帮助才能使用您提供的功能来获取任务列表。
我添加了import 'zone.js/dist/task-tracking'
;到polyfills.ts
和下面的代码到AppModule.ts的构造方法。但它抛出错误Cannot find name 'moduleInstance'.
// app.module.ts
const ngZone = moduleInstance.injector.get(NgZone);
setInterval(() => {
var taskTrackingZone = (<any>ngZone)._inner.getZoneWith("TaskTrackingZone");
if (!taskTrackingZone) {
throw new Error("'TaskTrackingZone' zone not found! Have you loaded 'node_modules/zone.js/dist/task-tracking.js'?");
}
var tasks: any[] = taskTrackingZone._properties.TaskTrackingZone.getTasksFor("macroTask");
tasks = _.clone(tasks);
if (_.size(tasks) > 0) {
console.log("ZONE pending tasks=", tasks);
}
}, 1000);
如果可能,请提供任何可行的示例。那将是您的极大帮助。
谢谢
Jignesh Raval
CC:@ hodossy-szabolcs