All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 12m35s
96 lines
4 KiB
TypeScript
96 lines
4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import express from "express";
|
|
import request from "supertest";
|
|
|
|
let app: express.Express;
|
|
|
|
beforeEach(async () => {
|
|
vi.clearAllMocks();
|
|
// resetModules to get fresh rate limiter instances
|
|
vi.resetModules();
|
|
|
|
// Re-import mocked services after resetModules
|
|
const { createPendingVerification, verifyCode } = await import("../services/verification.js");
|
|
const { sendVerificationEmail } = await import("../services/email.js");
|
|
const { getAllKeys } = await import("../services/keys.js");
|
|
|
|
vi.mocked(createPendingVerification).mockResolvedValue({ email: "test@test.com", code: "654321", createdAt: "", expiresAt: "", attempts: 0 });
|
|
vi.mocked(verifyCode).mockResolvedValue({ status: "ok" });
|
|
vi.mocked(sendVerificationEmail).mockResolvedValue(true);
|
|
vi.mocked(getAllKeys).mockReturnValue([
|
|
{ key: "existing-key", tier: "pro" as const, email: "found@test.com", createdAt: "2025-01-01" },
|
|
]);
|
|
|
|
const { recoverRouter } = await import("../routes/recover.js");
|
|
app = express();
|
|
app.use(express.json());
|
|
app.use("/recover", recoverRouter);
|
|
});
|
|
|
|
describe("POST /recover", () => {
|
|
it("returns 400 for missing email", async () => {
|
|
const res = await request(app).post("/recover").send({});
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it("returns 400 for invalid email", async () => {
|
|
const res = await request(app).post("/recover").send({ email: "bad" });
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it("returns 200 for email not found (anti-enumeration)", async () => {
|
|
const res = await request(app).post("/recover").send({ email: "nobody@test.com" });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.status).toBe("recovery_sent");
|
|
});
|
|
|
|
it("returns 200 and sends email for known email", async () => {
|
|
const { sendVerificationEmail } = await import("../services/email.js");
|
|
const res = await request(app).post("/recover").send({ email: "found@test.com" });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.status).toBe("recovery_sent");
|
|
await new Promise(r => setTimeout(r, 50));
|
|
expect(sendVerificationEmail).toHaveBeenCalledWith("found@test.com", "654321");
|
|
});
|
|
});
|
|
|
|
describe("POST /recover/verify", () => {
|
|
it("returns 400 for missing fields", async () => {
|
|
const res = await request(app).post("/recover/verify").send({ email: "a@b.com" });
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it("returns 410 for expired code", async () => {
|
|
const { verifyCode } = await import("../services/verification.js");
|
|
vi.mocked(verifyCode).mockResolvedValue({ status: "expired" });
|
|
const res = await request(app).post("/recover/verify").send({ email: "a@b.com", code: "123456" });
|
|
expect(res.status).toBe(410);
|
|
});
|
|
|
|
it("returns 429 for max attempts", async () => {
|
|
const { verifyCode } = await import("../services/verification.js");
|
|
vi.mocked(verifyCode).mockResolvedValue({ status: "max_attempts" });
|
|
const res = await request(app).post("/recover/verify").send({ email: "a@b.com", code: "123456" });
|
|
expect(res.status).toBe(429);
|
|
});
|
|
|
|
it("returns 400 for invalid code", async () => {
|
|
const { verifyCode } = await import("../services/verification.js");
|
|
vi.mocked(verifyCode).mockResolvedValue({ status: "invalid" });
|
|
const res = await request(app).post("/recover/verify").send({ email: "a@b.com", code: "999999" });
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it("returns 200 with apiKey when key found", async () => {
|
|
const res = await request(app).post("/recover/verify").send({ email: "found@test.com", code: "123456" });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body).toMatchObject({ status: "recovered", apiKey: "existing-key", tier: "pro" });
|
|
});
|
|
|
|
it("returns 200 with message only when no key found", async () => {
|
|
const res = await request(app).post("/recover/verify").send({ email: "nokey@test.com", code: "123456" });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.status).toBe("recovered");
|
|
expect(res.body.apiKey).toBeUndefined();
|
|
});
|
|
});
|