mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
763736eae0
* refactor(app-rsc-entry): delegate pure helpers to typed server modules The generated RSC entry template contained five inline implementations of pure runtime helpers: post-middleware request context construction, RSC error handler creation, request context cleanup, RSC stream preload hint normalization, and hook warning suppression. These inline blocks repeated runtime behavior across multiple call sites and could not be unit-tested independently. Move each helper to a dedicated typed module under server/ so the generated entry imports and wires them instead of owning the logic: - buildPostMwRequestContext → server/app-post-middleware-context.ts - createRscOnErrorHandler → server/app-rsc-error-handler.ts - __clearRequestContext + setNavigationContext → server/app-request-context.ts - renderToReadableStream preload hints → server/rsc-stream-hints.ts (createRscRenderer) - hook warning console.error patch → server/app-hook-warning-suppression.ts Each helper module has focused unit tests. The entry template is 55 lines shorter and now describes the app shape; the typed modules own behaviour. * fix: remove redundant as cast and fix test module caching app-hook-warning-suppression.ts contained an `as string` cast that was redundant because the typeof check on the prior line already narrows the type. The hook warning suppression tests in tests 2-4 were passing vacuously because dynamic import() returned the cached module whose console.error patch was no longer active after test 1 restored the original. Use vi.resetModules() before each test to force fresh module evaluation. clearAppRequestContext now delegates to setAppNavigationContext(null) instead of calling the raw navigation and root-params setters directly, matching the DRY pattern from the original inline code. * fix: resolve entry helper rebase conflicts * ci: rerun checks (font-google flake) * Update packages/vinext/src/entries/app-rsc-entry.ts Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> --------- Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com>
88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
import { describe, expect, it, vi, beforeEach } from "vite-plus/test";
|
|
|
|
describe("app-hook-warning-suppression", () => {
|
|
// The module patches console.error at import time. In a vitest environment,
|
|
// dynamic imports are cached across tests within the same suite. To ensure
|
|
// each test gets a fresh module evaluation (so the side-effect runs and
|
|
// captures the test's spy as _origConsoleError), we reset the module cache
|
|
// before each test.
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
});
|
|
|
|
it("suppresses 'Invalid hook call' messages when the ALS store is true", async () => {
|
|
const spy = vi.fn();
|
|
const prev = console.error;
|
|
console.error = spy;
|
|
try {
|
|
const { suppressHookWarningAls } =
|
|
await import("../packages/vinext/src/server/app-hook-warning-suppression.js");
|
|
|
|
// The module's patched console.error is active because import() ran the
|
|
// side-effect. suppressHookWarningAls.run(true, ...) sets the ALS store;
|
|
// the patched console.error checks the store and suppresses the message.
|
|
suppressHookWarningAls.run(true, () => {
|
|
console.error("Invalid hook call: check render method of ServerComponent");
|
|
});
|
|
expect(spy).not.toHaveBeenCalled();
|
|
} finally {
|
|
console.error = prev;
|
|
}
|
|
});
|
|
|
|
it("does NOT suppress non-hook messages even when the ALS store is true", async () => {
|
|
const spy = vi.fn();
|
|
const prev = console.error;
|
|
console.error = spy;
|
|
try {
|
|
const { suppressHookWarningAls } =
|
|
await import("../packages/vinext/src/server/app-hook-warning-suppression.js");
|
|
|
|
suppressHookWarningAls.run(true, () => {
|
|
console.error("A real error that should not be suppressed");
|
|
});
|
|
// The patched console.error should forward non-hook messages to the
|
|
// original (spy), not suppress them.
|
|
expect(spy).toHaveBeenCalledOnce();
|
|
expect(spy.mock.calls[0]?.[0]).toBe("A real error that should not be suppressed");
|
|
} finally {
|
|
console.error = prev;
|
|
}
|
|
});
|
|
|
|
it("passes 'Invalid hook call' messages through when the ALS store is NOT set", async () => {
|
|
const spy = vi.fn();
|
|
const prev = console.error;
|
|
console.error = spy;
|
|
try {
|
|
const { suppressHookWarningAls } =
|
|
await import("../packages/vinext/src/server/app-hook-warning-suppression.js");
|
|
|
|
// Outside of .run(), the ALS store is undefined. The patched
|
|
// console.error should forward the message to the original (spy).
|
|
expect(suppressHookWarningAls.getStore()).toBeUndefined();
|
|
|
|
console.error("Invalid hook call: check render method of Page");
|
|
expect(spy).toHaveBeenCalledOnce();
|
|
} finally {
|
|
console.error = prev;
|
|
}
|
|
});
|
|
|
|
it("forwards all arguments to the original console.error when not suppressing", async () => {
|
|
const spy = vi.fn();
|
|
const prev = console.error;
|
|
console.error = spy;
|
|
try {
|
|
await import("../packages/vinext/src/server/app-hook-warning-suppression.js");
|
|
|
|
// The patched console.error is active. Non-hook messages with multiple
|
|
// arguments should be forwarded exactly as received.
|
|
console.error("message", { detail: "payload" }, 42);
|
|
expect(spy).toHaveBeenCalledWith("message", { detail: "payload" }, 42);
|
|
} finally {
|
|
console.error = prev;
|
|
}
|
|
});
|
|
});
|