import { readFileSync } from "node:fs"; import { randomUUID } from "node:crypto"; import { eq } from "drizzle-orm"; import { describe, expect, it } from "vitest"; import { getDb, createPasswordResetToken, getPasswordResetToken, markTokenAsUsed } from "../db"; import { passwordResetTokens, users } from "../../drizzle/schema"; const schema = readFileSync( new URL("../../drizzle/schema.ts", import.meta.url), "utf8", ); const databaseHelpers = readFileSync( new URL("../db.ts", import.meta.url), "utf8", ); const router = readFileSync( new URL("../routers.ts", import.meta.url), "utf8", ); const passwordResetTokenSchema = schema.match( /export const passwordResetTokens = mysqlTable\([\s\S]*?\n\}\);/, )?.[0]; describe("contrat des tokens de réinitialisation", () => { it("référence un utilisateur et non une colonne email absente de la table déployée", () => { expect(passwordResetTokenSchema).toContain('userId: int("userId").notNull()'); expect(passwordResetTokenSchema).not.toContain('email: varchar("email", { length: 320 }).notNull()'); expect(databaseHelpers).toContain( "createPasswordResetToken(userId: number, token: string)", ); expect(databaseHelpers).toContain("userId,"); }); it("utilise l’identifiant utilisateur dans les parcours public et administrateur", () => { expect(router).toContain("db.createPasswordResetToken(utilisateur.id, token)"); expect(router).toContain("db.createPasswordResetToken(user.id, token)"); expect(router).toContain("db.getUserById(resetToken.userId)"); }); it("ne génère plus de lien de réinitialisation sur un domaine fictif", () => { expect(router).not.toContain("https://votre-domaine.com/reset-password"); }); it("insère et consomme un token lié à un utilisateur sans dépendre d’un e-mail", async () => { const db = await getDb(); if (!db) throw new Error("Base de test indisponible"); const [user] = await db.select({ id: users.id }).from(users).limit(1); if (!user) throw new Error("Utilisateur de test introuvable"); const token = `test-${randomUUID()}`; try { await createPasswordResetToken(user.id, token); const created = await getPasswordResetToken(token); expect(created?.userId).toBe(user.id); expect(created?.used).toBe(false); await markTokenAsUsed(created!.id); const consumed = await getPasswordResetToken(token); expect(consumed?.used).toBe(true); } finally { await db.delete(passwordResetTokens).where(eq(passwordResetTokens.token, token)); } }); });