/** * Tests für getPendingSubmissions (Domain-Approval-Queue). * * Schwerpunkt: Sort-Order-Garantie + Deadline-Computation. * - Legend > Pro > Free Plan-Priority * - Innerhalb gleicher Priority: älteste createdAt zuerst (FIFO) * - deadlineAt = createdAt + 24h, msUntilDeadline negativ wenn überfällig */ import { describe, expect, it, vi, beforeEach } from "vitest"; const prismaMock = vi.hoisted(() => ({ domainSubmission: { findMany: vi.fn(), }, })); vi.mock("../../server/utils/prisma", () => ({ usePrisma: () => prismaMock, })); import { getPendingSubmissions, ADMIN_APPROVAL_SLA_MS, } from "../../server/db/domains"; beforeEach(() => { vi.clearAllMocks(); }); function makeRow(overrides: Partial> = {}) { return { id: "sub-id", domain: "example.com", type: "web", yesVotes: 0, noVotes: 0, status: "in_review", createdAt: new Date("2026-05-09T10:00:00Z"), userId: "user-id", postId: null, customDomain: { id: "cd-id" }, user: { id: "user-id", nickname: "nick", plan: "free" }, ...overrides, }; } describe("getPendingSubmissions — Plan-Priority + Deadline", () => { it("sortiert Legend vor Pro vor Free (Plan-Priority)", async () => { const sameTime = new Date("2026-05-09T10:00:00Z"); prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ id: "free-1", createdAt: sameTime, user: { id: "u1", nickname: "a", plan: "free" }, }), makeRow({ id: "legend-1", createdAt: sameTime, user: { id: "u2", nickname: "b", plan: "legend" }, }), makeRow({ id: "pro-1", createdAt: sameTime, user: { id: "u3", nickname: "c", plan: "pro" }, }), ]); const result = await getPendingSubmissions(); expect(result.map((r) => r.id)).toEqual(["legend-1", "pro-1", "free-1"]); }); it("innerhalb gleicher Plan-Priority: älteste zuerst (FIFO)", async () => { prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ id: "legend-newer", createdAt: new Date("2026-05-09T12:00:00Z"), user: { id: "u1", nickname: "x", plan: "legend" }, }), makeRow({ id: "legend-older", createdAt: new Date("2026-05-09T08:00:00Z"), user: { id: "u2", nickname: "y", plan: "legend" }, }), ]); const result = await getPendingSubmissions(); expect(result.map((r) => r.id)).toEqual(["legend-older", "legend-newer"]); }); it("berechnet deadlineAt = createdAt + 24h pro row", async () => { const created = new Date("2026-05-09T10:00:00Z"); prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ createdAt: created }), ]); const result = await getPendingSubmissions(); const expectedDeadline = new Date( created.getTime() + ADMIN_APPROVAL_SLA_MS, ); expect(result[0]!.deadlineAt.toISOString()).toBe( expectedDeadline.toISOString(), ); }); it("msUntilDeadline ist negativ wenn Submission überfällig (>24h alt)", async () => { // 30h alte Submission → 6h überfällig → ms negativ const created = new Date(Date.now() - 30 * 60 * 60 * 1000); prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ createdAt: created }), ]); const result = await getPendingSubmissions(); expect(result[0]!.msUntilDeadline).toBeLessThan(0); }); it("planPriority fällt auf 0 zurück wenn user.plan unbekannt / null", async () => { prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ user: null }), ]); const result = await getPendingSubmissions(); expect(result[0]!.planPriority).toBe(0); }); it("returned type='web' für Web-Submission", async () => { prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ id: "web-sub", domain: "casino.de", type: "web" }), ]); const result = await getPendingSubmissions(); expect(result[0]!.type).toBe("web"); }); it("returned type='mail_domain' für Mail-Submission", async () => { prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ id: "mail-sub", domain: "mailing.casino-affiliate.com", type: "mail_domain", }), ]); const result = await getPendingSubmissions(); expect(result[0]!.type).toBe("mail_domain"); }); it("type ist im Response-Objekt vorhanden (passthrough)", async () => { prismaMock.domainSubmission.findMany.mockResolvedValueOnce([ makeRow({ type: "mail_domain" }), ]); const result = await getPendingSubmissions(); expect(Object.prototype.hasOwnProperty.call(result[0], "type")).toBe(true); }); });