如何调试等待异步 Angular 任务超时?无法在角度页面上找到元素

IT技术 javascript angular jasmine protractor
2021-03-10 01:33:55

编辑:请注意,我在@ernst-zwingli 的帮助下找到了问题的根源,因此如果您遇到相同的错误,他的一个修复程序可能会对您有所帮助。我的问题是量角器本身的一个已知问题,如果您认为这可能是您,我已经扩展了我的步骤以在我最初提出问题后查明问题的根源。


我正在尝试在使用 angular-cli 构建的 Angular2(只是 Angular)应用程序中使用 Protractor。

我的问题:在 Angular 应用程序页面上的元素browser.waitForAngularEnabled处于默认设置时无法找到true (如“我相信我在一个 Angular 页面上并且希望 Protractor 能够发挥它的魔力”)如果我设置browser.waitForAngularEnabledfalse (如“我不在一个有角度的页面上并且想自己处理这个问题,请坐 Protractor”),它们会被发现很好我如何在我的绝对 Angular 页面上追踪导致这种情况的原因?

我有一个带有非 Angular Auth0 登录页面的产品,该页面可以访问用 Angular 编写的产品的其余部分(准确地说Angular 4.3.2)。我已经成功遍历了非 Angular 登录页面的登录。我翻转了waitForAngularEnabledswitch 以false方便非 Angular 登录。true在单击提交按钮后,我将它转回到我希望加载初始登录页面 (Angular) 的位置。代码如下:

        browser.waitForAngularEnabled(false);
        browser.driver.get('https://dashboard.net/projects');
        browser.driver.sleep(10000);
        browser.driver.findElement(By.css("[type='email']"));
        browser.driver.findElement(By.css("[type='email']")).sendKeys("email@example.com");
        browser.driver.findElement(By.css(".auth0-label-submit")).click();

        browser.driver.findElement(By.id("passwordInput")).sendKeys("password");
        browser.driver.findElement(By.id("submitButton")).click();
        browser.driver.sleep(5000);  // needed if not waiting for Angular
        //browser.waitForAngularEnabled(true);  // Back to Protractor land we go
        let elementToFind = element(by.className("header-text"));
        elementToFind.isDisplayed().then(function() {grabTheDarnLocalStorage()});
        expect(elementToFind.isDisplayed()).toBeTruthy();

如果我取消注释该browser.waitForAngularEnabled(true);行以声明我回到了 Angular 代码中,我会得到如下错误跟踪:

Failed: Timed out waiting for asynchronous Angular tasks to finish after 30 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(css selector, .header-text)
ScriptTimeoutError: asynchronous script timeout: result was not received in 30 seconds
  (Session info: chrome=61.0.3163.100)
  (Driver info: chromedriver=2.32.498550 (9dec58e66c31bcc53a9ce3c7226f0c1c5810906a),platform=Windows NT 10.0.14393 x86_64)
    at WebDriverError (C:\Users\c-shouston\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\error.js:27:5)
    at ScriptTimeoutError (C:\Users\c-shouston\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\error.js:203:5)
    at Object.checkLegacyResponse (C:\Users\c-shouston\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\error.js:505:15)
    at parseHttpResponse (C:\Users\c-shouston\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\http.js:509:13)
    at doSend.then.response (C:\Users\c-shouston\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\http.js:440:13)
    at process._tickCallback (internal/process/next_tick.js:109:7)
From: Task: Protractor.waitForAngular() - Locator: By(css selector, .header-text)

我参考了常见问题解答:https : //github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular 我的开发人员说他们不使用 $timeout(他们使用(编辑:NOT $interval)Observable Interval 非常感谢您)而且他们不确定 $http。

我找到了有关调试量角器角度同步问题的规范方法的解决方案:调试量角器到角度同步问题的规范方法, 但我不确定该解决方案是否可以在无法修改开发代码以运行编程跟踪器的情况下工作。(编辑:我从来没有想过如何让它工作)

