import { beforeEach, describe, expect, it } from 'vitest'; import { newClient } from '../helpers/api'; import { resetDatabase } from '../helpers/database'; import { createHunt, createTeam, createTeamMember, createUser, TEST_PASSWORD } from '../helpers/factories'; import { prisma } from './setup'; beforeEach(resetDatabase); describe('create team (POST /api/hunt/[huntId]/team)', () => { it('requires a session', async () => { const res = await newClient().post('/api/hunt/1/team', { name: 'The A-Team' }); expect(res.status).toBe(401); }); it('creates a team with a generated invite password', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); const owner = await createUser({ email: 'owner@test.dev' }); const client = newClient(); await client.login('owner@test.dev', TEST_PASSWORD); const res = await client.post(`/api/hunt/${hunt.id}/team`, { name: 'The A-Team', description: 'We love photos' }); expect(res.status).toBe(200); const body = await res.json(); expect(body.team).toMatchObject({ name: 'The A-Team', description: 'We love photos', ownerId: owner.id, huntId: hunt.id }); // short hex invite code expect(body.team.password).toMatch(/^[0-9a-f]{6}$/); expect(await prisma.huntTeam.count({ where: { huntId: hunt.id } })).toBe(1); }); it('enforces one team per user per hunt', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); await createUser({ email: 'owner@test.dev' }); const client = newClient(); await client.login('owner@test.dev', TEST_PASSWORD); expect( (await client.post(`/api/hunt/${hunt.id}/team`, { name: 'First' })).status ).toBe(200); // as owner of the first team expect( (await client.post(`/api/hunt/${hunt.id}/team`, { name: 'Second' })) .status ).toBe(409); // as member of an existing team const team = await createTeam(hunt.id, creator.id); const member = await createUser({ email: 'member@test.dev' }); await createTeamMember(team.id, member.id); const memberClient = newClient(); await memberClient.login('member@test.dev', TEST_PASSWORD); expect( (await memberClient.post(`/api/hunt/${hunt.id}/team`, { name: 'Third' })) .status ).toBe(409); }); it('rejects invalid team names with 400', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); const client = newClient(); await client.login(creator.email, TEST_PASSWORD); expect( (await client.post(`/api/hunt/${hunt.id}/team`, { name: 'ab' })).status ).toBe(400); }); }); describe('teams overview (GET /api/hunt/[huntId]/teams)', () => { it('returns teams with owner name and member count, sorted by name', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); const ownerA = await createUser({ name: 'Alice' }); const ownerB = await createUser({ name: 'Bob' }); const teamA = await createTeam(hunt.id, ownerA.id, { name: 'Alpha' }); await createTeam(hunt.id, ownerB.id, { name: 'Zebra' }); const joiner = await createUser(); await createTeamMember(teamA.id, joiner.id); const res = await newClient().get(`/api/hunt/${hunt.id}/teams`); expect(res.status).toBe(200); const teams = await res.json(); expect(teams).toEqual([ { id: teamA.id, name: 'Alpha', description: '', owner: { name: 'Alice' }, _count: { members: 1 } }, expect.objectContaining({ name: 'Zebra', owner: { name: 'Bob' }, _count: { members: 0 } }) ]); // the invite password must not leak here expect(JSON.stringify(teams)).not.toContain('password'); }); }); describe('join via team password (POST /api/hunt/[huntId]/join)', () => { it('lets a second user join an existing team', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); const owner = await createUser(); const team = await createTeam(hunt.id, owner.id, { password: 'feedbe' }); await createUser({ email: 'joiner@test.dev' }); const client = newClient(); await client.login('joiner@test.dev', TEST_PASSWORD); const res = await client.post(`/api/hunt/${hunt.id}/join`, { team: team.id, password: 'feedbe' }); expect(res.status).toBe(200); const teamsRes = await client.get(`/api/hunt/${hunt.id}/teams`); const teams = await teamsRes.json(); expect(teams[0]._count.members).toBe(1); }); });