「要素がDOMにアタッチされなくなった」という質問があります。
別の解決策を試しましたが、断続的に機能しています。永続的な解決策を提案してください。
WebElement getStaleElemById(String id, WebDriver driver) {
try {
return driver.findElement(By.id(id));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemById(id, driver);
}
}
WebElement getStaleElemByCss(String css, WebDriver driver) {
try {
return driver.findElement(By.cssSelector(css));
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElemByCss(css, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElemByCss(css, driver);
}
}
ありがとう、アヌ
おそらく直面している問題は、メソッドが正しい(かつ有効な)要素を返すことですが、1秒後にアクセスしようとすると、古くなってスローされます。
これは通常、次の場合に発生します。
私が知っているそれを解決する4つの方法があります。
非同期ページに直面するときは、予想されるすべてのページロードの後に適切な待機を使用してください。最初のクリックの後に明示的な待機を挿入し、新しいページ/新しいコンテンツが読み込まれるのを待ちます。その後のみ、目的の要素を検索できます。これは、最初に行う必要があります。テストの堅牢性が大幅に向上します。
私は2年前からあなたの方法の変種を使用しており(上記の解決策1の手法と一緒に)、絶対に機能しほとんど、奇妙なWebDriverバグでのみ失敗します。見つかった直後に(メソッドから戻る前に).isDisplayed()
メソッドなどを使用して、見つかった要素にアクセスしてみます。それがスローされた場合は、もう一度検索する方法をすでに知っています。合格した場合は、もう1つ(偽)の保証があります。
WebElement
デコレーターを作成して、それがどのように見つけられたかを記憶し、アクセスおよびスローされたときにそれを再発見します。これは明らかに、デコレータのインスタンスを返すカスタムfindElement()
メソッドを使用することを強制します(または、さらに良いことに、通常のfindElement()
からインスタンスを返す装飾されたWebDriver
を使用します)およびfindElemens()
メソッド)。次のようにします。
_public class NeverStaleWebElement implements WebElement {
private WebElement element;
private final WebDriver driver;
private final By foundBy;
public NeverStaleWebElement(WebElement element, WebDriver driver, By foundBy) {
this.element = element;
this.driver = driver;
this.foundBy = foundBy;
}
@Override
public void click() {
try {
element.click();
} catch (StaleElementReferenceException e) {
// log exception
// assumes implicit wait, use custom findElement() methods for custom behaviour
element = driver.findElement(foundBy);
// recursion, consider a conditioned loop instead
click();
}
}
// ... similar for other methods, too
}
_
foundBy
情報は、これを簡単にするために一般的なWebElementsからアクセスできる必要があると思いますが、Selenium開発者は、このようなものを試すのは間違いであると考えて この情報を公開しないでください) 。古くなった要素を再検索することは間違いなく悪い習慣です。なぜなら、正当化されているかどうかを確認するためのメカニズムなしに暗黙的に要素を再検索しているためです。再検索メカニズムは、完全に異なる要素を見つける可能性があり、同じ要素を再び見つけることはできません。また、見つかった要素が多い場合は、findElements()
でひどく失敗します(findElements()
で見つかった要素の再検索を禁止するか、要素の元の数を覚えておく必要があります返されたList
)。
私はそれがときどき役立つと思いますが、テストの堅牢性のために明らかにはるかに優れたソリューションであるオプション1と2を誰も使用しないことは事実です。それらを使用して、これが必要であると確信した後でのみ、それを実行してください。
ワークフロー全体を新しい方法で実装してください!
@LoadsNewPage
_、_@Reversible
_などの注釈を付けます。これは明らかに多くの労力を要し、十分に検討しなければ、すぐに逆効果になる可能性があります。テストのページを手動で修正した後、失敗したテストを再開するために、この(かなり複雑で強力な)バリアントを使用しました。一部の条件(たとえば、StaleElementException
)では、失敗してもテストはすぐには終了しませんが、(最終的に15秒後にタイムアウトする前に)待機し、情報ウィンドウをポップアップしてユーザーに表示します。手動でページを更新するオプション/右ボタンをクリックする/フォームを修正する/何でも。その後、失敗したタスクを再実行するか、履歴内のいくつかのステップに戻る可能性があります(たとえば、最後の_@LoadsNewPage
_ジョブまで)。
そうは言っても、元のソリューションでは、いくらか磨くことができます。 2つの方法を1つのより一般的な方法に組み合わせることができます(または少なくともコードの繰り返しを減らすために、これらをこの方法に委任することができます)。
_WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException e) {
System.out.println("Attempting to recover from StaleElementReferenceException ...");
return getStaleElem(by, driver);
} catch (NoSuchElementException ele) {
System.out.println("Attempting to recover from NoSuchElementException ...");
return getStaleElem(by, driver);
}
}
_
Java 7の場合、単一のマルチキャッチブロックでも十分です。
_WebElement getStaleElem(By by, WebDriver driver) {
try {
return driver.findElement(by);
} catch (StaleElementReferenceException | NoSuchElementException e) {
System.out.println("Attempting to recover from " + e.getClass().getSimpleName() + "...");
return getStaleElem(by, driver);
}
}
_
このようにして、維持する必要のあるコードの量を大幅に減らすことができます。
これを解決するには、1。古くなった要素を保持し、例外がスローされるまでポーリングします。次に、要素が再び表示されるまで待ちます。
boolean isStillOnOldPage = true;
while (isStillOnOldPage) {
try {
theElement.getAttribute("whatever");
} catch (StaleElementReferenceException e) {
isStillOnOldPage = false;
}
}
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("theElementId")));
解決策:
driver = webdriver.Firefox(); driver.get("http://www.github.com"); search_input = lambda: driver.find_element_by_name('q'); search_input().send_keys('hello world\n'); time.sleep(5); search_input().send_keys('hello frank\n') // no stale element exception
# Using Jquery queue to get animation queue length. animationQueueIs = """ return $.queue( $("#%s")[0], "fx").length; """ % element_id wait_until(lambda: self.driver.execute_script(animationQueueIs)==0)
self.driver.execute_script("$(\"li:contains('Narendra')\").click()");
# Wait till the element goes stale, this means the list has updated wait_until(lambda: is_element_stale(old_link_reference))
私のために働いたこの解決策
リンクをクリックしようとすると、新しいページに移動します。その後、戻って他のリンクをクリックします。コードの下のそれらはあなたを助けるかもしれません。
public int getNumberOfElementsFound(By by) {
return driver.findElements(by).size();
}
public WebElement getElementWithIndex(By by, int pos) {
return driver.findElements(by).get(pos);
}
/**click on each link */
public void getLinks()throws Exception{
try {
List<WebElement> componentList = driver.findElements(By.tagName("a"));
System.out.println(componentList.size());
for (WebElement component : componentList)
{
//click1();
System.out.println(component.getAttribute("href"));
}
int numberOfElementsFound = getNumberOfElementsFound(By.tagName("a"));
for (int pos = 0; pos < numberOfElementsFound; pos++) {
if (getElementWithIndex(By.tagName("a"), pos).isDisplayed()){
getElementWithIndex(By.tagName("a"), pos).click();
Thread.sleep(200);
driver.navigate().back();
Thread.sleep(200);
}
}
}catch (Exception e){
System.out.println("error in getLinks "+e);
}
}
Fitnesseの場合、以下を使用できます。
|開始|スマートWebドライバー| Selenium.properties |
@Fixture(name = "Smart Web Driver")public class SmartWebDriver extends SlimWebDriver {
private final static Logger LOG = LoggerFactory.getLogger(SmartWebDriver.class);
/**
* Constructs a new SmartWebDriver.
*/
@Start(name = "Start Smart Web Driver", arguments = {"configuration"}, example = "|start |Smart Web Driver| Selenium.properties|")
public SmartWebDriver(String configuration) {
super(configuration);
}
/**
* Waits for an element to become invisible (meaning visible and width and height != 0).
*
* @param locator the locator to use to find the element.
*/
@Command(name = "smartWaitForNotVisible", arguments = {"locator"}, example = "|smartWaitForNotVisible; |//path/to/input (of css=, id=, name=, classname=, link=, partiallink=)|")
public boolean smartWaitForNotVisible(String locator) {
try {
waitForNotVisible(locator);
} catch (StaleElementReferenceException sere) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a StaleElementReferenceException occurred, trying to continue...", locator);
} catch (NoSuchElementException ele) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a NoSuchElementException occurred, trying to continue...", locator);
} catch (AssertionError ae) {
if (ae.getMessage().contains("No element found")) {
LOG.info("Element with locator '%s' did not become invisible (visible but also width and height != 0), a AssertionError occurred, trying to continue...", locator);
} else {
throw ae;
}
}
return true;
}
}
古い要素の例外が発生したとき!!
これらのテキストボックス/ボタン/リンクをサポートするライブラリが変更された場合、古い要素の例外が発生する可能性があります。つまり、要素は同じですが、ロケーターに影響を与えずにWebサイトで参照が変更されています。したがって、ページが更新されたライブラリで更新されたため、ライブラリ参照を含むキャッシュに保存した参照が古くなっているか、古くなっています。
for(int j=0; j<5;j++)
try {
WebElement elementName=driver.findElement(By.xpath(“somexpath”));
break;
} catch(StaleElementReferenceException e){
e.toString();
System.out.println(“Stale element error, trying :: ” + e.getMessage());
}
elementName.sendKeys(“xyz”);