我还发现这是关于您在每次测试之前添加的长时间超时,但我觉得这是不必要的开销,它使您的整体测试执行时间比不了解问题的根本原因要长:https : //stackoverflow.com/a /37217167/2718402 (编辑:是的,这是一个坏主意,会给您的测试增加不必要的时间,请不要这样做)

令人沮丧的是,这似乎很常见,而且似乎没有关于如何处理它的简化文档。使用非 Angular 页面登录只是为了转换到 Angular 页面。量角器未正确拾取角度页面。我在网上找到的所有示例都是一些代码,我没有参考它们在我的整体测试框架中应该在哪里。我会杀死一个完整的例子,有人测试一个非 Angular 登录,该登录转换到一个完整的 Angular 网站,具有设置配置和真实世界的测试用例。 (编辑:这仍然是正确的,但我无法自己制作一个,因为我的应用程序处于糟糕的灰色区域,请注意下面的 RCA 以获取更多详细信息。)

我只希望能够进行登录,然后成功转换到我的 Angular 页面,并且能够依靠 Protractor 来处理我的 Angular 页面。我需要知道要查找的内容可能是长时间运行的异步进程(我可以在 Chrome 开发工具中具体检查什么?)。我很想了解 Protractor 需要什么作为默认值才能成功地处理我的应用程序/网站的 Angular 部分(是否有超出<app-root _nghost-c0="" ng-version="4.3.2">HTML 中存在的内容?)。在这份工作之前,我在 Java 工作,所以所有这些异步性和 Angular 对我来说都是新的,所以我知道我错过了经验丰富的 Javascript 开发人员所知道的已知事物。


我的解决方案/根本原因分析

从@ernst-zwingli 建议的列表开始:

对于 Angular(2) 检查对象 window.getAllAngularRootElements 是否至少返回一个值。

它至少返回了一个值,所以我继续前进。

useAllAngular2AppRoots: 真,

我试过了,但仍然遇到了异步超时。

如果使用 $interval 或其他持久的异步任务,可能会出现问题,因为区域

之前@ernst-zwingli 也提到了查看可测试性方法,只不过是老方法。通过研究和测试我发现window对象也有getAllAngularTestabilities方法。这导致了一个有趣的兔子洞。Chrome 控制台的示例输出(放在window.getAllAngularTestabilities()Chrome 控制台窗口中,查看结果列表)如下:

