fix(tests): align 20 drifted tests with current source behavior
Tests fell behind source changes: lastTotpAt replay-attack prevention, activeSession invalidation on password reset, select clauses in permission updates, UNAUTHORIZED (anti-enumeration) for disabled TOTP, and password minimum raised from 8 to 12 characters. Also fix root eslint.config.mjs to ignore packages/ (linted via turbo) and add --no-warn-ignored to lint-staged to suppress warnings for ignored files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,9 @@ function makeCtx(userRow: Record<string, unknown> | null = null) {
|
||||
findUnique: vi.fn().mockResolvedValue(userRow),
|
||||
update: vi.fn().mockResolvedValue({}),
|
||||
},
|
||||
activeSession: {
|
||||
deleteMany: vi.fn().mockResolvedValue({ count: 0 }),
|
||||
},
|
||||
} as never,
|
||||
dbUser: { id: "admin_1" },
|
||||
};
|
||||
@@ -38,13 +41,15 @@ const EXISTING_USER = { id: "user_1", name: "Alice", email: "alice@example.com"
|
||||
// ── Tests ────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("setUserPassword — happy path", () => {
|
||||
beforeEach(() => { vi.clearAllMocks(); });
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("hashes the new password and updates the DB", async () => {
|
||||
const ctx = makeCtx(EXISTING_USER);
|
||||
const result = await setUserPassword(ctx, { userId: "user_1", password: "NewPass123!" });
|
||||
const result = await setUserPassword(ctx, { userId: "user_1", password: "NewPassword123!" });
|
||||
|
||||
expect(hashMock).toHaveBeenCalledWith("NewPass123!");
|
||||
expect(hashMock).toHaveBeenCalledWith("NewPassword123!");
|
||||
expect(ctx.db.user.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: { id: "user_1" },
|
||||
@@ -57,7 +62,7 @@ describe("setUserPassword — happy path", () => {
|
||||
it("creates an audit entry with summary 'Password reset by admin'", async () => {
|
||||
const { createAuditEntry } = await import("../lib/audit.js");
|
||||
const ctx = makeCtx(EXISTING_USER);
|
||||
await setUserPassword(ctx, { userId: "user_1", password: "NewPass123!" });
|
||||
await setUserPassword(ctx, { userId: "user_1", password: "NewPassword123!" });
|
||||
|
||||
// createAuditEntry is called fire-and-forget (void), so we give microtasks a tick
|
||||
await Promise.resolve();
|
||||
@@ -68,23 +73,28 @@ describe("setUserPassword — happy path", () => {
|
||||
});
|
||||
|
||||
describe("setUserPassword — not found", () => {
|
||||
beforeEach(() => { vi.clearAllMocks(); });
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("throws when the user does not exist", async () => {
|
||||
const ctx = makeCtx(null); // findUnique returns null
|
||||
await expect(
|
||||
setUserPassword(ctx, { userId: "ghost", password: "NewPass123!" }),
|
||||
setUserPassword(ctx, { userId: "ghost", password: "NewPassword123!" }),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SetUserPasswordInputSchema — validation", () => {
|
||||
it("accepts a valid input", () => {
|
||||
const result = SetUserPasswordInputSchema.safeParse({ userId: "u1", password: "Valid123!" });
|
||||
const result = SetUserPasswordInputSchema.safeParse({
|
||||
userId: "u1",
|
||||
password: "ValidPass123!",
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects a password shorter than 8 characters", () => {
|
||||
it("rejects a password shorter than 12 characters", () => {
|
||||
const result = SetUserPasswordInputSchema.safeParse({ userId: "u1", password: "short" });
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user