From 377c0a8d57a33104ecf6fc88e9844a543a96dda9 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sun, 23 Dec 2018 21:47:44 +0200 Subject: [PATCH 1/4] Supress StaleElementReferenceException in waiting keywords --- src/SeleniumLibrary/keywords/waiting.py | 4 ++ ...ting_stale_element_refereance_exception.py | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 utest/test/keywords/test_waiting_stale_element_refereance_exception.py diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py index d5b6dde40..74a5df378 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,8 @@ def _wait_until_worker(self, condition, timeout, error): return except ElementNotFound as err: not_found = str(err) + except StaleElementReferenceException as err: + 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..713f85dc0 --- /dev/null +++ b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py @@ -0,0 +1,64 @@ +import unittest + +from selenium.common.exceptions import StaleElementReferenceException +from mockito import mock, when, unstub, when2, patch + +from SeleniumLibrary.keywords import WaitingKeywords + + +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) From d91e24cb81e20b9d394c09b4515735a8ba9aadab Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sun, 23 Dec 2018 22:53:45 +0200 Subject: [PATCH 2/4] More tests --- ...ting_stale_element_refereance_exception.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/utest/test/keywords/test_waiting_stale_element_refereance_exception.py b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py index 713f85dc0..01ed364d8 100644 --- a/utest/test/keywords/test_waiting_stale_element_refereance_exception.py +++ b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py @@ -1,11 +1,15 @@ import unittest from selenium.common.exceptions import StaleElementReferenceException -from mockito import mock, when, unstub, when2, patch +from mockito import mock, when, unstub from SeleniumLibrary.keywords import WaitingKeywords +def _raise(*a): + raise StaleElementReferenceException('Darn') + + class TableKeywordsTest(unittest.TestCase): @classmethod @@ -62,3 +66,21 @@ def test_wait_until_element_is_enabled_fails(self): 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() + element1.__class__.text = property(_raise) + element2.text = 'foobar' + 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() + element1.__class__.text = property(_raise) + element2.text = 'tidii' + when(self.waiting).find_element(locator).thenReturn(element1).thenReturn(element2) + self.waiting.wait_until_element_does_not_contain(locator, text, self.timeout) From ed0f3a06413b8bbc07ed5526939c8b87ae7cd228 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sun, 23 Dec 2018 23:21:11 +0200 Subject: [PATCH 3/4] Added loggin when StaleElementReferenceException is seen --- src/SeleniumLibrary/keywords/waiting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SeleniumLibrary/keywords/waiting.py b/src/SeleniumLibrary/keywords/waiting.py index 74a5df378..755f815d2 100644 --- a/src/SeleniumLibrary/keywords/waiting.py +++ b/src/SeleniumLibrary/keywords/waiting.py @@ -231,6 +231,7 @@ def _wait_until_worker(self, condition, timeout, error): 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 From 559d5cf54d4f5caae9da2a40303ab6919a52f3fe Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Mon, 24 Dec 2018 00:02:51 +0200 Subject: [PATCH 4/4] Cleaning unit tests --- .../test_waiting_stale_element_refereance_exception.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utest/test/keywords/test_waiting_stale_element_refereance_exception.py b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py index 01ed364d8..49e2e80a7 100644 --- a/utest/test/keywords/test_waiting_stale_element_refereance_exception.py +++ b/utest/test/keywords/test_waiting_stale_element_refereance_exception.py @@ -70,17 +70,15 @@ def test_wait_until_element_is_enabled_fails(self): def test_wait_until_element_contains(self): locator = '//div' text = 'foo' - element1, element2 = mock(), mock() + element1, element2 = mock(), mock({'text': 'foobar'}) element1.__class__.text = property(_raise) - element2.text = 'foobar' 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() + element1, element2 = mock(), mock({'text': 'tidii'}) element1.__class__.text = property(_raise) - element2.text = 'tidii' when(self.waiting).find_element(locator).thenReturn(element1).thenReturn(element2) self.waiting.wait_until_element_does_not_contain(locator, text, self.timeout)