import { beforeEach, describe, expect, it, mock, vi } from 'bun:test'; import { Hono } from 'hono'; const db = { group: { findMany: mock(), count: mock(), create: mock(), }, groupMember: { create: mock(), }, merchantAccount: { findUnique: mock(), }, }; mock.module('@/lib/prisma', () => ({ default: db, getPrismaClient: mock(), UnitOfWork: class { executeResult = mock(async (cb: (tx: unknown) => Promise) => cb(db)); execute = mock(async (cb: (tx: unknown) => Promise) => cb(db)); }, })); import prisma from '@/lib/prisma'; import { groupsRoutes } from '@/modules/groups'; const userId = 'user-1'; const group = { id: 'group-1', name: 'Cuadrilla Alfa', description: null, createdById: userId, createdAt: new Date('2026-08-01T10:00:00.000Z'), updatedAt: new Date('2026-08-01T10:00:00.000Z'), days: null, time: null, capacity: null, price: null, billingType: null, dueDay: null, inviteToken: null, }; function makeApp(userValue: unknown) { const app = new Hono(); app.use('*', async (c, next) => { c.set('user', userValue as never); await next(); }); app.route('/groups', groupsRoutes); return app; } describe('groups routes', () => { beforeEach(() => { vi.clearAllMocks(); }); it('lists groups scoped to the current user', async () => { prisma.group.findMany.mockResolvedValue([group]); prisma.group.count.mockResolvedValue(1); const res = await makeApp({ id: userId }).request('/groups'); expect(res.status).toBe(200); expect(await res.json()).toEqual({ data: [ { ...group, createdAt: group.createdAt.toISOString(), updatedAt: group.updatedAt.toISOString(), }, ], pagination: { page: 1, pageSize: 10, total: 1, totalPages: 1 }, }); const where = { OR: [{ createdById: userId }, { members: { some: { userId } } }], }; expect(prisma.group.findMany).toHaveBeenCalledWith({ where, skip: 0, take: 10, orderBy: { createdAt: 'desc' }, }); expect(prisma.group.count).toHaveBeenCalledWith({ where }); }); it('rejects listing groups without a session', async () => { const res = await makeApp(null).request('/groups'); expect(res.status).toBe(401); expect(await res.json()).toMatchObject({ code: 'unauthorized' }); }); it('rejects invalid pagination query parameters', async () => { const res = await makeApp({ id: userId }).request('/groups?pageSize=101'); expect(res.status).toBe(400); }); it('creates a group with billing configuration', async () => { prisma.merchantAccount.findUnique.mockResolvedValue({ id: 'merchant-1', userId }); prisma.group.create.mockResolvedValue({ ...group, days: ['MONDAY'], time: '09:00', capacity: 20, price: 500, billingType: 'MONTHLY', dueDay: 5, }); const res = await makeApp({ id: userId }).request('/groups', { method: 'POST', body: JSON.stringify({ name: 'Cuadrilla Alfa', days: ['MONDAY'], time: '09:00', capacity: 20, price: 500, billingType: 'MONTHLY', dueDay: 5, }), headers: { 'Content-Type': 'application/json' }, }); expect(res.status).toBe(201); expect(await res.json()).toEqual({ group: { ...group, days: ['MONDAY'], time: '09:00', capacity: 20, price: 500, billingType: 'MONTHLY', dueDay: 5, createdAt: group.createdAt.toISOString(), updatedAt: group.updatedAt.toISOString(), }, }); expect(prisma.group.create).toHaveBeenCalledWith({ data: { name: 'Cuadrilla Alfa', createdById: userId, days: ['MONDAY'], time: '09:00', capacity: 20, price: 500, billingType: 'MONTHLY', dueDay: 5, }, }); expect(prisma.groupMember.create).toHaveBeenCalledWith({ data: { groupId: 'group-1', userId, role: 'OWNER' }, }); }); it('rejects creating a group without a linked merchant account', async () => { prisma.merchantAccount.findUnique.mockResolvedValue(null); const res = await makeApp({ id: userId }).request('/groups', { method: 'POST', body: JSON.stringify({ name: 'Cuadrilla Alfa', days: ['MONDAY'], time: '09:00', capacity: 20, price: 500, billingType: 'MONTHLY', dueDay: 5, }), headers: { 'Content-Type': 'application/json' }, }); expect(res.status).toBe(409); expect(await res.json()).toMatchObject({ code: 'payment_not_setup' }); expect(prisma.group.create).not.toHaveBeenCalled(); }); it('rejects creating a group with an invalid payload', async () => { const res = await makeApp({ id: userId }).request('/groups', { method: 'POST', body: JSON.stringify({ name: 'x' }), headers: { 'Content-Type': 'application/json' }, }); expect(res.status).toBe(400); expect(prisma.group.create).not.toHaveBeenCalled(); }); });