mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
A module mock that leaves out an export the code under test reaches throws at the call, and where that code catches and logs (a best-effort tail, a fail-soft read) the test went on green while the path it meant to cover never ran. The Apple Health import tests mocked the rollup module without its fold window, so the import tail's rollup fold and cache invalidation never ran in any of them; four route test files mocked the logging context or the rollups without what the measurement tail reaches. Both setup files now watch the console and fail the test in which such a line was logged. The ECG import test keeps the real rollup module and stubs only the fold, and the four unit mocks gain what they lacked.
53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
/**
|
|
* A module mock that leaves out an export the code under test reaches throws
|
|
* `No "X" export is defined on the "Y" mock` at the call. Where the code
|
|
* catches and logs that (a best-effort tail, a fail-soft read), the test went
|
|
* on green while the code path it meant to cover never ran: the Apple Health
|
|
* import tests mocked the rollup module without its fold window, and the
|
|
* import's cache invalidation never ran in any of them.
|
|
*
|
|
* `watchSwallowedMockErrors` wraps the console once per worker and returns
|
|
* the check a setup file runs after each test: it throws, failing that test,
|
|
* when such a line was logged during it.
|
|
*/
|
|
const MISSING_MOCK_EXPORT = /No "[^"]+" export is defined on the "[^"]+" mock/;
|
|
|
|
function textOf(arg: unknown): string {
|
|
if (arg instanceof Error) return `${arg.message} ${String(arg.cause ?? "")}`;
|
|
return typeof arg === "string" ? arg : "";
|
|
}
|
|
|
|
const SEEN = Symbol.for("healthlog.tests.swallowedMockErrors");
|
|
|
|
export function watchSwallowedMockErrors(): () => void {
|
|
// A setup file runs once per test file, and a worker runs many files: the
|
|
// console is wrapped once per worker, and every file shares what it saw.
|
|
const slot = globalThis as unknown as { [SEEN]?: string[] };
|
|
let seen = slot[SEEN];
|
|
if (!seen) {
|
|
const lines: string[] = [];
|
|
seen = lines;
|
|
slot[SEEN] = lines;
|
|
for (const level of ["log", "info", "warn", "error"] as const) {
|
|
const original = console[level].bind(console);
|
|
console[level] = (...args: unknown[]) => {
|
|
for (const arg of args) {
|
|
const match = MISSING_MOCK_EXPORT.exec(textOf(arg));
|
|
if (match) lines.push(match[0]);
|
|
}
|
|
original(...args);
|
|
};
|
|
}
|
|
}
|
|
const lines = seen;
|
|
return () => {
|
|
if (lines.length === 0) return;
|
|
const found = [...new Set(lines)];
|
|
lines.length = 0;
|
|
throw new Error(
|
|
"a module mock lacks an export the code under test reached, and the " +
|
|
`error was caught and logged instead of failing: ${found.join("; ")}`,
|
|
);
|
|
};
|
|
}
|