fix(web): typed-routes + redirect-mock signatures in auth.ts

Next.js 16 typed-routes (experimental.typedRoutes in next.config.ts)
narrows redirect()'s parameter to RouteImpl<T>, which a runtime
string from the form can't satisfy. Cast to any with a comment for
the two redirect call sites in auth.ts.

The auth.test.ts redirectMock used `() =>` zero-arg signature, which
typescript rejected once the action started passing the path through.
Change to `(_path: string) =>` so the signature matches and the test
still passes (vitest's esbuild-transpiled run was fine; tsc caught it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
yiekheng 2026-05-10 17:54:59 +08:00
parent 4f1056cdcd
commit 5b4787d10e
2 changed files with 9 additions and 5 deletions

View File

@ -15,7 +15,7 @@ const {
findUserMock: vi.fn(),
headersGetMock: vi.fn(() => "127.0.0.1"),
checkRateLimitMock: vi.fn(),
redirectMock: vi.fn(() => {
redirectMock: vi.fn((_path: string) => {
throw new Error("redirect");
}),
loggerMock: { warn: vi.fn(), info: vi.fn() },
@ -28,7 +28,7 @@ vi.mock("next/headers", () => ({
}),
}));
vi.mock("next/navigation", () => ({
redirect: (...a: unknown[]) => redirectMock(...a),
redirect: (path: string) => redirectMock(path),
}));
vi.mock("@/lib/db", () => ({
db: {
@ -52,7 +52,7 @@ beforeEach(() => {
checkRateLimitMock.mockReset();
checkRateLimitMock.mockResolvedValue({ limited: false, count: 1 });
redirectMock.mockReset();
redirectMock.mockImplementation(() => {
redirectMock.mockImplementation((_path: string) => {
throw new Error("redirect");
});
loggerMock.warn.mockReset();

View File

@ -106,11 +106,15 @@ export async function loginAction(formData: FormData): Promise<LoginResult> {
maxAge: DEFAULT_TTL_SECONDS,
});
redirect(safeRedirect(next));
// Typed-routes is on (next.config.ts experimental.typedRoutes); the
// `next` value is a runtime string from the form so we cast through any.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
redirect(safeRedirect(next) as any);
}
export async function logoutAction(): Promise<void> {
const jar = await cookies();
jar.delete(COOKIE_NAME);
redirect("/login");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
redirect("/login" as any);
}