2012-10-19 10 views
45

मैं जावा का उपयोग कर कई सेलेनियम परीक्षणों को कार्यान्वित कर रहा हूं। कभी-कभी, मेरे परीक्षण StaleElementReferenceException के कारण विफल हो जाते हैं। क्या आप परीक्षण को और अधिक स्थिर बनाने के लिए कुछ दृष्टिकोण सुझा सकते हैं?सेलेनियम में "StaleElementReferenceException" से कैसे बचें?

उत्तर

44

यह तब हो सकता है जब पृष्ठ पर एक डीओएम ऑपरेशन हो रहा है अस्थायी रूप से तत्व को अनावश्यक होने का कारण बनता है। उन मामलों की अनुमति देने के लिए, आप अंततः अपवाद फेंकने से पहले लूप में कई बार तत्व तक पहुंचने का प्रयास कर सकते हैं।

this excellent solution from darrelgrainger.blogspot.com का प्रयास करें:

public boolean retryingFindClick(By by) { 
    boolean result = false; 
    int attempts = 0; 
    while(attempts < 2) { 
     try { 
      driver.findElement(by).click(); 
      result = true; 
      break; 
     } catch(StaleElementException e) { 
     } 
     attempts++; 
    } 
    return result; 
} 
+0

वाह! यह वही था जो मुझे चाहिए था। धन्यवाद! – SpartaSixZero

+0

इसे तत्व के विभिन्न संदर्भों का उपयोग करके भी ठीक किया जा सकता है। –

+0

कि 2 रिट्रीज़ के साथ एक बहुत गंदा समाधान है, इंतजार करना चाहिए। मेरा समाधान देखें – cocorossello

11

आम तौर पर यह डोम की वजह से अपडेट किया जा रहा है और आप एक अद्यतन/नए तत्व का उपयोग करने की कोशिश कर रहा है - लेकिन डोम के ताजा तो यह गलत संदर्भ आपके पास है ..

अद्यतन पूर्ण होने के लिए तत्व पर एक स्पष्ट प्रतीक्षा का उपयोग करके इसे पहले प्राप्त करें, फिर तत्व के लिए एक नया संदर्भ लें।

