Selenium WebDriver StaleElementReferenceException

Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException вообще.

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

25
задан Ripon Al Wasim 31 July 2015 в 10:37
поделиться

10 ответов

Я столкнулся с этой же проблемой и не смог найти решения. Придумал решение и разместил его здесь, надеюсь, это поможет кому-то с такой же проблемой. Я создал класс для обработки устаревших элементов в зависимости от их типа, cssselector, id и т. Д. И просто вызывал его, как и любой другой объект страницы.

public void StaleElementHandleByID (String elementID){
int count = 0;
boolean clicked = false;
while (count < 4 || !clicked){
    try {
       WebElement yourSlipperyElement= driver.findElement(By.id(elementID));
       yourSlipperyElement.click(); 
       clicked = true;
     } catch (StaleElementReferenceException e){
       e.toString();
       System.out.println("Trying to recover from a stale element :" + e.getMessage());
       count = count+1;
     }     
}

Я бы рекомендовал использовать это только для тех элементов, которые, как вы знаете, вызывают проблемы для WebDriver.

30
ответ дан Andreas Waldahl 31 July 2015 в 10:37
поделиться

Мы обходим эту проблему, делая что-то под названием WebdriverWrapper и WebElementWrapper.

То, что делают эти оболочки, это обрабатывать исключение StaleElementException внутри, а затем использовать локатор для повторной оценки и получения нового объекта WebElement. Таким образом, вам нужно распространить код, обрабатывающий исключение, по всей базе кода и локализовать его для одного класса.

Я скоро расскажу об открытых источниках этих двух классов и добавлю ссылку сюда, если вам интересно.

8
ответ дан xyz 31 July 2015 в 10:37
поделиться

Это исключение выдается, когда вы пытаетесь использовать метод WebElement, которого больше нет на странице. Если ваша сетка загружает данные динамически, и вы обновляете сетку, любые ссылки на элементы этой сетки будут «устаревшими». Дважды проверьте, что элемент, на который вы пытаетесь сослаться, находится на странице в ваших тестах, и вам может понадобиться создать экземпляр объекта.

4
ответ дан pnewhook 31 July 2015 в 10:37
поделиться

Возможно, вы пытаетесь получить любое из свойств элемента после нажатия на элемент.

У меня была такая же проблема, я пытался получить текст () кнопки после ее нажатия. В моем случае, после нажатия кнопки появляется новое окно.

1
ответ дан ram_c 31 July 2015 в 10:37
поделиться

Я сделал некоторые изменения, чтобы быть более гибким:

   delegate void StaleFunction(IWebElement elt);
        private static void StaleElementHandleByID(By by, StaleFunction func )
        {
            int count = 0;
            while (count < 4)
            {
                try
                {
                    IWebElement yourSlipperyElement = Driver.FindElement(by);
                    func(yourSlipperyElement);
                    count = count + 4;
                }
                catch (StaleElementReferenceException e)
                {
                    count = count + 1;
                }

            }
        }

 StaleElementHandleByID(By.Id("identDdl"),
                    delegate(IWebElement elt)
                {
                    SelectElement select = new SelectElement(elt);
                    select.SelectByText(tosave.ItemEquipamentoCem.CodigoCne.ToString());
                });
0
ответ дан WoF_Angel 31 July 2015 в 10:37
поделиться

В этом случае тесты ищут элемент, который еще не загружен или был обновлен. В результате возникает StaleElementException. Простым решением было бы добавить fluentWait.

0
ответ дан Kermit_ice_tea 31 July 2015 в 10:37
поделиться

быстрый & amp; грязное решение:

el.click()

time.sleep(1)

затем продолжить анализ в итерационном порядке

-1
ответ дан netz75 31 July 2015 в 10:37
поделиться
public static Boolean executeElementSendKeys
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
    return (Boolean) executeElementMaster
            (driver, element, "sendKeys", sInputParameters, 30, true);
}

public static Boolean executeElementClear
(WebDriver driver, WebElement element) throws Exception {
    return (Boolean) executeElementMaster (driver, element, "clear", "", 30, true);
}

public static String executeElementGetText
(WebDriver driver, WebElement element) throws Exception {
    return (String) executeElementMaster (driver, element, "getText", "", 30, true);
}

public static Boolean executeElementClick
(WebDriver driver, WebElement element) throws Exception {
    return (Boolean) executeElementMaster (driver, element, "click", "", 30, true);
}

public static boolean executeElementIsDisplayed
(WebDriver driver, WebElement element) throws Exception {
    return (Boolean) executeElementMaster (driver, element, "isDisplayed", "", 30, true);
}

public static String executeElementGetAttribute
(WebDriver driver, WebElement element, String sInputParameters) throws Exception {
    return (String) executeElementMaster
            (driver, element, "getAttribute", sInputParameters, 30, true);
}

// И ниже мастер-метод, который обрабатывает StaleElementReferenceException и другие исключения.

// В разделе catch замените (Exception e) на (StaleElementReferenceException e), если вы хотите, чтобы этот метод повторял действия (например, щелчок, sendkeys и т. Д.) Только для StaleElementReferenceException, а не для других исключений.

