I'm on my third day working with Protractor and I'm constantly hitting bric walls in regards to waiting around for pages to load and elements to appear. This test case in particular has grown ugly and I would like to solve the issues without having to rely on sleeps.
我在第三天和Protractor一起工作时,我经常会在等待页面加载和元素出现方面碰到金砖墙。特别是这个测试案例变得丑陋,我想解决问题而不必依赖睡眠。
I am currently "outside of the land of AngularJS"
我目前“在AngularJS之外”
it('it should reflect in both the field and the title when the personnel name is changed', function() {
var inputField, personnelHeader, personnelName;
personnelName = element(By.css(".overlay.editnameoverlay")).click();
personnelHeader = element(By.id("personnel_name_header"));
inputField = element(By.css("input[name='newvalue']"));
inputField.clear();
inputField.sendKeys("Test 123");
element(By.css("input[name='ok_button']")).click();
// browser.driver.sleep(2000); This test only works with this sleep added
browser.wait(function() {
console.log("Waiting for header to change...");
return personnelHeader.getText().then(function(text) {
return text === "Test 123";
});
}, 5000);
return expect(personnelHeader.getText()).toBe(personnelName.getText());
});
So the test here changes the name in an input field. submits it and waits for the changes to become reflected in the header of the modal. The problem is that without the browser.driver.sleep(2000) I get an error saying
因此,此处的测试会更改输入字段中的名称。提交它并等待更改反映在模态的标题中。问题是没有browser.driver.sleep(2000)我得到一个错误说
Stacktrace:
StaleElementReferenceError: stale element reference: element is not attached to the page document
How do I go about solving this in this particular case?
在这种特殊情况下,我该如何解决这个问题?
2 个解决方案
#1
10
From the documentation for Expect Conditions:
从期望条件的文档:
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to contain the text 'foo'.
browser.wait(EC.textToBePresentInElement($('#abc'), 'foo'), 5000);
#2
6
When you use Protractor to test for non-angular pages you're on your own regarding waiting for elements to be ready for interaction.
当您使用Protractor测试非角度页面时,您就可以自己等待元素准备好进行交互。
StaleElementReferenceError
is probably the most useless selenium error, it happens when the element got removed from the DOM but is still cached somehow, I also suffered this problem when started with Protractor and even tried to convince it should be automatically retried Protractor-side.
StaleElementReferenceError可能是最无用的selenium错误,它发生在元素从DOM中删除但仍以某种方式缓存时,我在使用Protractor时也遇到了这个问题,甚至试图说服它应该自动重试Protractor端。
The solution for me is to always explicitly wait for an element to appear on the page using a custom function waitReady()
that browser.wait
for elements ready, i.e: waits for the element to be ready for interaction:
我的解决方案是始终使用自定义函数waitReady()来显式等待元素出现在页面上,该函数使用browser.wait来准备元素,即:等待元素准备好进行交互:
expect($('#login_field').waitReady()).toBeTruthy();
First integrate this snippet in your code: https://gist.github.com/elgalu/2939aad2b2e31418c1bb
首先将此代码段集成到您的代码中:https://gist.github.com/elgalu/2939aad2b2e31418c1bb
Not only the custom waitReady()
waits for the element but it also swallows any unrelated useless webdriver error like StaleElementReferenceError
and will simply retry up until finding the element or it will timeout.
不仅自定义waitReady()等待该元素,而且它还吞下任何无关的无用webdriver错误,如StaleElementReferenceError,并且只是重试直到找到该元素或它将超时。
So waitReady()
each element before interacting, i.e. before clear()
or sendKeys()
or click()
...
所以waitReady()在交互之前的每个元素,即在clear()或sendKeys()或click()之前......
// TODO: Move to Page Objects module
var personnelNameElm = $(".overlay.editnameoverlay");
var personnelHeaderElm = $("#personnel_name_header");
var inputFieldElm = $("input[name='newvalue']");
var okBtnElm = $("input[name='ok_button']");
it('it should reflect in both the field and the title when the ' +
'personnel name is changed', function() {
expect(personnelNameElm.waitReady()).toBeTruthy();
personnelNameElm.click();
expect(inputFieldElm.waitReady()).toBeTruthy();
inputFieldElm.clear().sendKeys("Test 123");
expect(okBtnElm.waitReady()).toBeTruthy();
okBtnElm.click();
browser.wait(function() {
console.log("Waiting for header to change...");
// Using waitReady() before getText() avoids Stale element errors
return personnelHeaderElm.waitReady().then(function() {
return personnelHeaderElm.getText().then(function(text) {
return text === "Test 123";
});
});
}, 5000);
expect(personnelHeaderElm.getText()).toEqual(personnelNameElm.getText());
});
#1
10
From the documentation for Expect Conditions:
从期望条件的文档:
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to contain the text 'foo'.
browser.wait(EC.textToBePresentInElement($('#abc'), 'foo'), 5000);
#2
6
When you use Protractor to test for non-angular pages you're on your own regarding waiting for elements to be ready for interaction.
当您使用Protractor测试非角度页面时,您就可以自己等待元素准备好进行交互。
StaleElementReferenceError
is probably the most useless selenium error, it happens when the element got removed from the DOM but is still cached somehow, I also suffered this problem when started with Protractor and even tried to convince it should be automatically retried Protractor-side.
StaleElementReferenceError可能是最无用的selenium错误,它发生在元素从DOM中删除但仍以某种方式缓存时,我在使用Protractor时也遇到了这个问题,甚至试图说服它应该自动重试Protractor端。
The solution for me is to always explicitly wait for an element to appear on the page using a custom function waitReady()
that browser.wait
for elements ready, i.e: waits for the element to be ready for interaction:
我的解决方案是始终使用自定义函数waitReady()来显式等待元素出现在页面上,该函数使用browser.wait来准备元素,即:等待元素准备好进行交互:
expect($('#login_field').waitReady()).toBeTruthy();
First integrate this snippet in your code: https://gist.github.com/elgalu/2939aad2b2e31418c1bb
首先将此代码段集成到您的代码中:https://gist.github.com/elgalu/2939aad2b2e31418c1bb
Not only the custom waitReady()
waits for the element but it also swallows any unrelated useless webdriver error like StaleElementReferenceError
and will simply retry up until finding the element or it will timeout.
不仅自定义waitReady()等待该元素,而且它还吞下任何无关的无用webdriver错误,如StaleElementReferenceError,并且只是重试直到找到该元素或它将超时。
So waitReady()
each element before interacting, i.e. before clear()
or sendKeys()
or click()
...
所以waitReady()在交互之前的每个元素,即在clear()或sendKeys()或click()之前......
// TODO: Move to Page Objects module
var personnelNameElm = $(".overlay.editnameoverlay");
var personnelHeaderElm = $("#personnel_name_header");
var inputFieldElm = $("input[name='newvalue']");
var okBtnElm = $("input[name='ok_button']");
it('it should reflect in both the field and the title when the ' +
'personnel name is changed', function() {
expect(personnelNameElm.waitReady()).toBeTruthy();
personnelNameElm.click();
expect(inputFieldElm.waitReady()).toBeTruthy();
inputFieldElm.clear().sendKeys("Test 123");
expect(okBtnElm.waitReady()).toBeTruthy();
okBtnElm.click();
browser.wait(function() {
console.log("Waiting for header to change...");
// Using waitReady() before getText() avoids Stale element errors
return personnelHeaderElm.waitReady().then(function() {
return personnelHeaderElm.getText().then(function(text) {
return text === "Test 123";
});
});
}, 5000);
expect(personnelHeaderElm.getText()).toEqual(personnelNameElm.getText());
});