From 3040758128a46b325e84e4696557c4bc0031ffc6 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 4 Aug 2026 17:45:58 -0500 Subject: [PATCH] host: Answer test-realm fetches in-page instead of via the service worker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Host tests serve http://test-realm/* URLs through a service worker that relays them to the in-browser mock realm. The worker only intercepts once it controls the page and its per-module activation has been acked, so a fetch issued before that window closes escapes to the real network and fails — test-realm is not a real host. When the fetch is fire-and-forget (a card component loading a realm's _types summary as it renders), the rejection surfaces as a QUnit global error and fails the whole shard rather than a single test. The test fetch wrapper now answers requests whose URL falls under a registered test realm via realm.maybeHandle. The registry is populated at realm construction, before any component can render, so this path has no startup window. A request the realm declines still falls through to the network, and non-fetch resources (images, workers) continue to rely on the service worker. Module-loading latency normally hides the race: base card modules are fetched and transpiled before their components can render, which takes long enough that the worker is ready. Anything that shortens that path re-exposes it. Co-Authored-By: Claude Opus 5 (1M context) --- packages/host/tests/helpers/setup.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/host/tests/helpers/setup.ts b/packages/host/tests/helpers/setup.ts index 0a4e48f354c..c1eace22d6e 100644 --- a/packages/host/tests/helpers/setup.ts +++ b/packages/host/tests/helpers/setup.ts @@ -20,6 +20,8 @@ import { clearHtmlComponentCache } from '@cardstack/host/lib/html-component'; import type SessionService from '@cardstack/host/services/session'; import { AiAssistantOpen } from '@cardstack/host/utils/local-storage-keys'; +import { getTestRealmRegistry } from './test-realm-registry'; + import { cleanupMonacoEditorModels } from './index'; // Pin `yaml` into the eager test bundle. `markdown-file-def` parses frontmatter @@ -268,6 +270,25 @@ function setupFetchDebugging(hooks: NestedHooks) { startedAt: Date.now(), }); try { + // Requests to a registered test realm are answered in-page rather + // than dispatched to the network. The service-worker relay that + // otherwise serves these URLs only intercepts once the worker + // controls the page and its per-module activation has been acked; + // a card component that renders (and fetches) before that window + // closes would otherwise hit the real network and fail, since the + // test-realm host doesn't exist outside the harness. The registry + // is populated at realm construction, so this path has no such + // window. Non-fetch resources (images, workers) still rely on the + // service worker. + for (let [realmUrl, { realm }] of getTestRealmRegistry()) { + if (url.startsWith(realmUrl)) { + let response = await realm.maybeHandle(new Request(input, init)); + if (response) { + return response; + } + break; + } + } return await boundFetch(input, init); } catch (error) { let reason = formatErrorForLog(error);