【问题标题】:testability.whenStable() returns, testability.isStable() returns falsetestability.whenStable() 返回, testability.isStable() 返回 false
【发布时间】:2019-06-27 19:26:48
【问题描述】:

请注意,这并非特定于 Protractor。问题在于 Angular 2 的内置 Testability service,Protractor 恰好使用了它。 Protractor 通过调用waitForAngular 调用Testability.whenStable。我遇到了一些失败的代码。

我的测试代码如下所示:

await renderFooView();
await interactWithFooView();

第二行失败:

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

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

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

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

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

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

事实上,我不应该手动执行那条中间线。每当我拨打与浏览器交互的电话时,Protractor 都会自动执行此操作。

经过一番挖掘,我发现 Protractor 正在进行调用,它工作正常,但 Angular 2 中的底层可测试性机制似乎已损坏。

在 Angular 2 下,Protractor 的“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 回调中始终为真,因此 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() 为假?

【问题讨论】:

  • 不幸的是,在某些地方仍然需要await browser.sleep(...) 以使规范更加稳定。我希望我们也可以完全依赖内置机制。
  • 如果你使用我上面展示的 waitForAngular 的最终版本,你的代码中不需要任意长的browser.sleep。它将像量角器一样工作。

标签: angular protractor angular-test


【解决方案1】:

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

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

2) 编写一个辅助函数,该函数将持续 ping 可测试性 api 并监控 isStable 标志。它将等待标志变为真,然后继续进行测试。这就像在等待角度之上添加等待角度包装器。

我们选择了第一个解决方案,因为这很有帮助。

附带说明:您也可能在代码中的某处缺少等待,因为没有解决承诺并且测试在搜索元素之前没有等待 isStable 标志。您能否在测试中关闭 selenium 承诺管理器并尝试查看是否有任何承诺被拒绝?您可以通过在量角器配置文件中添加一个标志来做到这一点:SELENIUM_PROMISE_MANAGER: false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 2015-08-02
    • 2012-05-17
    • 2013-10-26
    相关资源
    最近更新 更多