kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 130 lines 3.7 kB view raw
1import { eq } from "drizzle-orm"; 2import { beforeEach, describe, expect, it } from "vitest"; 3import db, { schema } from "../../apps/api/src/database"; 4import { createApp } from "../../apps/api/src/index"; 5import { mockAnonymousSession, mockAuthenticatedSession } from "./helpers/auth"; 6import { resetTestDatabase } from "./helpers/database"; 7import { createWorkspaceMember } from "./helpers/fixtures"; 8 9describe("API integration: project creation", () => { 10 beforeEach(async () => { 11 await resetTestDatabase(); 12 }); 13 14 it("rejects unauthenticated project creation requests", async () => { 15 mockAnonymousSession(); 16 const { app } = createApp(); 17 18 const response = await app.request("/api/project", { 19 method: "POST", 20 headers: { 21 "content-type": "application/json", 22 }, 23 body: JSON.stringify({ 24 workspaceId: "workspace-missing", 25 name: "Unauthorized Project", 26 icon: "Folder", 27 slug: "unauthorized-project", 28 }), 29 }); 30 31 expect(response.status).toBe(401); 32 await expect(response.text()).resolves.toBe("Unauthorized"); 33 }); 34 35 it("creates a project for a workspace member and seeds default columns", async () => { 36 const member = await createWorkspaceMember(); 37 mockAuthenticatedSession(member.user); 38 const { app } = createApp(); 39 40 const response = await app.request("/api/project", { 41 method: "POST", 42 headers: { 43 "content-type": "application/json", 44 }, 45 body: JSON.stringify({ 46 workspaceId: member.workspace.id, 47 name: "Roadmap", 48 icon: "FolderKanban", 49 slug: "roadmap", 50 }), 51 }); 52 53 expect(response.status).toBe(200); 54 const payload = 55 (await response.json()) as typeof schema.projectTable.$inferSelect; 56 57 expect(payload).toMatchObject({ 58 workspaceId: member.workspace.id, 59 name: "Roadmap", 60 icon: "FolderKanban", 61 slug: "roadmap", 62 }); 63 64 const persistedProject = await db.query.projectTable.findFirst({ 65 where: eq(schema.projectTable.id, payload.id), 66 }); 67 68 expect(persistedProject).toMatchObject({ 69 id: payload.id, 70 workspaceId: member.workspace.id, 71 name: "Roadmap", 72 slug: "roadmap", 73 }); 74 75 const columns = await db.query.columnTable.findMany({ 76 where: eq(schema.columnTable.projectId, payload.id), 77 orderBy: (column, { asc }) => [asc(column.position)], 78 }); 79 80 expect(columns).toHaveLength(4); 81 expect(columns.map((column) => column.slug)).toEqual([ 82 "to-do", 83 "in-progress", 84 "in-review", 85 "done", 86 ]); 87 expect(columns.map((column) => column.isFinal)).toEqual([ 88 false, 89 false, 90 false, 91 true, 92 ]); 93 }); 94 95 it("rejects project creation for users outside the workspace", async () => { 96 const member = await createWorkspaceMember(); 97 const outsiderId = "user-outsider"; 98 99 const [outsider] = await db 100 .insert(schema.userTable) 101 .values({ 102 id: outsiderId, 103 email: `${outsiderId}@example.com`, 104 emailVerified: true, 105 name: "Outsider", 106 }) 107 .returning(); 108 109 mockAuthenticatedSession(outsider); 110 const { app } = createApp(); 111 112 const response = await app.request("/api/project", { 113 method: "POST", 114 headers: { 115 "content-type": "application/json", 116 }, 117 body: JSON.stringify({ 118 workspaceId: member.workspace.id, 119 name: "Forbidden Project", 120 icon: "Folder", 121 slug: "forbidden-project", 122 }), 123 }); 124 125 expect(response.status).toBe(403); 126 await expect(response.text()).resolves.toBe( 127 "You don't have access to this workspace", 128 ); 129 }); 130});