testability.whenStable()返回,testability.isStable()返回false

时间:2019-02-04 02:51:55

标签: angular protractor angular-testing

请注意,这并非特定于量角器。问题出在量角器恰好使用的Angular 2的内置Testability service中。量角器通过调用Testability.whenStable来调用waitForAngular。我在失败的地方打了一些代码。

我的测试代码如下:

await renderFooView();
await interactWithFooView();

第二行失败:

 Failed: No element found using locator: By(css selector, foo-view)

当量角器继续尝试与之交互的代码时,Angular尚未完成“ foo-view”的渲染。

如果我在两者之间添加睡眠,那么它会起作用:

await renderFooView();
await browser.sleep(1000);
await interactWithFooView();

很显然,我不想这样做。对于我来说,量角器的大部分价值是“等待角度”机制,它消除了脚本中的“等待X”噪音。我想要的是这个

await renderFooView();
await browser.waitForAngular();
await interactWithFooView();

实际上,我永远不必手动执行该中间线。每当我与浏览器进行交互的呼叫时,量角器都会自动执行此操作。

进行一些挖掘之后,我发现量角器正在进行调用,它可以正常工作,但是Angular 2中潜在的Testability机制似乎已损坏。

在Angular 2下,量角器的“ waitForAngular”类似于以下内容:

let rootElement = window.getAllAngularRootElements()[0];
let testability = window.getAngularTestability(rootElement);
testability.whenStable(callbackThatResumesScriptExecution);

换句话说,它调用Angular的testability.whenStable并仅在Angular报告其稳定时才恢复执行。如果我在回调中添加一些日志记录:

testability.whenStable(() => {
    console.log("isStable:", testability.isStable());
    callback();
});

isStable()whenStable回调中始终为true,因此Angular肯定会在正确的时间调用

但是,如果此回调返回后立即,我再次轮询isStable(),则它的值为false。

    let pollAngularIsStable = `{ 
        let rootElement = window.getAllAngularRootElements()[0];
        let testability = window.getAngularTestability(rootElement);
        return testability.isStable();
    }`;

    await renderFooView();
    await browser.waitForAngular();
    console.log(await browser.executeScript(pollAngularIsStable)); // => false
    await interactWithFooView();

我已经编写了自己的browser.waitForAngular版本,并且看到了完全相同的结果:

    let waitForAngularStable = `
        let callback = arguments[arguments.length - 1];
        let rootElement = window.getAllAngularRootElements()[0];
        let testability = window.getAngularTestability(rootElement);
        testability.whenStable(callback);
    `;
    await renderFooView();
    await browser.executeAsyncScript(waitForAngularStable);
    console.log(await browser.executeScript(pollAngularIsStable)); // => false
    await interactWithFooView();

如果我编写了一个手动轮询isStable()直到返回true的例程,则该脚本将修复我的脚本:

    async function waitForAngular() {
        let ms;
        for (ms=0; ms<10000; ++ms) {
            await browser.sleep(1);
            if (await browser.executeScript(pollAngularIsStable)) {
                break;
            }
        }
        console.log(`Waited ${ms}ms for Angular to be stable.`);
    }

    await renderFooView();
    await waitForAngular(); // usually waits < 50ms
    console.log(await browser.executeScript(pollAngularIsStable)); // => true
    await interactWithFooView(); // always works now

那么...为什么轮询isStable()可以工作,但是等待whenStable()回调却不起作用?更重要的是,当下一次调用(无插入代码)显示whenStable()为假时,为什么isStable()会报告应用程序稳定?

1 个答案:

答案 0 :(得分:0)

过去在使用Protractor和Angular应用程序时遇到过类似的问题。就我而言,有一个第三方插件的运行时间比预期的要长。因此,isStable标志在完全加载之前将显示为false。我们深入研究,发现有两种方法可以解决此问题:

1)删除端到端测试套件中的第三方集成并运行测试(这解决了该问题,我们不需要使用browser.sleep

2)编写一个辅助函数,该函数将连续ping可测性api并监视isStable标志。它将等待标志变为真,然后继续测试。这就像在等待角度的顶部添加等待角度的包装。

我们寻求第一个解决方案是因为这有所帮助。

在旁注:您可能还会在代码中的某个地方缺少一个等待,因为它无法解决承诺,并且测试在搜索元素之前没有等待isStable标志。您可以在测试中关闭硒承诺管理器并尝试查看是否拒绝了任何承诺吗?您可以通过在量角器配置文件中添加一个标记来做到这一点:SELENIUM_PROMISE_MANAGER:false