From 2abe689af45984a4080e2e7e46f8bd7ded1932c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 19:30:42 +0000 Subject: [PATCH] web-e2e: discover the delayed proxy package with Refresh from upstream Since #841 (#836), a proxy's package page answers from what the proxy has cached and asks no upstream: GET /browse/packages/{repo}/{id} of a package the proxy holds nothing of is a 404, and looking no longer discovers it. The proxy-delay spec discovered the upstream's Sample.Lib by that GET, so it failed with a 404 and web-e2e failed on main. The spec now follows the page's own flow: it opens the package page, sees Package not cached, clicks Refresh from upstream, and finds the version row with the delayed badge; the detail API, from the cache now, surfaces the version as delayed_until. The first look waits out the detail query's two retries of the 404. fetchPackageDetail's comment no longer says the read discovers a proxy's package. Fixes #858 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012e6DJbCpYhgvM3SxcYuMD1 --- web/e2e/helpers.ts | 7 +++--- web/e2e/specs/proxy-delay.spec.ts | 36 ++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/web/e2e/helpers.ts b/web/e2e/helpers.ts index 61965445..5bfee7e4 100644 --- a/web/e2e/helpers.ts +++ b/web/e2e/helpers.ts @@ -90,9 +90,10 @@ export async function addGroupMember( /** * Fetch a package's browse detail (the read endpoint the SPA's detail page - * uses). For a proxy this also drives upstream **discovery** (it runs the - * proxy read ops), so calling it stamps `first_seen_at` and surfaces a - * still-delayed version with `delay_status = "delayed_until"`. + * uses). For a proxy it answers from what the proxy has cached and asks no + * upstream (#836): a package the proxy holds nothing of is a 404 until a + * client installs it or **Refresh from upstream** discovers it. A + * still-delayed version carries `delay_status = "delayed_until"`. */ export async function fetchPackageDetail( repo: string, diff --git a/web/e2e/specs/proxy-delay.spec.ts b/web/e2e/specs/proxy-delay.spec.ts index 20f6887a..b920c684 100644 --- a/web/e2e/specs/proxy-delay.spec.ts +++ b/web/e2e/specs/proxy-delay.spec.ts @@ -12,7 +12,10 @@ import { * Proxy delay status. * * An admin configures a proxy with a long package delay through the repository - * form. A version freshly discovered upstream is inside the delay window, so: + * form. The package page shows what the proxy has cached and asks no upstream + * (#836), so the package is **not cached** until **Refresh from upstream** + * discovers it. A version freshly discovered upstream is inside the delay + * window, so: * * - the package-detail view renders the `DelayBadge` as **delayed** (the * version exists upstream but is not yet downloadable); @@ -53,25 +56,32 @@ test('a delayed proxy version shows the delay badge and is absent from browse', await page.getByRole('button', { name: /create repository/i }).click() await expect(page).toHaveURL(new RegExp(`/manage/repositories/${proxy}`)) - // 2. Trigger upstream discovery: hitting the detail read path runs the proxy - // read ops, which stamp `first_seen_at` and (because the delay has not - // elapsed) surface the version as `delayed_until`. - const detail = await fetchPackageDetail(proxy, 'Sample.Lib') - const delayed = detail.versions.find((v) => v.delay_status === 'delayed_until') - expect(delayed, 'a delayed version should be surfaced').toBeTruthy() - expect(delayed?.delayed_until).toBeTruthy() - - // 3. Package detail in the browser: the delay badge reads "delayed". (For a - // delayed-only proxy package there is no cached original casing yet, so the - // heading shows the requested lowercased id — match case-insensitively.) + // 2. The package page answers from the cache and asks no upstream: the proxy + // holds nothing of the package yet, so the page says it is not cached + // (looking does not discover it). The page shows that once its detail + // query has given up on the 404, after two retries a few seconds apart. await page.goto(`/packages/${proxy}/sample.lib`) - await expect(page.getByRole('heading', { name: /sample\.lib/i })).toBeVisible() + await expect(page.getByText('Package not cached')).toBeVisible({ timeout: 15_000 }) + + // 3. Refresh from upstream asks the upstream, as a client's install does: + // it stamps the version's `first_seen_at`, and as the delay has not + // elapsed the page shows it delayed. (For a delayed-only proxy package + // there is no cached original casing yet, so the heading shows the + // requested lowercased id — match case-insensitively.) + await page.getByRole('button', { name: 'Refresh from upstream' }).click() // The version row carries the delayed badge. const row = page .getByRole('table', { name: /^Versions of / }) .getByRole('row', { name: /1\.2\.3/ }) await expect(row).toBeVisible() await expect(row.getByText(/delayed/)).toBeVisible() + await expect(page.getByRole('heading', { name: /sample\.lib/i })).toBeVisible() + + // The detail API, from the cache now, surfaces the version as delayed. + const detail = await fetchPackageDetail(proxy, 'Sample.Lib') + const delayed = detail.versions.find((v) => v.delay_status === 'delayed_until') + expect(delayed, 'a delayed version should be surfaced').toBeTruthy() + expect(delayed?.delayed_until).toBeTruthy() // 4. The delay-gated version is absent from downloadable browse: search in // THIS proxy's folder view never surfaces a delay-gated version, so the