마이페이지, 리포트, 메일인증
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
import "dotenv/config";
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
|
||||
import { signAccessToken } from "@/features/auth/authCrypto";
|
||||
|
||||
const BASE_URL = "http://localhost";
|
||||
|
||||
// in-memory Prisma 목 데이터
|
||||
const inMemoryProjects: any[] = [];
|
||||
const inMemorySubmissions: any[] = [];
|
||||
|
||||
vi.mock("@prisma/client", () => {
|
||||
class PrismaClientMock {
|
||||
project = {
|
||||
findMany: async ({ where }: any) => {
|
||||
if (!where || !where.userId) return [];
|
||||
return inMemoryProjects.filter((p) => p.userId === where.userId);
|
||||
},
|
||||
};
|
||||
|
||||
formSubmission = {
|
||||
findMany: async ({ where }: any) => {
|
||||
if (!where || !where.userId) return [];
|
||||
return inMemorySubmissions.filter((s) => s.userId === where.userId);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return { PrismaClient: PrismaClientMock };
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
inMemoryProjects.length = 0;
|
||||
inMemorySubmissions.length = 0;
|
||||
process.env.AUTH_JWT_SECRET = "test-jwt-secret-reports-leads";
|
||||
process.env.AUTH_ENCRYPTION_KEY = "0123456789abcdef0123456789abcdef";
|
||||
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2025-01-10T00:00:00.000Z"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
describe("/api/reports/leads", () => {
|
||||
it("range=all 에서 필터된 모든 리드를 최신순으로 반환해야 한다", async () => {
|
||||
const { GET: leads } = await import("@/app/api/reports/leads/route");
|
||||
|
||||
const userId = "user-reports-leads-all";
|
||||
|
||||
inMemoryProjects.push(
|
||||
{ id: "p1", userId, title: "Project A", slug: "project-a" },
|
||||
{ id: "p2", userId, title: "Project B", slug: "project-b" },
|
||||
);
|
||||
|
||||
inMemorySubmissions.push(
|
||||
{
|
||||
id: "s1",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-09T12:00:00.000Z"),
|
||||
payloadJson: { name: "Alice" },
|
||||
},
|
||||
{
|
||||
id: "s2",
|
||||
userId,
|
||||
projectId: "p2",
|
||||
projectSlug: "project-b",
|
||||
createdAt: new Date("2025-01-08T09:00:00.000Z"),
|
||||
payloadJson: { email: "bob@example.com" },
|
||||
},
|
||||
{
|
||||
id: "s3",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-10T00:00:00.000Z"),
|
||||
payloadJson: { phone: "010-0000-0000" },
|
||||
},
|
||||
);
|
||||
|
||||
const token = await signAccessToken({
|
||||
id: userId,
|
||||
email: "reports-leads@example.com",
|
||||
tokenVersion: 1,
|
||||
emailVerified: true,
|
||||
} as any);
|
||||
|
||||
const res = await leads(
|
||||
new Request(`${BASE_URL}/api/reports/leads?range=all`, {
|
||||
headers: { cookie: `pb_access=${token}` },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const json = (await res.json()) as any;
|
||||
|
||||
expect(json.total).toBe(3);
|
||||
expect(Array.isArray(json.items)).toBe(true);
|
||||
expect(json.items.length).toBe(3);
|
||||
|
||||
// 최신순 정렬: createdAt 이 가장 최근인 s3 가 첫 번째여야 한다.
|
||||
expect(json.items[0].id).toBe("s3");
|
||||
expect(json.items[1].id).toBe("s1");
|
||||
expect(json.items[2].id).toBe("s2");
|
||||
|
||||
const first = json.items[0];
|
||||
expect(first.projectSlug).toBe("project-a");
|
||||
expect(first.projectTitle).toBe("Project A");
|
||||
expect(first.payload).toEqual({ phone: "010-0000-0000" });
|
||||
});
|
||||
|
||||
it("range=7d 와 projectId 가 적용되면 해당 조건에 맞는 리드만 반환해야 한다", async () => {
|
||||
const { GET: leads } = await import("@/app/api/reports/leads/route");
|
||||
|
||||
const userId = "user-reports-leads-filter";
|
||||
|
||||
inMemoryProjects.push({ id: "p1", userId, title: "Project A", slug: "project-a" });
|
||||
|
||||
// 기준 시간: 2025-01-10
|
||||
inMemorySubmissions.push(
|
||||
{
|
||||
id: "s1",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-09T12:00:00.000Z"), // within 7d
|
||||
payloadJson: { name: "Alice" },
|
||||
},
|
||||
{
|
||||
id: "s2",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-01T12:00:00.000Z"), // older than 7d
|
||||
payloadJson: { name: "Old" },
|
||||
},
|
||||
);
|
||||
|
||||
const token = await signAccessToken({
|
||||
id: userId,
|
||||
email: "reports-leads-filter@example.com",
|
||||
tokenVersion: 1,
|
||||
emailVerified: true,
|
||||
} as any);
|
||||
|
||||
const res = await leads(
|
||||
new Request(`${BASE_URL}/api/reports/leads?range=7d&projectId=p1`, {
|
||||
headers: { cookie: `pb_access=${token}` },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const json = (await res.json()) as any;
|
||||
|
||||
expect(json.total).toBe(1);
|
||||
expect(json.items.length).toBe(1);
|
||||
expect(json.items[0].id).toBe("s1");
|
||||
});
|
||||
|
||||
it("from/to 쿼리로 커스텀 기간의 리드만 반환해야 한다", async () => {
|
||||
const { GET: leads } = await import("@/app/api/reports/leads/route");
|
||||
|
||||
const userId = "user-reports-leads-from-to";
|
||||
|
||||
inMemoryProjects.push({ id: "p1", userId, title: "Project A", slug: "project-a" });
|
||||
|
||||
inMemorySubmissions.push(
|
||||
{
|
||||
id: "s1",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-01T12:00:00.000Z"),
|
||||
payloadJson: { label: "old" },
|
||||
},
|
||||
{
|
||||
id: "s2",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-05T12:00:00.000Z"),
|
||||
payloadJson: { label: "mid" },
|
||||
},
|
||||
{
|
||||
id: "s3",
|
||||
userId,
|
||||
projectId: "p1",
|
||||
projectSlug: "project-a",
|
||||
createdAt: new Date("2025-01-09T12:00:00.000Z"),
|
||||
payloadJson: { label: "new" },
|
||||
},
|
||||
);
|
||||
|
||||
const token = await signAccessToken({
|
||||
id: userId,
|
||||
email: "reports-leads-from-to@example.com",
|
||||
tokenVersion: 1,
|
||||
emailVerified: true,
|
||||
} as any);
|
||||
|
||||
const res = await leads(
|
||||
new Request(`${BASE_URL}/api/reports/leads?from=2025-01-02&to=2025-01-08`, {
|
||||
headers: { cookie: `pb_access=${token}` },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const json = (await res.json()) as any;
|
||||
|
||||
expect(json.total).toBe(1);
|
||||
expect(json.items.length).toBe(1);
|
||||
expect(json.items[0].id).toBe("s2");
|
||||
});
|
||||
|
||||
it("JWT 가 없으면 401 을 반환해야 한다", async () => {
|
||||
const { GET: leads } = await import("@/app/api/reports/leads/route");
|
||||
|
||||
const res = await leads(new Request(`${BASE_URL}/api/reports/leads?range=all`));
|
||||
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user