ajout des champs date de naissance et gender sur l'inscription, modification de la permition de lancer le jeu concour par l'administrateur, envoie des mail a chaque lot remporter
This commit is contained in:
106
backend/tests/drawNotification.test.js
Normal file
106
backend/tests/drawNotification.test.js
Normal file
@@ -0,0 +1,106 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
113
backend/tests/gainNotification.test.js
Normal file
113
backend/tests/gainNotification.test.js
Normal file
@@ -0,0 +1,113 @@
|
||||
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 = "gain-";
|
||||
const CODES = ["GAINTICK01", "GAINTICK02", "GAINTICK03"];
|
||||
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: { in: CODES } } });
|
||||
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;
|
||||
|
||||
ctx.lot = await prisma.lot.findFirst({ orderBy: { id: "asc" } });
|
||||
for (const c of CODES) await prisma.ticket.create({ data: { code: c, lotId: ctx.lot.id } });
|
||||
|
||||
const h = await bcrypt.hash("Password123", 10);
|
||||
ctx.client = await prisma.user.create({ data: { firstname: "Chloe", lastname: "Martin", email: PREFIX + "chloe@test.local", password: h, role: "CLIENT", isEmailVerified: true } });
|
||||
ctx.tClient = tk(ctx.client);
|
||||
|
||||
await jourJ(1);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.gameSettings.update({ where: { id: ctx.settingsId }, data: { startDate: ctx.startDateOriginale } });
|
||||
await cleanup();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
describe("Notification du gain a chaque participation", () => {
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
test("le joueur recoit un email decrivant son lot", async () => {
|
||||
mailer.sendMail.mockResolvedValue(true);
|
||||
|
||||
const res = await request(app)
|
||||
.post("/api/game/participate")
|
||||
.set("Authorization", "Bearer " + ctx.tClient)
|
||||
.send({ code: CODES[0] })
|
||||
.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).toContain(ctx.lot.name);
|
||||
expect(envoi.html).toContain("Chloe");
|
||||
expect(envoi.html).toContain(CODES[0]);
|
||||
expect(envoi.html).toContain(ctx.lot.name);
|
||||
});
|
||||
|
||||
test("un SMTP en panne n annule pas la participation", async () => {
|
||||
mailer.sendMail.mockRejectedValue(new Error("SMTP indisponible"));
|
||||
|
||||
const res = await request(app)
|
||||
.post("/api/game/participate")
|
||||
.set("Authorization", "Bearer " + ctx.tClient)
|
||||
.send({ code: CODES[1] });
|
||||
|
||||
expect(res.status).toBe(201);
|
||||
expect(res.body.emailSent).toBe(false);
|
||||
|
||||
// Le gain reste acquis et consultable.
|
||||
const t = await prisma.ticket.findUnique({ where: { code: CODES[1] } });
|
||||
expect(t.isUsed).toBe(true);
|
||||
|
||||
const gains = await request(app).get("/api/game/my-gains").set("Authorization", "Bearer " + ctx.tClient).expect(200);
|
||||
expect(gains.body.gains.some((g) => g.ticketCode === CODES[1])).toBe(true);
|
||||
});
|
||||
|
||||
test("aucun email si le code est refuse", async () => {
|
||||
mailer.sendMail.mockResolvedValue(true);
|
||||
|
||||
const rejoue = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[0] });
|
||||
expect(rejoue.status).toBe(409);
|
||||
|
||||
const inconnu = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: "INEXISTAN1" });
|
||||
expect(inconnu.status).toBe(404);
|
||||
|
||||
await jourJ(45);
|
||||
const horsDelai = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[2] });
|
||||
expect(horsDelai.status).toBe(410);
|
||||
await jourJ(1);
|
||||
|
||||
expect(mailer.sendMail).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
163
backend/tests/gameFlow.test.js
Normal file
163
backend/tests/gameFlow.test.js
Normal file
@@ -0,0 +1,163 @@
|
||||
const request = require("supertest");
|
||||
const app = require("../src/app");
|
||||
const prisma = require("../src/config/prisma");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
jest.mock("../src/config/mailer", () => ({ sendMail: jest.fn().mockResolvedValue(true) }));
|
||||
|
||||
const emails = { adm: "v-adm@test.local", emp: "v-emp@test.local", a: "v-a@test.local", b: "v-b@test.local" };
|
||||
const CODES = ["VERIFTICK1", "VERIFTICK2", "VERIFTICK3", "VERIFTICK4", "VERIFTICK5"];
|
||||
const DAY = 86400000;
|
||||
let ctx = {};
|
||||
const log = (...a) => console.log(" ", ...a);
|
||||
|
||||
async function cleanup() {
|
||||
const us = await prisma.user.findMany({ where: { email: { in: [...Object.values(emails), "v-r1@test.local", "v-r2@test.local"] } } });
|
||||
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: { in: CODES } } });
|
||||
await prisma.user.deleteMany({ where: { id: { in: ids } } });
|
||||
}
|
||||
|
||||
const setStart = (d) =>
|
||||
prisma.gameSettings.update({ where: { id: ctx.settings.id }, data: { startDate: new Date(Date.now() - d * DAY) } });
|
||||
|
||||
beforeAll(async () => {
|
||||
await cleanup();
|
||||
ctx.settings = await prisma.gameSettings.findFirst({ orderBy: { id: "asc" } });
|
||||
ctx.orig = ctx.settings.startDate;
|
||||
const lot = await prisma.lot.findFirst({ orderBy: { id: "asc" } });
|
||||
for (const c of CODES) await prisma.ticket.create({ data: { code: c, lotId: lot.id } });
|
||||
const h = await bcrypt.hash("Password123", 10);
|
||||
const mk = (e, r) => prisma.user.create({ data: { firstname: "V", lastname: r, email: e, password: h, role: r, isEmailVerified: true } });
|
||||
ctx.adm = await mk(emails.adm, "ADMIN");
|
||||
ctx.emp = await mk(emails.emp, "EMPLOYEE");
|
||||
ctx.a = await mk(emails.a, "CLIENT");
|
||||
ctx.b = await mk(emails.b, "CLIENT");
|
||||
const tk = (u) => jwt.sign({ id: u.id, role: u.role }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
||||
ctx.tadm = tk(ctx.adm);
|
||||
ctx.temp = tk(ctx.emp);
|
||||
ctx.ta = tk(ctx.a);
|
||||
ctx.tb = tk(ctx.b);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.gameSettings.update({ where: { id: ctx.settings.id }, data: { startDate: ctx.orig } });
|
||||
await cleanup();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
describe("VERIFICATION DES 7 CORRECTIFS", () => {
|
||||
test("#1 ADMIN peut lancer le jeu", async () => {
|
||||
const futur = new Date(Date.now() + 5 * DAY).toISOString();
|
||||
const r = await request(app).put("/api/admin/game-settings").set("Authorization", `Bearer ${ctx.tadm}`).send({ startDate: futur });
|
||||
log("PUT game-settings ->", r.status, r.body.message);
|
||||
expect(r.status).toBe(200);
|
||||
|
||||
const g = await request(app).get("/api/admin/game-settings").set("Authorization", `Bearer ${ctx.tadm}`).expect(200);
|
||||
log("GET game-settings -> participation ouverte :", g.body.gameWindow.isParticipationOpen, "(jeu pas encore commence)");
|
||||
|
||||
const bad = await request(app).put("/api/admin/game-settings").set("Authorization", `Bearer ${ctx.tadm}`).send({ startDate: "pas-une-date" });
|
||||
log("date invalide ->", bad.status, bad.body.message);
|
||||
expect(bad.status).toBe(400);
|
||||
|
||||
const nonAdmin = await request(app).put("/api/admin/game-settings").set("Authorization", `Bearer ${ctx.ta}`).send({ startDate: futur });
|
||||
log("client tente de lancer le jeu ->", nonAdmin.status);
|
||||
expect(nonAdmin.status).toBe(403);
|
||||
});
|
||||
|
||||
test("#2 participation refusee apres 30 jours", async () => {
|
||||
await setStart(45);
|
||||
const r = await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.ta}`).send({ code: CODES[0] });
|
||||
log("jour 45 ->", r.status, r.body.message);
|
||||
expect(r.status).toBe(410);
|
||||
|
||||
await setStart(1);
|
||||
const ok = await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.ta}`).send({ code: CODES[0] });
|
||||
log("jour 1 ->", ok.status, ok.body.message || "accepte");
|
||||
expect(ok.status).toBe(201);
|
||||
ctx.claimId = ok.body.claim.id;
|
||||
});
|
||||
|
||||
test("#3 expiration derivee et reversible", async () => {
|
||||
await setStart(70);
|
||||
const g1 = await request(app).get("/api/game/my-gains").set("Authorization", `Bearer ${ctx.ta}`).expect(200);
|
||||
log("jour 70, statut affiche :", g1.body.gains.map((g) => g.claimStatus).join(","));
|
||||
expect(g1.body.gains[0].claimStatus).toBe("CANCELLED");
|
||||
|
||||
const enBase = await prisma.claim.findUnique({ where: { id: ctx.claimId } });
|
||||
log("statut REEL en base :", enBase.status, "(non ecrase)");
|
||||
expect(enBase.status).toBe("PENDING");
|
||||
|
||||
await setStart(1);
|
||||
const g2 = await request(app).get("/api/game/my-gains").set("Authorization", `Bearer ${ctx.ta}`).expect(200);
|
||||
log("retour jour 1, statut :", g2.body.gains.map((g) => g.claimStatus).join(","), "(reversible)");
|
||||
expect(g2.body.gains[0].claimStatus).toBe("PENDING");
|
||||
});
|
||||
|
||||
test("#4 tirage refuse pendant le jeu", async () => {
|
||||
await setStart(1);
|
||||
const r = await request(app).post("/api/admin/draw").set("Authorization", `Bearer ${ctx.tadm}`);
|
||||
log("tirage pendant le jeu ->", r.status, r.body.message);
|
||||
expect(r.status).toBe(409);
|
||||
|
||||
await setStart(35);
|
||||
const r2 = await request(app).post("/api/admin/draw").set("Authorization", `Bearer ${ctx.tadm}`);
|
||||
log("tirage apres cloture ->", r2.status, r2.body.message, r2.body.totalEligibleParticipants ? `(${r2.body.totalEligibleParticipants} eligibles)` : "");
|
||||
expect(r2.status).toBe(201);
|
||||
|
||||
await prisma.grandPrizeWinner.deleteMany({ where: { userId: { in: [ctx.a.id, ctx.b.id] } } });
|
||||
await setStart(1);
|
||||
});
|
||||
|
||||
test("#5 admin et employe ne peuvent plus jouer", async () => {
|
||||
const r1 = await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.tadm}`).send({ code: CODES[1] });
|
||||
const r2 = await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.temp}`).send({ code: CODES[1] });
|
||||
log("ADMIN ->", r1.status, r1.body.message);
|
||||
log("EMPLOYE ->", r2.status, r2.body.message);
|
||||
expect(r1.status).toBe(403);
|
||||
expect(r2.status).toBe(403);
|
||||
|
||||
const t = await prisma.ticket.findUnique({ where: { code: CODES[1] } });
|
||||
log("le ticket reste vierge :", t.isUsed === false);
|
||||
expect(t.isUsed).toBe(false);
|
||||
});
|
||||
|
||||
test("#6 suppression de compte ne remet pas le ticket en jeu", async () => {
|
||||
await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.tb}`).send({ code: CODES[2] }).expect(201);
|
||||
await request(app).delete("/api/auth/account").set("Authorization", `Bearer ${ctx.tb}`).expect(200);
|
||||
|
||||
const t = await prisma.ticket.findUnique({ where: { code: CODES[2] } });
|
||||
log("apres suppression : isUsed =", t.isUsed, "| userId =", t.userId);
|
||||
expect(t.isUsed).toBe(true);
|
||||
|
||||
const rejoue = await request(app).post("/api/game/participate").set("Authorization", `Bearer ${ctx.ta}`).send({ code: CODES[2] });
|
||||
log("tentative de rejouer le code ->", rejoue.status, rejoue.body.message);
|
||||
expect(rejoue.status).toBe(409);
|
||||
});
|
||||
|
||||
test("#7 course sur un meme code", async () => {
|
||||
const h = await bcrypt.hash("Password123", 10);
|
||||
const c1 = await prisma.user.create({ data: { firstname: "R", lastname: "1", email: "v-r1@test.local", password: h, role: "CLIENT", isEmailVerified: true } });
|
||||
const c2 = await prisma.user.create({ data: { firstname: "R", lastname: "2", email: "v-r2@test.local", password: h, role: "CLIENT", isEmailVerified: true } });
|
||||
const t1 = jwt.sign({ id: c1.id, role: "CLIENT" }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
||||
const t2 = jwt.sign({ id: c2.id, role: "CLIENT" }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
||||
|
||||
const [r1, r2] = await Promise.all([
|
||||
request(app).post("/api/game/participate").set("Authorization", `Bearer ${t1}`).send({ code: CODES[3] }),
|
||||
request(app).post("/api/game/participate").set("Authorization", `Bearer ${t2}`).send({ code: CODES[3] }),
|
||||
]);
|
||||
|
||||
const codes = [r1.status, r2.status].sort();
|
||||
log("statuts obtenus :", codes.join(" + "), "(201 + 409 attendu, aucun 500)");
|
||||
expect(codes).toEqual([201, 409]);
|
||||
|
||||
const n = await prisma.participation.count({ where: { ticket: { code: CODES[3] } } });
|
||||
log("participations pour ce ticket :", n);
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
});
|
||||
145
backend/tests/gamePhases.test.js
Normal file
145
backend/tests/gamePhases.test.js
Normal file
@@ -0,0 +1,145 @@
|
||||
const request = require("supertest");
|
||||
const app = require("../src/app");
|
||||
const prisma = require("../src/config/prisma");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
jest.mock("../src/config/mailer", () => ({ sendMail: jest.fn().mockResolvedValue(true) }));
|
||||
|
||||
const DAY = 86400000;
|
||||
const PREFIX = "r2-";
|
||||
const CODES = ["R2TICKET01", "R2TICKET02", "R2TICKET03", "R2TICKET04"];
|
||||
let ctx = {};
|
||||
const log = (...a) => console.log(" ", ...a);
|
||||
const titre = (t) => console.log("\n===== " + t + " =====");
|
||||
|
||||
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: { in: CODES } } });
|
||||
await prisma.user.deleteMany({ where: { id: { in: ids } } });
|
||||
}
|
||||
|
||||
async function jourJ(offsetJours) {
|
||||
const row = await prisma.gameSettings.findFirst({ orderBy: { id: "asc" } });
|
||||
const debut = new Date(Date.now() - offsetJours * DAY);
|
||||
if (row) await prisma.gameSettings.update({ where: { id: row.id }, data: { startDate: debut } });
|
||||
else await prisma.gameSettings.create({ data: { startDate: debut } });
|
||||
}
|
||||
|
||||
const tk = (u) => jwt.sign({ id: u.id, role: u.role }, process.env.JWT_SECRET, { expiresIn: "2h" });
|
||||
|
||||
beforeAll(async () => {
|
||||
await cleanup();
|
||||
const row = await prisma.gameSettings.findFirst({ orderBy: { id: "asc" } });
|
||||
ctx.startDateOriginale = row ? row.startDate : null;
|
||||
|
||||
const lot = await prisma.lot.findFirst({ orderBy: { id: "asc" } });
|
||||
for (const c of CODES) await prisma.ticket.create({ data: { code: c, 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: "Zoe", lastname: "Cliente", email: PREFIX + "zoe@test.local", password: h, role: "CLIENT", isEmailVerified: true } });
|
||||
ctx.tAdmin = tk(ctx.admin);
|
||||
ctx.tClient = tk(ctx.client);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
const row = await prisma.gameSettings.findFirst({ orderBy: { id: "asc" } });
|
||||
if (ctx.startDateOriginale) {
|
||||
if (row) await prisma.gameSettings.update({ where: { id: row.id }, data: { startDate: ctx.startDateOriginale } });
|
||||
else await prisma.gameSettings.create({ data: { startDate: ctx.startDateOriginale } });
|
||||
}
|
||||
await cleanup();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
describe("VERIFICATION DES 3 CORRECTIFS DE PHASE", () => {
|
||||
|
||||
test("A. rien nest jouable avant tout lancement", async () => {
|
||||
titre("A : aucune GameSettings en base");
|
||||
await prisma.gameSettings.deleteMany({});
|
||||
|
||||
const vue = await request(app).get("/api/admin/game-settings").set("Authorization", "Bearer " + ctx.tAdmin).expect(200);
|
||||
log("phase :", vue.body.gameWindow.phase, "| participations ouvertes :", vue.body.gameWindow.isParticipationOpen);
|
||||
expect(vue.body.gameWindow.phase).toBe("NOT_CONFIGURED");
|
||||
|
||||
const essai = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[0] });
|
||||
log("un client tente de jouer ->", essai.status, essai.body.message);
|
||||
expect(essai.status).toBe(410);
|
||||
|
||||
const t = await prisma.ticket.findUnique({ where: { code: CODES[0] } });
|
||||
log("le ticket reste vierge :", t.isUsed === false);
|
||||
expect(t.isUsed).toBe(false);
|
||||
|
||||
const tirage = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin);
|
||||
log("admin tente le tirage ->", tirage.status, tirage.body.message);
|
||||
expect(tirage.status).toBe(409);
|
||||
expect(await prisma.grandPrizeWinner.count()).toBe(0);
|
||||
});
|
||||
|
||||
test("B. jeu programme : message juste et tirage bloque", async () => {
|
||||
titre("B : lancement programme a J+7");
|
||||
const futur = new Date(Date.now() + 7 * DAY).toISOString();
|
||||
const r = await request(app).put("/api/admin/game-settings").set("Authorization", "Bearer " + ctx.tAdmin).send({ startDate: futur });
|
||||
log("PUT game-settings ->", r.status, "| phase :", r.body.gameWindow.phase);
|
||||
expect(r.body.gameWindow.phase).toBe("SCHEDULED");
|
||||
|
||||
const anticipe = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[0] });
|
||||
log("client joue avant ouverture ->", anticipe.status);
|
||||
log("message :", JSON.stringify(anticipe.body.message));
|
||||
expect(anticipe.body.message).toMatch(/ouvrira le/);
|
||||
expect(anticipe.body.message).not.toMatch(/terminée/);
|
||||
|
||||
const tirage = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin);
|
||||
log("tirage avant ouverture ->", tirage.status, tirage.body.message);
|
||||
expect(tirage.status).toBe(409);
|
||||
expect(tirage.body.message).toMatch(/pas encore commencé/);
|
||||
});
|
||||
|
||||
test("C. les quatre phases dun jeu configure", async () => {
|
||||
titre("C : parcours des phases");
|
||||
|
||||
await jourJ(1);
|
||||
let w = (await request(app).get("/api/admin/game-settings").set("Authorization", "Bearer " + ctx.tAdmin)).body.gameWindow;
|
||||
const ok = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[0] });
|
||||
log("jour 1 | phase", w.phase, "| participate ->", ok.status);
|
||||
expect(w.phase).toBe("OPEN");
|
||||
expect(ok.status).toBe(201);
|
||||
ctx.claimId = ok.body.claim.id;
|
||||
|
||||
await jourJ(35);
|
||||
w = (await request(app).get("/api/admin/game-settings").set("Authorization", "Bearer " + ctx.tAdmin)).body.gameWindow;
|
||||
const tard = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[1] });
|
||||
log("jour 35 | phase", w.phase, "| participate ->", tard.status, JSON.stringify(tard.body.message));
|
||||
expect(w.phase).toBe("CLAIM_ONLY");
|
||||
expect(tard.body.message).toMatch(/participation est terminée/);
|
||||
|
||||
const tirage = await request(app).post("/api/admin/draw").set("Authorization", "Bearer " + ctx.tAdmin);
|
||||
log("tirage apres cloture ->", tirage.status, tirage.body.message);
|
||||
expect(tirage.status).toBe(201);
|
||||
|
||||
await jourJ(70);
|
||||
w = (await request(app).get("/api/admin/game-settings").set("Authorization", "Bearer " + ctx.tAdmin)).body.gameWindow;
|
||||
const fini = await request(app).post("/api/game/participate").set("Authorization", "Bearer " + ctx.tClient).send({ code: CODES[2] });
|
||||
log("jour 70 | phase", w.phase, "| participate ->", fini.status, JSON.stringify(fini.body.message));
|
||||
expect(w.phase).toBe("CLOSED");
|
||||
expect(fini.body.message).toMatch(/jeu-concours est terminé/);
|
||||
});
|
||||
|
||||
test("D. non-regression : le parcours nominal fonctionne toujours", async () => {
|
||||
titre("D : verification du parcours de base");
|
||||
await jourJ(2);
|
||||
const g = await request(app).get("/api/game/my-gains").set("Authorization", "Bearer " + ctx.tClient).expect(200);
|
||||
log("gains du client :", JSON.stringify(g.body.gains.map((x) => x.claimStatus)));
|
||||
expect(g.body.gains[0].claimStatus).toBe("PENDING");
|
||||
|
||||
const stats = await request(app).get("/api/admin/stats").set("Authorization", "Bearer " + ctx.tAdmin).expect(200);
|
||||
log("stats : phase =", stats.body.gameWindow.phase, "| participations =", stats.body.participations);
|
||||
expect(stats.body.gameWindow.phase).toBe("OPEN");
|
||||
});
|
||||
});
|
||||
66
backend/tests/register.mail.test.js
Normal file
66
backend/tests/register.mail.test.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const request = require("supertest");
|
||||
const app = require("../src/app");
|
||||
const prisma = require("../src/config/prisma");
|
||||
const mailer = require("../src/config/mailer");
|
||||
|
||||
jest.mock("../src/config/mailer", () => ({
|
||||
sendMail: jest.fn(),
|
||||
}));
|
||||
|
||||
// Comme le reste de la suite, ce fichier tourne sur la base de dev : il ne
|
||||
// touche qu'au compte qu'il crée lui-même, identifié par cet email.
|
||||
const testEmail = "rollback-mail-test@test.com";
|
||||
|
||||
const payload = {
|
||||
firstname: "Camille",
|
||||
lastname: "Martin",
|
||||
email: testEmail,
|
||||
password: "Password123",
|
||||
birthdate: "1990-05-14",
|
||||
gender: "Femme",
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
await prisma.user.deleteMany({ where: { email: testEmail } });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.user.deleteMany({ where: { email: testEmail } });
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
describe("Inscription - echec d'envoi du code de validation", () => {
|
||||
test("repond 502 et ne laisse aucun compte orphelin", async () => {
|
||||
mailer.sendMail.mockRejectedValue(new Error("SMTP indisponible"));
|
||||
|
||||
const res = await request(app).post("/api/auth/register").send(payload);
|
||||
|
||||
expect(res.statusCode).toBe(502);
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: testEmail } });
|
||||
expect(user).toBeNull();
|
||||
});
|
||||
|
||||
test("l'email reste reutilisable apres un echec d'envoi", async () => {
|
||||
mailer.sendMail.mockRejectedValueOnce(new Error("SMTP indisponible"));
|
||||
const echec = await request(app).post("/api/auth/register").send(payload);
|
||||
expect(echec.statusCode).toBe(502);
|
||||
|
||||
mailer.sendMail.mockResolvedValue(true);
|
||||
const succes = await request(app).post("/api/auth/register").send(payload);
|
||||
|
||||
expect(succes.statusCode).toBe(201);
|
||||
});
|
||||
|
||||
test("enregistre la date de naissance et le genre", async () => {
|
||||
mailer.sendMail.mockResolvedValue(true);
|
||||
|
||||
const res = await request(app).post("/api/auth/register").send(payload);
|
||||
expect(res.statusCode).toBe(201);
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: testEmail } });
|
||||
expect(user.gender).toBe("Femme");
|
||||
expect(user.birthdate.toISOString()).toBe("1990-05-14T00:00:00.000Z");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user