/** @jest-environment node */ import { makeZodVerifiedAPICall, makeAPICall, pruneDatabase, } from "@/src/__tests__/test-utils"; import { prisma } from "@langfuse/shared/src/db"; import { createOrgProjectAndApiKey } from "@langfuse/shared/src/server"; import { v4 as uuidv4 } from "uuid"; import { CreateAnnotationQueueAssignmentResponse, DeleteAnnotationQueueAssignmentResponse, } from "@/src/features/public-api/types/annotation-queues"; describe("/api/public/annotation-queues/:queueId/assignments API", () => { let auth: string; let projectId: string; let orgId: string; let queueId: string; let testUserId: string; let secondTestUserId: string; beforeAll(async () => { const { auth: newAuth, projectId: newProjectId, orgId: newOrgId, } = await createOrgProjectAndApiKey(); auth = newAuth; projectId = newProjectId; orgId = newOrgId; // Create a test annotation queue const queue = await prisma.annotationQueue.create({ data: { id: uuidv4(), name: "Test Queue for Assignments", description: "Test queue for assignment testing", projectId, scoreConfigIds: [], }, }); queueId = queue.id; // Create test users with project access const testUser = await prisma.user.create({ data: { id: uuidv4(), email: `testuser1-${uuidv4()}@example.com`, name: "Test User 1", }, }); testUserId = testUser.id; const secondTestUser = await prisma.user.create({ data: { id: uuidv4(), email: `testuser2-${uuidv4()}@example.com`, name: "Test User 2", }, }); secondTestUserId = secondTestUser.id; // Give users project access - need to create org memberships first await prisma.organizationMembership.createMany({ data: [ { orgId, userId: testUserId, role: "MEMBER", }, { orgId, userId: secondTestUserId, role: "MEMBER", }, ], }); // Get the org membership IDs and create project memberships const orgMembership1 = await prisma.organizationMembership.findFirst({ where: { orgId, userId: testUserId }, }); const orgMembership2 = await prisma.organizationMembership.findFirst({ where: { orgId, userId: secondTestUserId }, }); await prisma.projectMembership.createMany({ data: [ { projectId, userId: testUserId, role: "MEMBER", orgMembershipId: orgMembership1!.id, }, { projectId, userId: secondTestUserId, role: "MEMBER", orgMembershipId: orgMembership2!.id, }, ], }); }); afterAll(async () => { await pruneDatabase(); }); describe("POST /api/public/annotation-queues/:queueId/assignments", () => { it("should create annotation queue assignment successfully", async () => { const response = await makeZodVerifiedAPICall( CreateAnnotationQueueAssignmentResponse, "POST", `/api/public/annotation-queues/${queueId}/assignments`, { userId: testUserId, }, auth, ); expect(response.status).toBe(200); expect(response.body.userId).toBe(testUserId); expect(response.body.projectId).toBe(projectId); expect(response.body.queueId).toBe(queueId); // Verify the membership was created in the database const assignment = await prisma.annotationQueueAssignment.findUnique({ where: { projectId_queueId_userId: { projectId, queueId, userId: testUserId, }, }, }); expect(assignment).toBeTruthy(); expect(assignment?.userId).toBe(testUserId); expect(assignment?.projectId).toBe(projectId); expect(assignment?.queueId).toBe(queueId); }); it("should handle duplicate assignment creation gracefully", async () => { // Create assignment first time await makeZodVerifiedAPICall( CreateAnnotationQueueAssignmentResponse, "POST", `/api/public/annotation-queues/${queueId}/assignments`, { userId: secondTestUserId, }, auth, ); // Create same assignment again - should succeed (upsert behavior) const response = await makeZodVerifiedAPICall( CreateAnnotationQueueAssignmentResponse, "POST", `/api/public/annotation-queues/${queueId}/assignments`, { userId: secondTestUserId, }, auth, ); expect(response.status).toBe(200); expect(response.body.userId).toBe(secondTestUserId); // Verify only one assignment exists const assignments = await prisma.annotationQueueAssignment.findMany({ where: { projectId, queueId, userId: secondTestUserId, }, }); expect(assignments).toHaveLength(1); }); it("should return 404 for non-existent annotation queue", async () => { const nonExistentQueueId = uuidv4(); const response = await makeAPICall( "POST", `/api/public/annotation-queues/${nonExistentQueueId}/assignments`, { userId: testUserId, }, auth, ); expect(response.status).toBe(404); }); it("should return 404 for non-existent user", async () => { const nonExistentUserId = uuidv4(); const response = await makeAPICall( "POST", `/api/public/annotation-queues/${queueId}/assignments`, { userId: nonExistentUserId, }, auth, ); expect(response.status).toBe(404); }); it("should return 404 for user without project access", async () => { // Create a user without project access const userWithoutAccess = await prisma.user.create({ data: { id: uuidv4(), email: `noaccess-${uuidv4()}@example.com`, name: "No Access User", }, }); const response = await makeAPICall( "POST", `/api/public/annotation-queues/${queueId}/assignments`, { userId: userWithoutAccess.id, }, auth, ); expect(response.status).toBe(404); }); it("should validate request body", async () => { // Missing userId const response = await makeAPICall( "POST", `/api/public/annotation-queues/${queueId}/assignments`, {}, auth, ); expect(response.status).toBe(400); }); it("should require valid queueId format", async () => { const response = await makeAPICall( "POST", `/api/public/annotation-queues/invalid-queue-id/assignments`, { userId: testUserId, }, auth, ); expect(response.status).toBe(404); }); }); describe("DELETE /api/public/annotation-queues/:queueId/assignments", () => { beforeEach(async () => { // Ensure assignment exists for delete tests await prisma.annotationQueueAssignment.upsert({ where: { projectId_queueId_userId: { projectId, queueId, userId: testUserId, }, }, create: { projectId, queueId, userId: testUserId, }, update: {}, }); }); it("should delete annotation queue membership successfully", async () => { const response = await makeZodVerifiedAPICall( DeleteAnnotationQueueAssignmentResponse, "DELETE", `/api/public/annotation-queues/${queueId}/assignments`, { userId: testUserId, }, auth, ); expect(response.status).toBe(200); expect(response.body.success).toBe(true); // Verify the membership was deleted from the database const assignment = await prisma.annotationQueueAssignment.findUnique({ where: { projectId_queueId_userId: { projectId, queueId, userId: testUserId, }, }, }); expect(assignment).toBeNull(); }); it("should handle deletion of non-existent assignment gracefully", async () => { // Delete a assignment that doesn't exist const nonExistentUserId = uuidv4(); const response = await makeZodVerifiedAPICall( DeleteAnnotationQueueAssignmentResponse, "DELETE", `/api/public/annotation-queues/${queueId}/assignments`, { userId: nonExistentUserId, }, auth, ); expect(response.status).toBe(200); expect(response.body.success).toBe(true); }); it("should return 404 for non-existent annotation queue", async () => { const nonExistentQueueId = uuidv4(); const response = await makeAPICall( "DELETE", `/api/public/annotation-queues/${nonExistentQueueId}/assignments`, { userId: testUserId, }, auth, ); expect(response.status).toBe(404); }); }); });