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

时间:2017-10-05 14:56:00

标签: javascript angular jasmine protractor

编辑:请注意,我在@ ernst-zwingli的帮助下找到了我的问题的根源,所以如果你有同样的错误,他的一个明确的修复可能会帮助你。我的问题是Protractor本身的一个已知问题,如果您认为这可能是您,我已经扩展了我的步骤,以便在我的原始问题之后找出问题的根源。

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

我的问题:当browser.waitForAngularEnabled处于true 的默认设置时,找不到Angular应用页面上的元素(因为在'我相信我我在一个有角度的页面上,并希望Protractor能够做到这一点的魔法')。如果我将browser.waitForAngularEnabled设置为false ,就会发现它们很好(因为在'我不是在一个有角度的页面上,我想自己处理这个问题,坐下来量角器&# 39)。如何在我明确的Angular页面上追踪导致这种情况的原因?

我有一个带有非Angular Auth0登录页面的产品,可以访问以Angular编写的 的其他产品(准确地说是Angular 4.3.2)。我已成功遍历非Angular登录页面上的登录。我将waitForAngularEnabled切换为false,以方便非Angular登录。在点击提交按钮后,我在预期加载初始着陆页(Angular)的位置将其转回true。代码如下:

        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(他们使用(编辑:非$ interval)Observable Interval非常感谢你)并且他们不确定$ http。

我找到了关于调试量角器Angular sync问题的规范方法的解决方案:Canonical way to debug Protractor-to-Angular sync issues 但我不确定解决方案是否可以无法修改dev代码来运行程序化跟踪器。 (编辑:我从来没有弄明白如何让它发挥作用)

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

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

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

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

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

  

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

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

  

useAllAngular2AppRoots:true,

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

  

如果使用$ 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就足够了,但对于Protractor来说显然不是这样。然后看着Macrotasks是真的,我不得不查看Macrotask的内容:What does hasPendingMacrotasks and hasPendingMicrotasks check for?

macrotask可以是:

  

即。 setTimeout,setInterval,setImmediate

因此,@ ernst-zwingli关于间隔引起区域问题的记录被记住了,最后点击了一些东西。
First github issue, about zone instability

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

Issue #3349 - 我的问题的实际根本原因。我的开发人员不会主动跳进和离开可观察区域。即使这些可观察者只有一个用户。由于他们此时生活在角区,他们是一个长期运行的&#34; Macrotask&#34;量角器无限期地等待。

我无法使用这些包装器重写代码,因为我目前还没有足够的Angular来安全地完成它,而且我们目前正在朝着11月的最后期限前进。我想我暂时不得不处理使用browser.driver的问题,希望以后我不能修复它。希望我的RCA对你有所帮助。

2 个答案:

答案 0 :(得分:7)

在下文中,我列出了一组潜在的原因以及修复/解​​决它们的可能性。

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

我无法解释它和Andrey Agibalov in his Blog here,所以请查看(也适用于开发人员)。

基本上,量角器所需的物品可以检查您的Chrome Dev。

for AngularJS 检查对象window.angular是否已正确定义,即查找window.angular.version并尝试使用根元素的window.angular.getTestability

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

根元素(AngularJS)

你的Angular App可能会像Body <div ng-app="my-app">一样包含在Body中。 在这种情况下,您必须在rootElement: body内调整config.tsCheck this answer for details

<强>角(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出现这些问题。 read all about it here

<强> browser.driver。 - 侧面评论

browser.driver.get()就像ignoreSynchronization = true一样工作,因为您直接分配了浏览器驱动程序,并且您绕过了量角器的同步逻辑。 请在this answer here中了解详情。

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

答案 1 :(得分:-1)

请你设置

    browser.ignoreSynchronization = true;

并尝试