private static Object executeElementMaster(WebDriver driver, WebElement element, String sExecuteAction, String sInputParametersOptional, int MaxTimeToWait,
        boolean bExpectedElementState) throws Exception {
    try {
        // Local variable declaration
        String sElementString = "";
        String sElementXpath = "";
        Object ReturnValue = "";
        int Index = 0;
        boolean bCurrentElementState = true;
        boolean bWebDriverWaitUntilElementClickableFlag = false;

        System.out.println("**** Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Expected : '" + bExpectedElementState + "'");
        System.out.println("**** MaxTimeToWait ='" + MaxTimeToWait + "' seconds");

        // Set browser timeout to 1 second. Will be reset to default later
        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);

        // Keep trying until 'MaxTimeToWait' is reached 
        for (int i = 0; i < MaxTimeToWait; i++) {
            try {
                // Get element xPath - and find element again
                if (element != null && i < 2 && sElementString == "") {
                    sElementString = (element).toString();
                    if (sElementString.contains("xpath: ")) {
                        // Retrieve xPath from element, if available
                        Index = sElementString.indexOf("xpath: ");
                        sElementXpath = sElementString.substring(Index + 7, sElementString.length());
                    }
                }

                // Find Element again
                if (sElementXpath != "" && i > 0) {
                    element = driver.findElement(By.xpath(sElementXpath));
                }

                // Execute the action requested
                switch (sExecuteAction) {
                    case ("isDisplayed"):
                        // Check if element is displayed and save in bCurrentElementState variable
                        ReturnValue = element.isDisplayed();
                        bCurrentElementState = (Boolean) ReturnValue;
                        bWebDriverWaitUntilElementClickableFlag = true;
                        break;
                    case ("getText"):
                        ReturnValue = element.getText();
                        bCurrentElementState = true;
                        bWebDriverWaitUntilElementClickableFlag = false;
                        break;
                    case ("sendKeys"):
                        // Scroll element into view before performing any action

                        element.sendKeys(sInputParametersOptional);
                        ReturnValue = true;
                        bCurrentElementState = true;
                        bWebDriverWaitUntilElementClickableFlag = false;
                        break;
                    case ("clear"):
                        // Scroll element into view before performing any action

                        element.clear();
                        ReturnValue = true;
                        bCurrentElementState = true;
                        bWebDriverWaitUntilElementClickableFlag = false;
                        break;
                    case ("click"):
                        // Scroll element into view before performing any action

                        element.click();
                        ReturnValue = true;
                        bCurrentElementState = true;
                        bWebDriverWaitUntilElementClickableFlag = false;
                        break;
                    default:
                        ReturnValue = element.getAttribute(sInputParametersOptional);
                        bCurrentElementState = true;
                        break;
                }
            } catch (Exception e) {
                Thread.sleep(500);
                bCurrentElementState = false;
                ReturnValue = false;
            }
            if (bCurrentElementState == bExpectedElementState) {
                // If element's actual and expected states match, log result and return value
                System.out.println("**** PASSED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' ****   \n"
                        + "Actual element status: '" + bCurrentElementState + "'  Expected element status: '" + bExpectedElementState + "'");
                break;
            } else {
                // If element's actual and expected states do NOT match, loop until they match or timeout is reached
                Thread.sleep(500);
            }
        }
        // Reset browser timeout to default
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // Return value before exiting
        if (bCurrentElementState != bExpectedElementState) {
            // If element's actual and expected states do NOT match, log result and return value
            System.out.println("**** FAILED: Execute method '" + sExecuteAction + "' on '" + sElementString + "' - Returned '" + ReturnValue + "' ****   \n"
                    + "Actual element status: '" + bCurrentElementState + "'  Expected element status: '" + bExpectedElementState + "'");
            if (sExecuteAction.equalsIgnoreCase("findElement")) {
                ReturnValue = null;
            }
        }

        return ReturnValue;
    } catch (Exception e) {
        System.out.println("Exception in executeElementMaster - " + e.getMessage());
        throw (e);
    }
}
1
ответ дан Nash N 31 July 2015 в 10:37
поделиться

Я использовал FluentWait, а также переопределение применения ExpectedCondition: https://gist.github.com/djangofan/5112655 . Этот обрабатывает исключение внутри завершенного блока, в отличие от того, как другие люди отвечают на это, и позволяет заключить последовательные попытки в этот блок. Я думаю, что это более элегантно.

public static void clickByLocator( final By locator ) {
  final long startTime = System.currentTimeMillis();
  driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
  Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
        .withTimeout(90000, TimeUnit.MILLISECONDS)
        .pollingEvery(5500, TimeUnit.MILLISECONDS);
        //.ignoring( StaleElementReferenceException.class );        
  wait.until( new ExpectedCondition<Boolean>() { 
    @Override 
    public Boolean apply( WebDriver webDriver ) {
      try {
        webDriver.findElement( locator ).click();
        return true;
      } catch ( StaleElementReferenceException e ) {                      // try again
        return false;
      }     
    } 
  } );      
  driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
  long endTime   = System.currentTimeMillis();
  long totalTime = endTime - startTime;
  log("Finished click after waiting for " + totalTime + " milliseconds.");
}
1
ответ дан djangofan 31 July 2015 в 10:37
поделиться

@netz75:Спасибо. имел эту проблему, когда щелчок перенаправляет к второй странице. Это работало на меня:

 //.. (first page asserts)
 //...
 element.Click();   
 Thread.Sleep(200);
 //.. (second page asserts)
 //...
0
ответ дан 28 November 2019 в 20:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: