From a848c142c80b8af62e700236fae6b09bc6de0d52 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Fri, 29 May 2026 16:22:58 +0800 Subject: [PATCH] test(reader): de-flake scrolled-mode backward-preload precondition (#4112) (#4354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two #4112 scrolled-mode preload browser tests asserted that the previous-previous section (F-1) was not loaded after navigating to a section, checking it after `waitForFillComplete()`. The eager backward buffer (minPages) is suppressed while `#display` is stabilizing, but pulls F-1 (and beyond) in on the first scroll events once the fill settles. So the post-fill assertion raced the buffer: it passed locally but failed intermittently on CI (loaded set [1,2,3,4,5]). Assert the precondition the instant `#display` stabilizes — where the buffer is provably suppressed and only the immediate-previous section is loaded — before the fill settles. The eager buffer loading F-1 later is exactly what the second test wants once it navigates back. Test-only; production behaviour is unchanged. Co-authored-by: Claude Opus 4.8 (1M context) --- .../paginator-scrolled.browser.test.ts | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/readest-app/src/__tests__/document/paginator-scrolled.browser.test.ts b/apps/readest-app/src/__tests__/document/paginator-scrolled.browser.test.ts index ebae91a5..cda43113 100644 --- a/apps/readest-app/src/__tests__/document/paginator-scrolled.browser.test.ts +++ b/apps/readest-app/src/__tests__/document/paginator-scrolled.browser.test.ts @@ -197,11 +197,17 @@ describe('Paginator scrolled mode (browser)', () => { return null; }; - // 1) Navigate to M so #display preloads F above it. + // 1) Navigate to M so #display preloads F above it. Assert the loaded set + // the instant #display stabilizes: #display only pulls in the immediate + // previous section (F), and the scroll-handler backward buffer stays + // suppressed while #stabilizing. Everything below — up to the goTo(F) + // that is meant to prepend F-1 — runs synchronously, so the eager + // backward buffer can't pull F-1 in early and steal the measurement. + // (Waiting for the fill to settle first is racy: once #stabilizing ends + // the minPages backward buffer may pull F-1 in — readest/readest#4112.) const stabilized = waitForStabilized(paginator); await paginator.goTo({ index: M, anchor: 0 }); await stabilized; - await waitForFillComplete(paginator); // F is loaded as the top view; F-1 has not been pulled in yet. const loadedIndices = () => paginator.getContents().map((c) => c.index); @@ -251,12 +257,18 @@ describe('Paginator scrolled mode (browser)', () => { expect(F).toBeGreaterThan(0); const M = F + 1; - // Navigate to M (preloads F above it); F-1 is not loaded yet. + // Navigate to M (preloads F above it). Assert F-1 is not loaded the instant + // #display stabilizes — #display only pulls in the immediate previous + // section (F), and the scroll-handler backward buffer is suppressed while + // #stabilizing. Asserting after the fill settles is racy: once + // stabilization ends the eager minPages backward buffer may pull F-1 in + // (readest/readest#4112). It doing so later is fine — that is exactly what + // we want once we navigate back, below. const stabilized = waitForStabilized(paginator); await paginator.goTo({ index: M, anchor: 0 }); await stabilized; - await waitForFillComplete(paginator); expect(paginator.getContents().map((c) => c.index)).not.toContain(F - 1); + await waitForFillComplete(paginator); // Navigate one section back to F. The previous section (F-1) must be // pre-loaded so the user can immediately scroll up into it.