9

I am stuck in writing a Python Selenium script and can't seem to satisfactorily resolve this StaleElementReferenceException I am getting.

I have my page loaded and click a button which opens a form that allows the user to add a new credit card to the order. At this point I do a WebDriverWait to pause the script until the Save button on this form becomes visible. At that point, recreate the page object since it has changed, and my intent is to populate the fields and save the card.

The problem is that after refreshing the page object the script fails with the StaleElementReferenceException. My understanding is that the WebDriverWait will pause the the execution giving the page time to load all the elements that need to load, but that doesn't appear to be happening. Instead something in that refresh of the page object is stale and causes the error (different part of the object creation each time).

If I just uncomment the line 'time.sleep(2)' then this script runs fine and it will pass. So I know I just need to give the page time to reload correctly before I refresh the object. The WebDriverWait just doesn't seem to be doing that effectively for me.

Is there a more correct way I can do this without the sleep command?

checkout = CheckoutProcess(self.driver)

# Add Credit Card
checkout.add_credit_card()

# Wait for form to display
WebDriverWait(self.driver,30).until(
    expected_conditions.presence_of_element_located((By.CLASS_NAME, 'total')))

# time.sleep(2)

# Refresh the page object so form can be filled in
checkout = CheckoutProcess(self.driver)  # Script Fails Here
checkout.populate_credit_card_data(
    credit_card_name, credit_card_number,
    credit_card_expiration_date, credit_card_cvc)
checkout.click_credit_card_save_button()
4
  • You need to add more information in your question. Where is the code for CheckoutProcess ? Show us the exact stack trace. Also, which url are you testing ? Btw, are you using a custom framework (which wraps around selenium) to do your work instead of pure selenium ? Commented Oct 13, 2016 at 21:06
  • 1
    My $0.02... don't scrape the page on instantiating the page object. Scrape the page as you use the elements. For example, in .populate_credit_card_data() do a .find_* for each of the elements, do .send_keys(), and so on. That will eliminate the stale element exception. Commented Oct 13, 2016 at 21:09
  • Also... I'm with testerjoe2 in that we need to see the code for CheckoutProcess(). You are likely referencing some element without fetching it first... or there's some time between fetching and using where it goes stale. You probably need a good way to determine if the page has finished loading. Commented Oct 13, 2016 at 21:12
  • When CheckoutProcess is instantiated it has some variables that are populated with data from the page. I used this for some test scripts, but most don't need this data. Most of the time these variables populate fine, but in this case that is not so. Where they fail changes from run to run in this script. I commented out that line of code, and now will just call the function that populates that data as I need it. That should be a small price to pay for solving this issue. Commented Oct 14, 2016 at 16:26

3 Answers 3

7

A StaleElementReferenceException is thrown when the element you were interacting is destroyed and then recreated. Most complex web pages these days will move things about on the fly as the user interacts with it and this requires elements in the DOM to be destroyed and recreated.

Try doing

wait.until(ExpectedConditions.stalenessOf(whatever element));

or

wait.until(ExpectedConditions.presenceOfElementLocated(By.id("whatever elemnt")))

Hope it will help you

Sign up to request clarification or add additional context in comments.

1 Comment

I've extracted all links I want to click which are <h3> tags. using link_list = browser.find_by_tag('h3'). then I loop through it and click each link. I am able to store all data scraped however it gives me an error preventing to goto next page. Any help? Thanks.
4

I had this same problem and solved it by implementing this wrapper that retries when the exception is caught:

from selenium.common.exceptions import StaleElementReferenceException

def _loop_is_text_present(text, max_attempts=3):
    attempt = 1
    while True:
        try:
            return self.browser.is_text_present(text)
        except StaleElementReferenceException:
            if attempt == max_attempts:
                raise
            attempt += 1

Inspired by: http://darrellgrainger.blogspot.com/2012/06/staleelementexception.html

Comments

2
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import StaleElementReferenceException


    def objectIdentificationUsingWaits(self, maxTimeOut, locatorProperties, locatorType = "xpath"):
        element = None
        try:
            WebDriverWait(self.driver, maxTimeOut, ignored_exceptions=[StaleElementReferenceException]).until(
                EC.presence_of_element_located((self.getLocatorType(locatorType), locatorProperties)))
            element = self.driver.find_element(locatorType, locatorProperties)
        except:
            print("Exception occurred during object identification.")
        return element

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.