import { describe, it, expect, vi } from 'vitest'; import { createProjectsRepo } from './projects.js'; /** * Build a minimal Drizzle mock. Each call to db.select() returns a fresh * chain that resolves `where()` to the provided rows for that call. * * `calls` is an ordered list: the first item is returned for the first * db.select() call, the second for the second, and so on. */ function makeDb(calls: unknown[][]) { let callIndex = 0; const selectSpy = vi.fn(() => { const rows = calls[callIndex++] ?? []; const chain = { where: vi.fn().mockResolvedValue(rows), } as { where: ReturnType; from?: ReturnType }; // from() returns the chain so .where() can be chained, but also resolves // directly (as a thenable) for queries with no .where() call. chain.from = vi.fn(() => Object.assign(Promise.resolve(rows), chain)); return chain; }); return { select: selectSpy }; } describe('createProjectsRepo — findAllForUser', () => { it('filters by userId when user has no team memberships', async () => { // First select: teamMembers query → empty // Second select: projects query → one owned project const db = makeDb([ [], // teamMembers rows [{ id: 'p1', ownerId: 'user-1', teamId: null, ownerType: 'user' }], ]); const repo = createProjectsRepo(db as never); const result = await repo.findAllForUser('user-1'); expect(db.select).toHaveBeenCalledTimes(2); expect(result).toHaveLength(1); expect(result[0]?.id).toBe('p1'); }); it('includes team projects when user is a team member', async () => { // First select: teamMembers → user belongs to one team // Second select: projects query → two projects (own + team) const db = makeDb([ [{ teamId: 'team-1' }], [ { id: 'p1', ownerId: 'user-1', teamId: null, ownerType: 'user' }, { id: 'p2', ownerId: null, teamId: 'team-1', ownerType: 'team' }, ], ]); const repo = createProjectsRepo(db as never); const result = await repo.findAllForUser('user-1'); expect(db.select).toHaveBeenCalledTimes(2); expect(result).toHaveLength(2); }); it('returns empty array when user has no projects and no teams', async () => { const db = makeDb([[], []]); const repo = createProjectsRepo(db as never); const result = await repo.findAllForUser('user-no-projects'); expect(result).toHaveLength(0); }); }); describe('createProjectsRepo — findAll', () => { it('returns all rows without any user filter', async () => { const rows = [ { id: 'p1', ownerId: 'user-1', teamId: null, ownerType: 'user' }, { id: 'p2', ownerId: 'user-2', teamId: null, ownerType: 'user' }, ]; const db = makeDb([rows]); const repo = createProjectsRepo(db as never); const result = await repo.findAll(); expect(result).toHaveLength(2); }); });