From 2356cb00ca06e45090a1128ed7c728a54d9c70f7 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Tue, 28 Apr 2026 16:05:40 -0600 Subject: [PATCH 1/3] fix: Update URL comparison check --- src/choreographer/protocol/devtools_async_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/choreographer/protocol/devtools_async_helpers.py b/src/choreographer/protocol/devtools_async_helpers.py index dafbb3ba..797b5e9e 100644 --- a/src/choreographer/protocol/devtools_async_helpers.py +++ b/src/choreographer/protocol/devtools_async_helpers.py @@ -34,9 +34,9 @@ async def _check_document_ready(session: Session, url: str) -> BrowserResponse: new Promise((resolve) => { if ( (document.readyState === 'complete') && - (window.location==`""" # CONCATENATE! + (window.location.href.startsWith(`""" # CONCATENATE! f"{url!s}" - """`) + """`)) ){ resolve("Was complete"); } else { From 443a731cd66a211b4bcf5b2c9ab60702ce72ee6e Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Tue, 22 Sep 2026 08:04:47 -0600 Subject: [PATCH 2/3] Add test --- tests/test_devtools_async_helpers.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_devtools_async_helpers.py b/tests/test_devtools_async_helpers.py index 86a83132..842def31 100644 --- a/tests/test_devtools_async_helpers.py +++ b/tests/test_devtools_async_helpers.py @@ -4,6 +4,7 @@ import pytest from choreographer.protocol.devtools_async_helpers import ( + _check_document_ready, create_and_wait, execute_js_and_wait, navigate_and_wait, @@ -52,6 +53,31 @@ async def test_create_and_wait(browser): await create_and_wait(browser, url="http://192.0.2.1:9999", timeout=0.5) +@pytest.mark.asyncio +async def test_check_document_ready_tolerates_missing_trailing_slash(browser): + """Test that the ready check tolerates a missing trailing slash""" + _logger.info("testing _check_document_ready...") + # Chrome normalizes "https://www.example.com" to "https://www.example.com/", + # so an exact comparison against the input URL never matches + url = "https://www.example.com" + tab = await create_and_wait(browser, url=url, timeout=5.0) + + session = await tab.create_session() + try: + # Chrome already fired the load event for this tab, so it never fires + # again. The check must take the readyState branch or it hangs + response = await asyncio.wait_for( + _check_document_ready(session, url), + timeout=5.0, + ) + except TimeoutError: + pytest.fail("The ready check hung, so it did not match the normalized URL") + finally: + await tab.close_session(session.session_id) + + assert response["result"]["result"]["value"] == "Was complete" + + @pytest.mark.asyncio async def test_navigate_and_wait(browser): """Test navigate_and_wait with both valid data URL and bad URL.""" From 58707642873a54b1260acec97567b13e09c64812 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Tue, 22 Sep 2026 08:05:10 -0600 Subject: [PATCH 3/3] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0257ac88..778eeec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ where X.Y.Z is the semver of the most recent choreographer release. ## [Unreleased] ### Fixed +- Fix the page-ready check so that a URL without a trailing slash no longer causes a false load timeout [[#295](https://github.com/plotly/choreographer/pull/295)] - Build the `ChromeNotFoundError` message as one string, so it no longer prints as a tuple [[#314](https://github.com/plotly/choreographer/pull/314)], with thanks to @Blizzeq for the contribution!