如何使用量角器定位 angular 应用之外的元素?

How can I target elements outside the angular app with protractor?

我有一个在 Angular 应用 bootstrap 之前播放的介绍元素。

<!-- need to target div below -->
<div id="intro"></div>
<!-- still bootstraping -->
<app-root></app-root>

我正在使用 Angular-cli

中提供的以下量角器规范
describe('my App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage(); // default from angular cli
  });

  it(`should provide an intro div`, () => {
    page.navigateTo();
    const introDiv = element(by.id('intro'));
    expect(introDiv.isPresent()).toBe(true); // reports as false in protractor test
  });
});

我可以使用上面相同的 'it' 函数定位 Angular 应用程序内的元素,为什么这在 Angular 应用程序之外不起作用以及我如何定位index.html?

中的元素

更新:

我已经做了进一步的测试,想把这个记录在问题中仅供参考:

上面没有提到,我实际上 angular 删除了介绍 div 因为它是全屏覆盖。

感谢 Ernst Zwingli 提供的 Protractor 文档的参考,它告诉我 Protractor 在每个 WebDriver 操作之前自动应用 browser.waitForAngular() 命令。

因此上面试图针对介绍 div 的测试在寻找它时找不到它 angular bootstraped 并删除了 div .

我在 index.html 中创建了一个临时的 div,没有任何内容。即使它不在 Angular 的应用程序中,也可以通过 element(by.id('find-me')) 使用。

<div id="find-me"></div>

it(`is available after angular bootstraps and can be targeted with element()`, () => {
    const findMeDiv = element(by.id('find-me'));
    expect(findMeDiv.isPresent()).toBe(true);
  });

我终于能够通过使用 browser.waitForAngularEnabled(false) 来定位简介 div,因为它在 Angular bootstrap 之前可用。虽然这只是等待 $http 和 $timeouts,但它似乎足以在 bootstrap 之前定位到 div。我不确定它是否完全抵消了 browser.waitForAngular()

(与 waitForAngular() 的区别是等待 rendering, http, timeouts 而 waitForAngularEnabled() 只关心 httptimeouts - 尽管名称相似性可能暗示 waitForAngularEnabled(false) 完全抵消了 waitForAngular()例如,还包括 rendering 并且未在文档中指定)。

<div id="intro"></div>

// Works
  it(`Found to be available if I use browser.waitForAngularEnabled(false) since div is removed when Angular is ready`, () => {
    browser.waitForAngularEnabled(false);
    const introDiv = element(by.id('intro'));
    expect(introDiv.isPresent()).toBe(true);
  });

所以基本上 Ernst Zwingli 和 Xotabu4 都提供了很好的洞察力,因为我需要 browser.waitForAngularEnabled(false); 并且可以使用 element() 函数来访问 div。

您基本上应该将该部分视为 non-angular 并使用 Selenium WebDriver-methods.

查找元素

因此,使用 browser.driver.findElement(by.id('intro')) 而不是 element(by.id('intro')),由于 browser.driver 使用 JavaScript/Vanilla browser 而不是量角器 browser因此可以在任何 angular 范围之外工作。

但是,你需要放弃你的expect()-statement,因为Protractor element(locator)代表一个ElementArrayFinder,而WebDriver-methods like findElement(), getWebElement() 和类似的,直接表示 WebElement(因此它们会立即执行元素搜索,而不是等到代码需要真正的 WebElement 时再进行搜索)。 Read about here

所以在你的情况下,findElement 你要么得到一个 WebDriver-Error,因为该元素不存在,要么你得到 WebElement,因为它在那里(不需要进一步检查是否存在)。

Here the Selenium-Documentation and here a GitHub, that explains the use of Protractor in Non-Angular

顺便说一句:

如果整个页面是非Angular,您需要使用browser.waitForAngularEnabled(false)关闭Protractor ControlFlow(这是较早的ignoreSynchronization = true,但不要再使用它了) .

如果只有页面的一部分是非Angular,您可能不需要关闭量角器,但您可能需要明确地处理同步执行(用于尝试和错误的东西)

更新

由于我收到的评论,我很想 link 了解更多信息,这进一步证明了我的观点(因为 Protractor <> Vanilla):