diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py index d5b6dde40..755f815d2 100644 --- a/src/SeleniumLibrary/keywords/waiting.py +++ b/src/SeleniumLibrary/keywords/waiting.py @@ -16,6 +16,8 @@ import time +from selenium.common.exceptions import StaleElementReferenceException + from SeleniumLibrary.base import LibraryComponent, keyword from SeleniumLibrary.errors import ElementNotFound from SeleniumLibrary.utils import is_noney, secs_to_timestr @@ -228,6 +230,9 @@ def _wait_until_worker(self, condition, timeout, error): return except ElementNotFound as err: not_found = str(err) + except StaleElementReferenceException as err: + self.info('Suppressing StaleElementReferenceException from Selenium.') + not_found = err else: not_found = None time.sleep(0.2) diff --git a/utest/test/keywords/test_waiting_stale_element_refereance_exception.py b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py new file mode 100644 index 000000000..49e2e80a7 --- /dev/null +++ b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py @@ -0,0 +1,84 @@ +import unittest + +from selenium.common.exceptions import StaleElementReferenceException +from mockito import mock, when, unstub + +from SeleniumLibrary.keywords import WaitingKeywords + + +def _raise(*a): + raise StaleElementReferenceException('Darn') + + +class TableKeywordsTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.ctx = mock() + cls.waiting = WaitingKeywords(cls.ctx) + cls.timeout = 0.5 + cls.count = 0 + + def tearDown(self): + unstub() + + def test_wait_until_element_is_visible(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, required=False).thenReturn(element) + when(element).is_displayed().thenRaise(StaleElementReferenceException()).thenReturn(True) + self.waiting.wait_until_element_is_visible(locator, self.timeout) + + def test_wait_until_element_is_visible_fails(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, required=False).thenReturn(element) + when(element).is_displayed().thenRaise(StaleElementReferenceException('foo')) + with self.assertRaisesRegexp(AssertionError, 'Message: foo'): + self.waiting.wait_until_element_is_visible(locator, self.timeout) + + def test_wait_until_element_is_not_visible(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, required=False).thenReturn(element) + when(element).is_displayed().thenRaise(StaleElementReferenceException()).thenReturn(False) + self.waiting.wait_until_element_is_not_visible(locator, self.timeout) + + def test_wait_until_element_is_enabled(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, None).thenReturn(element) + when(element).is_enabled().thenRaise(StaleElementReferenceException()).thenReturn(True) + self.waiting.wait_until_element_is_enabled(locator, self.timeout) + + def test_wait_until_element_is_enabled_get_attribute_readonly(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, None).thenReturn(element) + when(element).is_enabled().thenReturn(True) + when(element).get_attribute('readonly').thenRaise(StaleElementReferenceException()).thenReturn(None) + self.waiting.wait_until_element_is_enabled(locator, self.timeout) + + def test_wait_until_element_is_enabled_fails(self): + locator = '//div' + element = mock() + when(self.waiting).find_element(locator, None).thenReturn(element) + when(element).is_enabled().thenRaise(StaleElementReferenceException('foo')) + with self.assertRaisesRegexp(AssertionError, 'Message: foo'): + self.waiting.wait_until_element_is_enabled(locator, self.timeout) + + def test_wait_until_element_contains(self): + locator = '//div' + text = 'foo' + element1, element2 = mock(), mock({'text': 'foobar'}) + element1.__class__.text = property(_raise) + when(self.waiting).find_element(locator).thenReturn(element1).thenReturn(element2) + self.waiting.wait_until_element_contains(locator, text, self.timeout) + + def test_wait_until_element_does_not_contain(self): + locator = '//div' + text = 'foo' + element1, element2 = mock(), mock({'text': 'tidii'}) + element1.__class__.text = property(_raise) + when(self.waiting).find_element(locator).thenReturn(element1).thenReturn(element2) + self.waiting.wait_until_element_does_not_contain(locator, text, self.timeout)