test(auth): read the password hash off the stored row in proof tests

The proof gates now read whether an account has a password from its own
row rather than from the per-request user, so the suites that drive
them mock that read instead of carrying the hash on the session user.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 20:56:08 +02:00
1 parent 63a3e354c8
commit 652dd6943b
8 files changed
+30 -6

No files matched your search

@@ -14,7 +14,11 @@ vi.mock("@/lib/db", () => ({
session: { findUnique: vi.fn() },
webauthnMfaCredential: { count: vi.fn(async () => 0) },
passkey: { count: vi.fn(async () => 0) },
user: { findFirst: vi.fn() },
user: {
findFirst: vi.fn(),
// The stored row: the password hash is not on the session user.
findUnique: vi.fn(async () => ({ passwordHash: "argon" })),
},
accountGrant: { create: vi.fn(), findFirst: vi.fn() },
},
}));
@@ -50,7 +54,6 @@ const OWNER = {
role: "USER",
username: "owner",
totpConfirmedAt: null,
passwordHash: "argon",
};
function invite(): NextRequest {
@@ -17,7 +17,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
import { NextRequest } from "next/server";
vi.mock("@/lib/db", () => ({
prisma: {},
// The cached briefing text is read off its own row, not the session user.
prisma: { user: { findUnique: async () => null } },
}));
vi.mock("@/lib/auth/session", () => ({
getSession: vi.fn(),
@@ -71,7 +72,6 @@ const SESSION_OK = {
glucoseUnit: "mg/dL",
onboardingTourCompleted: true,
disableCoach: false,
insightsCachedText: null,
insightsCachedAt: null,
dashboardWidgetsJson: null,
},
@@ -28,6 +28,8 @@ vi.mock("@/lib/db", () => ({
},
webauthnMfaCredential: { count: vi.fn(async () => 0) },
passkey: { count: vi.fn(async () => 0) },
// The password hash is read off the stored row; none here.
user: { findUnique: vi.fn(async () => null) },
},
}));
vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() }));
@@ -35,6 +35,8 @@ vi.mock("@/lib/db", () => ({
},
webauthnMfaCredential: { count: vi.fn(async () => 0) },
passkey: { count: vi.fn(async () => 0) },
// The password hash is read off the stored row; none here.
user: { findUnique: vi.fn(async () => null) },
},
}));
vi.mock("@/lib/app-settings", () => ({
@@ -19,6 +19,8 @@ vi.mock("@/lib/db", () => ({
},
webauthnMfaCredential: { count: vi.fn(async () => 0) },
passkey: { count: vi.fn(async () => 0) },
// The password hash is read off the stored row; none here.
user: { findUnique: vi.fn(async () => null) },
},
}));
vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() }));
@@ -28,6 +28,8 @@ vi.mock("@/lib/db", () => ({
},
webauthnMfaCredential: { count: vi.fn(async () => 0) },
passkey: { count: vi.fn(async () => 0) },
// The password hash is read off the stored row; none here.
user: { findUnique: vi.fn(async () => null) },
},
}));
+10 -1
View File
@@ -5,6 +5,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("@/lib/db", () => ({
prisma: {
session: { findUnique: vi.fn() },
user: { findUnique: vi.fn() },
webauthnMfaCredential: { count: vi.fn() },
passkey: { count: vi.fn() },
},
@@ -50,7 +51,15 @@ beforeEach(() => {
vi.resetAllMocks();
});
function mockSession(user: unknown) {
function mockSession(user: {
id: string;
totpConfirmedAt: Date | null;
passwordHash?: string | null;
}) {
// The password hash is read off the stored row, not the session user.
vi.mocked(prisma.user.findUnique).mockResolvedValue({
passwordHash: user.passwordHash ?? null,
} as never);
vi.mocked(getSession).mockResolvedValue({
session: { id: "sess-1", expiresAt: new Date(Date.now() + 1e6) },
user,
@@ -72,13 +72,17 @@ beforeEach(() => {
});
function cookie(
user: unknown,
user: { id: string; passwordHash?: string | null },
stamps: {
mfaVerifiedAt?: Date | null;
createdAt?: Date;
reproofAt?: Date | null;
},
) {
// The password hash is read off the stored row, not the session user.
vi.mocked(prisma.user.findUnique).mockResolvedValue({
passwordHash: user.passwordHash ?? null,
} as never);
vi.mocked(getSession).mockResolvedValue({
session: { id: "sess-1", expiresAt: new Date(Date.now() + 1e6) },
user,