diff --git a/tests/render_harness.py b/tests/render_harness.py index d750f9c1b..29c5f1ce3 100644 --- a/tests/render_harness.py +++ b/tests/render_harness.py @@ -1340,6 +1340,27 @@ def new_page(**kwargs): return SimpleNamespace(new_page=new_page) +def margins_laid_out(page): + """Run the margin layout the page has scheduled, so a geometry read follows it. + + The margin's own geometry owner answers a width change through a ResizeObserver on + the body and a `requestAnimationFrame`, which is one whole rendering turn later than + the resize event `resized` waits for. A read taken in between is a read of the rows + at the width they have just left: on a page narrowed to exactly what its residents + need, the widest margin row was still at its roomy width and hung 24px past the + window — but only on the runs where the frame had not landed yet, which is why the + same probe condensed on one run and not the next. + + The pending frame is not a fact to wait a frame for (`tests/CLAUDE.md`, "a fixed + number of animation frames only guesses"), so the work is run instead of guessed at. + Whether the observer schedules it at all is `test_render_margin.py`'s subject, not + that of a test reading the layout it produces.""" + page.evaluate( + "() => import('/runtime/margin-layout.js')" + ".then(({layoutMarginRows}) => layoutMarginRows())" + ) + + def panel_settled(page, open=True): """Wait for the panel to reach `open` and the page to finish making room for it. diff --git a/tests/render_support.py b/tests/render_support.py index 6136af34b..a012a2fe0 100644 --- a/tests/render_support.py +++ b/tests/render_support.py @@ -309,6 +309,7 @@ hold_selection, key_line, leaf_page, + margins_laid_out, navigate, nudge, open_page, @@ -600,6 +601,7 @@ "live_leaf", "live_url", "live_watcher", + "margins_laid_out", "mark_edges", "mark_point", "mark_shows_beside_composer", diff --git a/tests/test_render_margin.py b/tests/test_render_margin.py index c28f2527a..748522985 100644 --- a/tests/test_render_margin.py +++ b/tests/test_render_margin.py @@ -15,6 +15,7 @@ compare_with, leaf_page, live_url, + margins_laid_out, open_page, panel_settled, resized, @@ -1028,9 +1029,7 @@ def offset(): page.evaluate( "() => document.scrollingElement.scrollBy({top: 320, behavior: 'instant'})" ) - page.evaluate( - "() => import('/runtime/margin-layout.js').then(({layoutMarginRows}) => layoutMarginRows())" - ) + margins_laid_out(page) assert offset() == pytest.approx(before, abs=1) assert errors == [] diff --git a/tests/test_render_pages.py b/tests/test_render_pages.py index 5221db0e2..5870abf95 100644 --- a/tests/test_render_pages.py +++ b/tests/test_render_pages.py @@ -52,6 +52,7 @@ composer_quote, leaf_page, live_url, + margins_laid_out, nudge, open_page, page_registry, @@ -2036,6 +2037,7 @@ def test_a_left_sidebar_uses_the_margin_until_the_page_needs_it_back(browser, se }""" resized(page, 1400, 900) + margins_laid_out(page) roomy = page.evaluate(reading) assert roomy["strip"] == 264 assert roomy["float"] == "left" and roomy["position"] == "sticky" @@ -2069,6 +2071,7 @@ def test_a_left_sidebar_uses_the_margin_until_the_page_needs_it_back(browser, se # root scrollport holds outside the container query's own width. exact = roomy["strip"] + 720 + roomy["rail"] resized(page, math.ceil(exact + roomy["viewportWidth"] - roomy["pageWidth"]), 900) + margins_laid_out(page) tighter = page.evaluate(reading) assert exact <= tighter["pageWidth"] <= exact + 1, ( f"the narrowed page is not the width the residents and column need: {tighter}"