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) }, }); // Un tirage reel peut exister en base : la table GrandPrizeWinner est unique // pour tout le jeu. On la met de cote le temps du test, puis on la restaure. async function mettreDeCoteLeGagnant() { const existant = await prisma.grandPrizeWinner.findFirst(); if (existant) await prisma.grandPrizeWinner.delete({ where: { id: existant.id } }); return existant; } async function restaurerLeGagnant(sauvegarde) { if (!sauvegarde) return; await prisma.grandPrizeWinner.deleteMany({}); await prisma.grandPrizeWinner.create({ data: { id: sauvegarde.id, userId: sauvegarde.userId, prize: sauvegarde.prize, drawnAt: sauvegarde.drawnAt, }, }); } beforeAll(async () => { ctx.gagnantSauvegarde = await mettreDeCoteLeGagnant(); 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 restaurerLeGagnant(ctx.gagnantSauvegarde); 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); // Le tirage est aleatoire parmi tous les participants : on verifie que // l email part bien au gagnant annonce, quel qu il soit. const gagnant = res.body.winner.user; const envoi = mailer.sendMail.mock.calls[0][0]; expect(envoi.to).toBe(gagnant.email); expect(envoi.subject).toMatch(/gros lot/i); expect(envoi.html).toContain(gagnant.firstname); expect(envoi.html).toContain("360"); await prisma.grandPrizeWinner.deleteMany({}); }); 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(); expect(enBase).not.toBeNull(); expect(enBase.userId).toBe(res.body.winner.user.id); await prisma.grandPrizeWinner.deleteMany({}); }); 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); }); });