Update features and dependencies
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
const mockSession = {
|
||||
user: { id: "user-1", name: "Test", email: "t@t.com", tier: "free" },
|
||||
};
|
||||
|
||||
const { mockRequireSession } = vi.hoisted(() => ({
|
||||
mockRequireSession: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/api-auth", () => ({
|
||||
requireSession: mockRequireSession,
|
||||
}));
|
||||
|
||||
vi.mock("@epicure/db", () => ({
|
||||
db: {
|
||||
delete: vi.fn(() => ({ where: vi.fn().mockResolvedValue(undefined) })),
|
||||
update: vi.fn(() => ({
|
||||
set: vi.fn(() => ({ where: vi.fn().mockResolvedValue(undefined) })),
|
||||
})),
|
||||
},
|
||||
recipes: { id: "id", authorId: "author_id", visibility: "visibility" },
|
||||
eq: vi.fn(),
|
||||
and: vi.fn(),
|
||||
inArray: vi.fn(),
|
||||
}));
|
||||
|
||||
import { DELETE, PATCH } from "../route";
|
||||
|
||||
function makeRequest(method: string, body: unknown) {
|
||||
return new NextRequest(`http://localhost/api/v1/recipes/bulk`, {
|
||||
method,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockRequireSession.mockResolvedValue({ session: mockSession, response: null });
|
||||
});
|
||||
|
||||
describe("DELETE /api/v1/recipes/bulk", () => {
|
||||
it("returns 200 on valid ids", async () => {
|
||||
const res = await DELETE(makeRequest("DELETE", { ids: ["r1", "r2"] }));
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json() as { ok: boolean };
|
||||
expect(body.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("returns 400 when ids is empty array", async () => {
|
||||
const res = await DELETE(makeRequest("DELETE", { ids: [] }));
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 400 when body is invalid", async () => {
|
||||
const res = await DELETE(makeRequest("DELETE", { notIds: "wrong" }));
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 401 when not authenticated", async () => {
|
||||
mockRequireSession.mockResolvedValue({
|
||||
session: null,
|
||||
response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 }),
|
||||
});
|
||||
const res = await DELETE(makeRequest("DELETE", { ids: ["r1"] }));
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PATCH /api/v1/recipes/bulk", () => {
|
||||
it("returns 200 on valid visibility update", async () => {
|
||||
const res = await PATCH(makeRequest("PATCH", { ids: ["r1"], visibility: "public" }));
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("returns 400 when visibility is missing", async () => {
|
||||
const res = await PATCH(makeRequest("PATCH", { ids: ["r1"] }));
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 400 when ids is empty", async () => {
|
||||
const res = await PATCH(makeRequest("PATCH", { ids: [], visibility: "public" }));
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 401 when not authenticated", async () => {
|
||||
mockRequireSession.mockResolvedValue({
|
||||
session: null,
|
||||
response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 }),
|
||||
});
|
||||
const res = await PATCH(makeRequest("PATCH", { ids: ["r1"], visibility: "public" }));
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
});
|
||||
@@ -13,22 +13,22 @@ const BulkUpdateSchema = z.object({
|
||||
});
|
||||
|
||||
export async function DELETE(req: NextRequest) {
|
||||
const session = await requireSession();
|
||||
if (session instanceof NextResponse) return session;
|
||||
const { session, response } = await requireSession();
|
||||
if (response) return response;
|
||||
|
||||
const body = BulkDeleteSchema.safeParse(await req.json());
|
||||
if (!body.success) return NextResponse.json({ error: "Invalid request" }, { status: 400 });
|
||||
|
||||
await db
|
||||
.delete(recipes)
|
||||
.where(and(inArray(recipes.id, body.data.ids), eq(recipes.authorId, session.user.id)));
|
||||
.where(and(inArray(recipes.id, body.data.ids), eq(recipes.authorId, session!.user.id)));
|
||||
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
export async function PATCH(req: NextRequest) {
|
||||
const session = await requireSession();
|
||||
if (session instanceof NextResponse) return session;
|
||||
const { session, response } = await requireSession();
|
||||
if (response) return response;
|
||||
|
||||
const body = BulkUpdateSchema.safeParse(await req.json());
|
||||
if (!body.success) return NextResponse.json({ error: "Invalid request" }, { status: 400 });
|
||||
@@ -39,7 +39,7 @@ export async function PATCH(req: NextRequest) {
|
||||
await db
|
||||
.update(recipes)
|
||||
.set({ visibility, updatedAt: new Date() })
|
||||
.where(and(inArray(recipes.id, ids), eq(recipes.authorId, session.user.id)));
|
||||
.where(and(inArray(recipes.id, ids), eq(recipes.authorId, session!.user.id)));
|
||||
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user