pythonseleniumfirefoxsplinter

Why does splinter is_text_present() cause intermittent StaleElementReferenceException with Firefox (but not Chrome or phantomjs)?


After upgrading my test environment to the latest versions of selenium, splinter, and Firefox, one of my tests now fails about 80% of the time using Firefox with the following:

Traceback (most recent call last):
  File "/Users/rbednark/Dropbox/git/quizme_website/questions/tests.py", line 103, in test_login_fails_incorrect_username
    "Your username and password didn't match. Please try again."
  File "/Users/rbednark/.virtualenvs/quizme-django-1.6.5/lib/python2.7/site-packages/splinter/driver/webdriver/__init__.py", line 302, in is_text_present
    self.driver.find_element_by_tag_name('body').text.index(text)
  File "/Users/rbednark/.virtualenvs/quizme-django-1.6.5/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 73, in text
    return self._execute(Command.GET_ELEMENT_TEXT)['value']
  File "/Users/rbednark/.virtualenvs/quizme-django-1.6.5/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 494, in _execute
    return self._parent.execute(command, params)
  File "/Users/rbednark/.virtualenvs/quizme-django-1.6.5/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 236, in execute
    self.error_handler.check_response(response)
  File "/Users/rbednark/.virtualenvs/quizme-django-1.6.5/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 192, in check_response
    raise exception_class(message, screen, stacktrace)
StaleElementReferenceException: Message: The element reference is stale. Either the element is no longer attached to the DOM or the page has been refreshed.

Note that this same test passes 100% of the time using Chrome and phantomjs. The test:

self.browser.visit(self.live_server_url)
self.assertEquals(self.browser.title, 'Quiz Me!')
self.browser.find_by_id('id_username')[0].fill(user)
self.browser.find_by_id('id_password')[0].fill(password)
# note that the following click() causes a page load
self.browser.find_by_value('login').click()
self.assertTrue(
      self.browser.is_text_present(
          "Your username and password didn't match. "
          "Please try again."
  )
)

firefox upgraded from 49.0.2 to 50.1.0
selenium upgraded from 2.46.0 to 3.0.2
splinter upgraded from 0.6.0 to 0.7.5
geckodriver 0.13.0
(the above are all the latest versions at the time this was posted)


Solution

  • I solved my problem 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

    Selenium source code that describes the StaleElementReferenceException.