mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
The unit suite reported all 1937 files green and then failed the job with `EnvironmentTeardownError: Closing rpc while "onUserConsoleLog" was pending`, naming a different scoring test each time. Vitest replaces globalThis.console with a sink that forwards every write to the main thread as an onUserConsoleLog RPC call. When a worker finishes a test file it awaits the calls in flight and then rejects whatever was started after that point, so a console write from work that outlived its test lands in the gap and fails the run. The blame goes to the file being torn down rather than to the test that started the work, which is why the named file never logged anything itself. Three paths detach a promise and log on the handle: fireAndForget, the stale-while-revalidate cache refresh, and the offline query persister. They now register the handled handle in a set that both suite setups drain in afterEach, so no test leaves work in flight. The registry is inert outside test: nothing there awaits it, and holding a reference to an unsettled promise would retain it for the life of a worker. No production behaviour changes, so there is no changelog entry. Evidence. A focused harness that starts failing background tasks and returns hit the teardown error 10 runs out of 10 before the change and 0 out of 10 after. Instrumenting the real suite showed two detached console writes per run escaping their test, both from the rollup tail; after the change, none, and thirteen writes per run now complete inside the test that started them. The guard asserts the behaviour, not a count: a registered task must keep settleBackgroundTasks from resolving ahead of it, and the set must drain back to empty. It goes red on unregistered work, on a disabled registry, on an unwrapped call site, on a sweep that matches nothing, and on a setup that drops the hook.
50 lines
2.2 KiB
TypeScript
50 lines
2.2 KiB
TypeScript
/**
|
|
* Unit-test setup.
|
|
*
|
|
* Seed the client-side locale cache with every message bundle. In
|
|
* production only EN ships statically; the active locale arrives as an
|
|
* RSC prop from the root layout and other locales load via dynamic
|
|
* import on switch (see `src/lib/i18n/load-locale.ts`). Tests mount
|
|
* `I18nProvider` standalone — often with `renderToStaticMarkup`, which
|
|
* is synchronous and cannot await a dynamic import — so the cache is
|
|
* primed up front and `t()` resolves every locale on the first render,
|
|
* exactly like the server-handoff path does in the app.
|
|
*/
|
|
import { afterEach } from "vitest";
|
|
import { settleBackgroundTasks } from "@/lib/logging/background-tasks";
|
|
import { primeMessages } from "@/lib/i18n/load-locale";
|
|
import deMessages from "./messages/de.json";
|
|
import enMessages from "./messages/en.json";
|
|
import esMessages from "./messages/es.json";
|
|
import frMessages from "./messages/fr.json";
|
|
import itMessages from "./messages/it.json";
|
|
import plMessages from "./messages/pl.json";
|
|
import koMessages from "./messages/ko.json";
|
|
|
|
primeMessages("de", deMessages);
|
|
primeMessages("en", enMessages);
|
|
primeMessages("es", esMessages);
|
|
primeMessages("fr", frMessages);
|
|
primeMessages("it", itMessages);
|
|
primeMessages("pl", plMessages);
|
|
primeMessages("ko", koMessages);
|
|
|
|
/**
|
|
* Leave no background work in flight when a test ends.
|
|
*
|
|
* Several paths start a promise, return without awaiting it, and log on the
|
|
* detached handle so the failure is not swallowed. Vitest forwards every
|
|
* console write to the main thread as an `onUserConsoleLog` RPC call and
|
|
* rejects whatever is still pending on that channel while it tears a test file
|
|
* down, so a write that lands in that window fails the whole run with
|
|
* `EnvironmentTeardownError: Closing rpc while "onUserConsoleLog" was pending`
|
|
* — blamed on the file the worker was tearing down, which is not the test that
|
|
* started the work and need not log anything of its own. Awaiting the
|
|
* registered tasks here removes the precondition instead of muting the
|
|
* console, which would have thrown away a real signal and left the
|
|
* non-determinism in place. See `src/lib/logging/background-tasks.ts`.
|
|
*/
|
|
afterEach(async () => {
|
|
await settleBackgroundTasks();
|
|
});
|