t:
  _callbacks:...,
  _didWork:true,
  _isZoneStable: true (this looks promising, but why isn't Protractor working then?!?)
  _ngZone:
    hasPendingMacrotasks: true,
    hasPendingMicrotasks: false,
    isStable: true

我认为 isZoneStable 就足够了,但对于量角器显然不是这样。然后看着 Macrotasks 是真的,我不得不查一下 Macrotask 到底是什么hasPendingMacrotasks 和 hasPendingMicrotasks 检查什么?.

宏任务可以是:

即 setTimeout, setInterval, setImmediate

因此,@ernst-zwingli 关于间隔在区域中引起问题的注释被记住了,并且最终点击了一些东西。
第一个 github 问题,关于区域不稳定

另一个 github 问题抱怨使用 browser.driver 与 browser.waitForAngularEnabled 一起完成工作的必要性。显然这是预期的行为,它导致我发出 #3349

问题 #3349 - 我的问题的实际根本原因。我的开发人员不会主动进出可观察对象的区域。即使这些 observables 只有一个订阅者。由于此时它们处于角度区域,因此它们是 Protractor 无限等待的长时间运行的“宏任务”。

我无法用这些包装器重写代码,因为我目前对 Angular 还不够精通,无法安全地做到这一点,而且我们目前正朝着 11 月的最后期限迈进。我想我暂时不得不处理使用 browser.driver 并希望我以后不能修复它。希望我的 RCA 对您有所帮助。

2个回答

在下面我列出了一组潜在的原因和修复/解决它们的可能性。

AngularJS 和 Angular(2) 如何工作/我可以在浏览器开发模式中检查什么

我无法像安德烈·阿吉巴洛夫( Andrey Agibalov) 在他的博客中那样解释它,所以请查看它(也适用于开发人员)。

基本上,您可以在 Chrome Dev 中检查 Protractor 所需的对象。

对于 AngularJS 检查对象window.angular是否正确定义,即查找window.angular.version并尝试window.angular.getTestability您的 Root 元素

for Angular(2) 检查对象是否window.getAllAngularRootElements至少返回一个值。

根元素 (AngularJS)

潜在地,您的 Angular 应用程序会像<div ng-app="my-app">. 在这种情况下,你必须调整你的rootElement: body内部config.ts查看此答案以了解详细信息

角(2)

如果您使用的是 Angular(又名 Angular2),那么引入了 ngZone。在这种情况下,您还config.js应该包含以下内容:

exports.config = {
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['spec.js'],
    useAllAngular2AppRoots: true,
    // rootElement: 'root-element'
};

检查您的浏览器,window.getAllAngularRootElements因为 conf.js 中的附加行是关于此的。

如果可以,也许可以利用多个区域的优势。创建第二个区域,配置rootElement: 'root-element' 为只关注一个区域,然后将一些异步任务移动到另一个区域,直到找到导致超时的任务。将这些任务(如果可能)放在单独的区域中,以便 Protractor 忽略这些任务。

如果使用$interval或 其他持久的异步任务,可能会因为区域而出现问题。重复或持久的任务应该在区域外开始,然后移动到区域中,否则量角器可能会超时。有一种解决方法可供开发人员申请,以避免 Protractor 出现这些问题。 在这里阅读所有相关信息

浏览器.驱动程序。- 旁注

browser.driver.get()就像 一样工作ignoreSynchronization = true,因为您直接分配浏览器驱动程序,并且有点绕过量角器的同步逻辑。此处的答案中阅读更多相关信息

希望我能给你更多的意见,你可以解决你的问题。请让我知道结果。

我认为你的答案对于试图调试出错的人来说是最好的,尽管 Angular2 的可测试性方法已经过时了,正如我之前所说的。如果您可以编辑,我会将其标记为已接受的答案。为了清楚起见,我将添加最终成为问题的内容。谢谢您的帮助!
2021-04-21 01:33:55
这真太了不起了。这里有很多我不知道/不知道如何查找的内容。我会按顺序回答它们: - 当我在我的 angular 页面上时,window.angular 在我的浏览器控制台中是“未定义的”(我们也使用 angular-cli,不确定这会如何影响答案) - 我我的产品的 html 中没有 ng-app,我的开发人员认为它已被 app-root 替换,因为我们使用了 angular-cli - 正如上一点中所述,angular-cli,所以我尝试了 useAllAngular2AppRoots,得到错误:超时 - 由 jasmine.DEFAULT_TIMEOUT_INTERVAL 指定的异步回调 [不及时]。
2021-04-25 01:33:55
我编辑了我的答案以更好地区分 AngularJS 和 Angular(2)。当您使用“Cli”时,几乎可以肯定,您使用的是 Angular(2)。作为另一种可能性,您可以使用诸如Cliptor.js 之类的配置帮助工具来交叉检查您的 conf.js 以获得该结果。
2021-04-26 01:33:55
我感谢更新!我正在调查你的建议。请注意:获得可测试性的函数(至少在我使用的 Angular2 版本中)是 window.getAllAngularTestabilities()。这将返回每个 Angular 根(其中我有一个,由 window.getAllAngularRootElements() 确定),而我拥有的一个_ngZone:isStable = true在我遇到麻烦的页面上有一个属性据我所知,没有 window.getAllAngularRootElements()[0].getTestability 方法。此外,持久的异步任务会在控制台中显示为无休止的网络调用,对吗?
2021-05-04 01:33:55
我之前没有明确提到过。请根据我的编辑重新检查您的问题。您现在应该能够根据我的回答中的 Angular(2) 信息解决问题。
2021-05-14 01:33:55

你能设置一下吗

    browser.ignoreSynchronization = true;

并尝试

browser.waitForAngularEnabled(false); 是现在做这件事的规范方法。它与您所写的内容相同。不过还是谢谢!
2021-05-04 01:33:55