From ec25b3a046cc9c84c558ef40675b0dcd18fb7f08 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 11 Sep 2024 18:18:09 -0700 Subject: [PATCH] tests: functional: Don't timeout when web server restarts Likely helps: #2271. When web server restarts we are shown an error page. Trying to lookup and element in this error page still raises StaleElementReferenceException. However, if the page was reloaded with driver.visit(), then trying to lookup the old element does not throw StaleElementReferenceException. Instead the NoSuchElementException is thrown. For this case, ensure that we stop waiting appropriately. This is likely to solve the large waits and timeouts when testing dynamicdns. Signed-off-by: Sunil Mohan Adapa --- plinth/tests/functional/__init__.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 49d212b1c..0eee46ef2 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -16,6 +16,7 @@ from contextlib import contextmanager import pytest import requests from selenium.common.exceptions import (ElementClickInterceptedException, + NoSuchElementException, StaleElementReferenceException, WebDriverException) from selenium.webdriver.support.ui import WebDriverWait @@ -99,19 +100,47 @@ class _PageLoaded(): def __init__(self, element, expected_url=None): self.element = element self.expected_url = expected_url + self.loaded_new_page = False def __call__(self, driver): is_stale = False try: self.element.has_class('whatever_class') + # XXX: There is still another unhandled case where the webserver + # restarts after submission of a form and the browser does not switch + # to error page. It continues to wait for a response from the server + # indefinitely until timeout. + except NoSuchElementException: + # This is still the old page, wait for it to change. + if not self.loaded_new_page: + return False + + # This is the new page and we are not waiting for a specific URL. + # Stop waiting. + if not self.expected_url: + return True + + # This is the new page and expected URL has not reached, wait for + # the page to spontaneously change. + if not driver.url.endswith(self.expected_url): + return False + + # This is the new page and we have reached the expected URL. Stop + # waiting. + return True except (StaleElementReferenceException, TypeError): # After a domain name change, Let's Encrypt will restart the web # server and could cause a connection failure. if driver.find_by_id('netErrorButtonContainer'): try: driver.visit(driver.url) + # After this for some unknown reason, + # StaleElementReferenceException is no longer thrown. + self.loaded_new_page = True except WebDriverException: + # Web server is not yet available. pass + return False is_fully_loaded = driver.execute_script(