import { beforeEach, describe, expect, it } from 'vitest'; import { newClient } from '../helpers/api'; import { resetDatabase } from '../helpers/database'; import { createHunt, createHuntMember, createQuest, createTeam, createTeamMember, createUser, TEST_PASSWORD } from '../helpers/factories'; import { prisma } from './setup'; beforeEach(resetDatabase); describe('hunt listing (GET /api/home)', () => { it('lists only public, joinable hunts that have not started yet', async () => { const creator = await createUser(); await createHunt(creator.id, { allowJoin: true }); await createHunt(creator.id, { allowJoin: true, public: false }); await createHunt(creator.id, { allowJoin: false }); await createHunt(creator.id, { allowJoin: true, start: new Date('2020-01-01') }); await createHunt(creator.id, { allowJoin: true, start: new Date(Date.now() + 24 * 60 * 60 * 1000) }); await createHunt(creator.id, { allowJoin: true, deletedAt: new Date() }); const res = await newClient().get('/api/home'); expect(res.status).toBe(200); const body = await res.json(); expect(body.own).toBeNull(); // one hunt without start + one future hunt expect(body.others).toHaveLength(2); }); it('lists hunts the user participates in under own', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id, { allowJoin: true }); const player = await createUser({ email: 'player@test.dev' }); const team = await createTeam(hunt.id, creator.id); await createTeamMember(team.id, player.id); const client = newClient(); await client.login('player@test.dev', TEST_PASSWORD); const res = await client.get('/api/home'); const body = await res.json(); expect(body.own).toHaveLength(1); expect(body.own[0].id).toBe(hunt.id); // the hunt is excluded from others because the user already plays it expect(body.others).toHaveLength(0); }); }); describe('hunt detail (GET /api/hunt/[huntId])', () => { it('returns 404 for unknown hunts', async () => { const res = await newClient().get('/api/hunt/999999'); expect(res.status).toBe(404); }); it('hides quests from anonymous users when revealQuests is false', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); await createQuest(hunt.id); const res = await newClient().get(`/api/hunt/${hunt.id}`); expect(res.status).toBe(200); const body = await res.json(); expect(body.quests).toBeNull(); expect(body.isMember).toBe(false); expect(body.loggedIn).toBe(false); expect(body.ownTeam).toBeNull(); }); it('shows quests to hunt members even without revealQuests', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id); await createQuest(hunt.id); const member = await createUser({ email: 'member@test.dev' }); await createHuntMember(hunt.id, member.id); const client = newClient(); await client.login('member@test.dev', TEST_PASSWORD); const res = await client.get(`/api/hunt/${hunt.id}`); const body = await res.json(); expect(body.isMember).toBe(true); expect(body.quests).toHaveLength(1); }); it('exposes the own team to team owners', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id, { revealQuests: true }); const team = await createTeam(hunt.id, creator.id, { name: 'Owners' }); const client = newClient(); await client.login(creator.email, TEST_PASSWORD); const res = await client.get(`/api/hunt/${hunt.id}`); const body = await res.json(); expect(body.ownTeam).toMatchObject({ id: team.id, name: 'Owners' }); }); }); describe('join hunt (POST /api/hunt/[huntId]/join)', () => { it('requires a session', async () => { const res = await newClient().post('/api/hunt/1/join', { team: 1, password: 'x' }); expect(res.status).toBe(401); }); it('joins a team with the correct invite password', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id, { allowJoin: true }); const team = await createTeam(hunt.id, creator.id, { password: 'abc123' }); const player = 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: 'abc123' }); expect(res.status).toBe(200); expect(await res.json()).toEqual({ success: true }); expect( await prisma.teamMember.count({ where: { teamId: team.id, memberId: player.id } }) ).toBe(1); }); it('rejects wrong team or password with 404', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id, { allowJoin: true }); const team = await createTeam(hunt.id, creator.id, { password: 'abc123' }); await createUser({ email: 'joiner@test.dev' }); const client = newClient(); await client.login('joiner@test.dev', TEST_PASSWORD); expect( ( await client.post(`/api/hunt/${hunt.id}/join`, { team: team.id, password: 'wrong' }) ).status ).toBe(404); expect( ( await client.post(`/api/hunt/${hunt.id}/join`, { team: team.id + 999, password: 'abc123' }) ).status ).toBe(404); }); it('rejects joining twice with 409', async () => { const creator = await createUser(); const hunt = await createHunt(creator.id, { allowJoin: true }); const team = await createTeam(hunt.id, creator.id, { password: 'abc123' }); const player = await createUser({ email: 'joiner@test.dev' }); await createTeamMember(team.id, player.id); 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: 'abc123' }); expect(res.status).toBe(409); }); });