如何使用量角器定位 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() 只关心 http 和 timeouts - 尽管名称相似性可能暗示 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):
我有一个在 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() 只关心 http 和 timeouts - 尽管名称相似性可能暗示 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):