import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { WatchListService } from "../src/watchlist/WatchListService"; import prisma from "@shieldai/db"; import { IdentifierType } from "@shieldai/types"; let runId = Date.now(); describe("WatchListService", () => { let service: WatchListService; let userId: string; beforeEach(async () => { runId = Date.now(); service = new WatchListService(); const user = await prisma.user.create({ data: { email: `test-${runId}@shieldai.local`, name: "Test User", subscriptionTier: "PREMIUM", }, }); userId = user.id; }); afterEach(async () => { await prisma.watchListItem.deleteMany({ where: { userId } }); await prisma.user.delete({ where: { id: userId } }); }); it("adds an email identifier", async () => { const item = await service.addItem(userId, IdentifierType.EMAIL, `test-${runId}@example.com`); expect(item.identifierValue).toBe(`test-${runId}@example.com`); expect(item.identifierType).toBe(IdentifierType.EMAIL); expect(item.identifierHash).toHaveLength(64); }); it("adds a phone identifier", async () => { const digits = String(runId).padStart(10, "0").slice(-10); const phone = `${digits.slice(0,3)}-${digits.slice(3,7)}-${digits.slice(7)}`; const item = await service.addItem(userId, IdentifierType.PHONE, phone); expect(item.identifierType).toBe(IdentifierType.PHONE); expect(item.identifierValue).toMatch(/^\+1\d{10}$/); }); it("deduplicates by hash", async () => { await service.addItem(userId, IdentifierType.EMAIL, `dedup-${runId}@example.com`); const duplicate = service.addItem(userId, IdentifierType.EMAIL, `DEDUP-${runId}@EXAMPLE.COM`); await expect(duplicate).rejects.toThrow("Identifier already watched"); }); it("lists items", async () => { await service.addItem(userId, IdentifierType.EMAIL, `list-a-${runId}@example.com`); await service.addItem(userId, IdentifierType.EMAIL, `list-b-${runId}@example.com`); const items = await service.listItems(userId); expect(items).toHaveLength(2); }); it("removes an item", async () => { const item = await service.addItem(userId, IdentifierType.EMAIL, `remove-${runId}@example.com`); const result = await service.removeItem(userId, item.id); expect(result.count).toBe(1); const remaining = await service.listItems(userId); expect(remaining).toHaveLength(0); }); it("enforces BASIC tier limit", async () => { const basicUser = await prisma.user.update({ where: { id: userId }, data: { subscriptionTier: "BASIC" }, }); await service.addItem(basicUser.id, IdentifierType.EMAIL, `basic-1-${runId}@example.com`); await service.addItem(basicUser.id, IdentifierType.EMAIL, `basic-2-${runId}@example.com`); const third = service.addItem(basicUser.id, IdentifierType.EMAIL, `basic-3-${runId}@example.com`); await expect(third).rejects.toThrow("Watch list limit reached"); }); });