const request = require("supertest"); const app = require("../src/app"); const prisma = require("../src/config/prisma"); const jwt = require("jsonwebtoken"); const bcrypt = require("bcrypt"); const mailer = require("../src/config/mailer"); jest.mock("../src/config/mailer", () => ({ sendMail: jest.fn() })); const DAY = 86400000; const PREFIX = "notif-"; const CODE = "NOTIFTICK1"; let ctx = {}; async function cleanup() { const us = await prisma.user.findMany({ where: { email: { contains: PREFIX } } }); const ids = us.map((u) => u.id); const ps = await prisma.participation.findMany({ where: { userId: { in: ids } } }); await prisma.claim.deleteMany({ where: { participationId: { in: ps.map((p) => p.id) } } }); await prisma.participation.deleteMany({ where: { userId: { in: ids } } }); await prisma.grandPrizeWinner.deleteMany({ where: { userId: { in: ids } } }); await prisma.ticket.deleteMany({ where: { code: CODE } }); await prisma.user.deleteMany({ where: { id: { in: ids } } }); } const tk = (u) => jwt.sign({ id: u.id, role: u.role }, process.env.JWT_SECRET, { expiresIn: "1h" }); const jourJ = (d) => prisma.gameSettings.update({ where: { id: ctx.settingsId }, data: { startDate: new Date(Date.now() - d * DAY) }, }); beforeAll(async () => { await cleanup(); const row = await prisma.gameSettings.findFirst({ orderBy: { id: "asc" } }); ctx.settingsId = row.id; ctx.startDateOriginale = row.startDate; const lot = await prisma.lot.findFirst({ orderBy: { id: "asc" } }); await prisma.ticket.create({ data: { code: CODE, lotId: lot.id } }); const h = await bcrypt.hash("Password123", 10); ctx.admin = await prisma.user.create({ data: { firstname: "Alice", lastname: "Admin", email: PREFIX + "admin@test.local", password: h, role: "ADMIN", isEmailVerified: true } }); ctx.client = await prisma.user.create({ data: { firstname: "Chloe", lastname: "Martin", email: PREFIX + "chloe@test.local", password: h, role: "CLIENT", isEmailVerified: true } }); ctx.tAdmin = tk(ctx.admin); await jourJ(1); mailer.sendMail.mockResolvedValue(true); await request(app).post("/api/game/participate").set("Authorization", "Bearer " + tk(ctx.client)).send({ code: CODE }).expect(201); await jourJ(35); }); afterAll(async () => { await prisma.gameSettings.update({ where: { id: ctx.settingsId }, data: { startDate: ctx.startDateOriginale } }); await cleanup(); await prisma.$disconnect(); }); describe("Notification du grand gagnant", () => { beforeEach(() => jest.clearAllMocks()); test("le gagnant recoit un email a son adresse", async () => { mailer.sendMail.mockResolvedValue(true); const res = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin).expect(201); expect(res.body.emailSent).toBe(true); expect(mailer.sendMail).toHaveBeenCalledTimes(1); const envoi = mailer.sendMail.mock.calls[0][0]; expect(envoi.to).toBe(ctx.client.email); expect(envoi.subject).toMatch(/gros lot/i); expect(envoi.html).toContain("Chloe"); expect(envoi.html).toContain("360"); await prisma.grandPrizeWinner.deleteMany({ where: { userId: ctx.client.id } }); }); test("un SMTP en panne n invalide pas le tirage", async () => { mailer.sendMail.mockRejectedValue(new Error("SMTP indisponible")); const res = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin); expect(res.status).toBe(201); expect(res.body.emailSent).toBe(false); expect(res.body.message).toMatch(/contacter directement/); // Le tirage reste enregistre : c est un acte irreversible. const enBase = await prisma.grandPrizeWinner.findFirst({ where: { userId: ctx.client.id } }); expect(enBase).not.toBeNull(); await prisma.grandPrizeWinner.deleteMany({ where: { userId: ctx.client.id } }); }); test("aucun email n est envoye si le tirage est refuse", async () => { mailer.sendMail.mockResolvedValue(true); await jourJ(1); const res = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin); expect(res.status).toBe(409); expect(mailer.sendMail).not.toHaveBeenCalled(); await jourJ(35); }); });