diff --git a/tests/e2e/utils.py b/tests/e2e/utils.py index 5fab62ed18..d92896cfd5 100644 --- a/tests/e2e/utils.py +++ b/tests/e2e/utils.py @@ -249,36 +249,60 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase): Raises a clear test failure if the element isn't found, the text doesn't appear within `timeout` seconds, or the text is not valid JSON. """ + use_body = context is None + wait_timeout = timeout or self.wait_timeout + + def get_context() -> WebElement: + """Get or refresh the context element.""" + if use_body: + return self.driver.find_element(By.TAG_NAME, "body") + return context + + def get_text_safely() -> str: + """Get element text, re-finding element if stale.""" + for _ in range(5): + try: + return get_context().text.strip() + except StaleElementReferenceException: + sleep(0.5) + return get_context().text.strip() + + def get_inner_html_safely() -> str: + """Get innerHTML, re-finding element if stale.""" + for _ in range(5): + try: + return get_context().get_attribute("innerHTML") or "" + except StaleElementReferenceException: + sleep(0.5) + return get_context().get_attribute("innerHTML") or "" try: - if context is None: - context = self.driver.find_element(By.TAG_NAME, "body") + get_context() except NoSuchElementException: self.fail( f"No element found (defaulted to
). Current URL: {self.driver.current_url}" ) - wait_timeout = timeout or self.wait_timeout - wait = WebDriverWait(context, wait_timeout) + wait = WebDriverWait(self.driver, wait_timeout) try: - wait.until(lambda d: len(d.text.strip()) != 0) + wait.until(lambda d: len(get_text_safely()) != 0) except TimeoutException: - snippet = context.text.strip()[:500].replace("\n", " ") + snippet = get_text_safely()[:500].replace("\n", " ") self.fail( f"Timed out waiting for element text to appear at {self.driver.current_url}. " f"Current content: {snippet or '