WebDriverWait wait = new WebDriverWait(browser, TimeSpan.FromSeconds(10)); 
IWebElement aRow = browser.FindElement(By.XPath(SOME XPATH HERE); 
IWebElement editLink = aRow.FindElement(By.LinkText("Edit")); 

//this Click causes an AJAX call 
editLink.Click(); 

//must first wait for the call to complete 
wait.Until(ExpectedConditions.ElementExists(By.XPath(SOME XPATH HERE)); 

//you've lost the reference to the row; you must grab it again. 
aRow = browser.FindElement(By.XPath(SOME XPATH HERE); 

//now proceed with asserts or other actions. 

आशा इस मदद करता है:

यहाँ कुछ छद्म वर्णन करने के लिए कोड (मैं के लिए बिल्कुल इस मुद्दे का उपयोग कुछ सी # कोड से अनुकूलित) है!

40

मुझे इस मुद्दे को अंतःस्थापित किया गया था। मेरे लिए अनजान, बैकबोनजेएस पृष्ठ पर चल रहा था और उस तत्व को बदल रहा था जिसे मैं क्लिक करने का प्रयास कर रहा था। मेरा कोड इस तरह दिखता था।

driver.findElement(By.id("checkoutLink")).click(); 

जो वास्तव में इस तरह कार्यात्मक रूप से समान है।

WebElement checkoutLink = driver.findElement(By.id("checkoutLink")); 
checkoutLink.click(); 

कभी-कभी क्या होता है जावास्क्रिप्ट चेकआउट लिंक तत्व को खोजने और क्लिक करने के बीच में बदल देगा, यानी।

WebElement checkoutLink = driver.findElement(By.id("checkoutLink")); 
// javascript replaces checkoutLink 
checkoutLink.click(); 

जब लिंक पर क्लिक करने की कोशिश कर रहा कौन सा हक एक StaleElementReferenceException का नेतृत्व किया। जब तक जावास्क्रिप्ट चलाना समाप्त नहीं हुआ तब तक वेबड्राइवर को प्रतीक्षा करने के लिए मुझे कोई विश्वसनीय तरीका नहीं मिला, इसलिए यहां मैंने अंततः इसे हल किया।

new WebDriverWait(driver, timeout) 
    .ignoring(StaleElementReferenceException.class) 
    .until(new Predicate<WebDriver>() { 
     @Override 
     public boolean apply(@Nullable WebDriver driver) { 
      driver.findElement(By.id("checkoutLink")).click(); 
      return true; 
     } 
    }); 

इस कोड को लगातार StaleElementReferenceExceptions अनदेखी जब तक या तो क्लिक सफल होता है या समय समाप्त हो जाती है, लिंक पर क्लिक करने की कोशिश करेंगे। मुझे यह समाधान पसंद है क्योंकि यह आपको किसी भी पुनः प्रयास तर्क लिखने के लिए बचाता है, और केवल वेबड्राइवर की अंतर्निर्मित संरचनाओं का उपयोग करता है।

-4

शायद इसे हाल ही में जोड़ा गया था, लेकिन अन्य उत्तर सेलेनियम की निहित प्रतीक्षा सुविधा का उल्लेख करने में असफल रहे, जो आपके लिए उपरोक्त सभी करता है, और सेलेनियम में बनाया गया है।

driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);

यह findElement() कॉल फिर से प्रयास करेगा जब तक तत्व पाया गया है, या 10 सेकंड के लिए।

स्रोत - http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp

+1

वह समाधान StaleElementReferenceException – MrSpock

+0

को रोकता नहीं है, संस्करणों पर किसी भी भ्रम को खत्म करने के लिए, यहां तक ​​कि सेलेनियम के नवीनतम संस्करण में भी स्पष्ट रूप से Wait() StaleElementReferenceException को रोकता नहीं है। मैं ऐसी विधि का उपयोग करता हूं जो नींद के साथ लूप में सफलता या निश्चित गणना तक कॉल करता है। –

1

सी # में एक समाधान होगा:

सहायक वर्ग:

internal class DriverHelper 
{ 

    private IWebDriver Driver { get; set; } 
    private WebDriverWait Wait { get; set; } 

    public DriverHelper(string driverUrl, int timeoutInSeconds) 
    { 
     Driver = new ChromeDriver(); 
     Driver.Url = driverUrl; 
     Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeoutInSeconds)); 
    } 

    internal bool ClickElement(string cssSelector) 
    { 
     //Find the element 
     IWebElement element = Wait.Until(d=>ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver); 
     return Wait.Until(c => ClickElement(element, cssSelector)); 
    } 

    private bool ClickElement(IWebElement element, string cssSelector) 
    { 
     try 
     { 
      //Check if element is still included in the dom 
      //If the element has changed a the OpenQA.Selenium.StaleElementReferenceException is thrown. 
      bool isDisplayed = element.Displayed; 

      element.Click(); 
      return true; 
     } 
     catch (StaleElementReferenceException) 
     { 
      //wait until the element is visible again 
      element = Wait.Until(d => ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver); 
      return ClickElement(element, cssSelector); 
     } 
     catch (Exception) 
     { 
      return false; 
     } 
    } 
} 

प्रार्थना:

 DriverHelper driverHelper = new DriverHelper("http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp", 10); 
     driverHelper.ClickElement("input[value='csharp']:first-child"); 

इसी तरह जावा के लिए इस्तेमाल किया जा सकता है।

0

कारण StaleElementReferenceException पहले से ही बाहर रखा गया है: तत्व के साथ कुछ खोजने और करने के बीच डोम के अपडेट।

public void clickOn(By locator, WebDriver driver, int timeout) 
{ 
    final WebDriverWait wait = new WebDriverWait(driver, timeout); 
    wait.until(ExpectedConditions.refreshed(
     ExpectedConditions.elementToBeClickable(locator))); 
    driver.findElement(locator).click(); 
} 

महत्वपूर्ण हिस्सा सेलेनियम के अपने ExpectedConditionsExpectedConditions.refreshed() के माध्यम से की "श्रृंखलन" है:

क्लिक के समस्या के लिए मैं हाल ही में इस तरह एक समाधान का उपयोग किया है। यह वास्तव में प्रतीक्षा करता है और जांच करता है कि निर्दिष्ट समय के दौरान प्रश्न में तत्व को ताज़ा किया गया है और इसके अतिरिक्त तत्व को क्लिक करने योग्य बनने की प्रतीक्षा है।

documentation for the refreshed method पर एक नज़र डालें।

new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.id("checkoutLink"))); 
driver.findElement(By.id("checkoutLink")).click(); 
4

केनी के समाधान अच्छा है, लेकिन यह एक और अधिक सुरुचिपूर्ण तरीका

new WebDriverWait(driver, timeout) 
     .ignoring(StaleElementReferenceException.class) 
     .until((WebDriver d) -> { 
      d.findElement(By.id("checkoutLink")).click(); 
      return true; 
     }); 

या भी लिखा जा सकता है। यह WebElement के लिए एक रैपर है जो यह पता लगाने में सक्षम है कि क्या तत्व स्टेल है और मूल तत्व का नया संदर्भ ढूंढता है। मैंने उन तत्वों को ढूंढने के लिए एक सहायक तरीके जोड़े हैं जो WebElement के बजाय StableWebElement को वापस करते हैं और StaleElementReference के साथ समस्या गायब हो जाती है।

public static IStableWebElement FindStableElement(this ISearchContext context, By by) 
{ 
    var element = context.FindElement(by); 
    return new StableWebElement(context, element, by, SearchApproachType.First); 
} 

सी # में कोड अपने प्रोजेक्ट के पृष्ठ पर उपलब्ध है, लेकिन यह आसानी से जावा https://github.com/cezarypiatek/Tellurium/blob/master/Src/MvcPages/SeleniumUtils/StableWebElement.cs

0

अपने प्रोजेक्ट में मैं StableWebElement की एक धारणा की शुरुआत की:

0

में पोर्ट किया जा सकता है यह मैं (100% काम कर रहे) के लिए काम करता है का उपयोग करते हुए सी #

public Boolean RetryingFindClick(IWebElement webElement) 
    { 
     Boolean result = false; 
     int attempts = 0; 
     while (attempts < 2) 
     { 
      try 
      { 
       webElement.Click(); 
       result = true; 
       break; 
      } 
      catch (StaleElementReferenceException e) 
      { 
       Logging.Text(e.Message); 
      } 
      attempts++; 
     } 
     return result; 
    } 
संबंधित मुद्दे