/** * Unit tests for tournament update functionality * Tests the allowTies field is properly saved when updating tournaments */ import { describe, it, expect, mock, beforeEach, afterAll } from 'bun:test'; // Create mock functions at module level const eventFindUniqueMock = mock(async () => ({})); const eventUpdateMock = mock(async () => ({})); const canManageTournamentMock = mock(async () => ({ allowed: true })); const canDeleteTournamentMock = mock(async () => ({ allowed: true })); // Mock prisma first mock.module('@/lib/prisma', () => ({ prisma: { event: { findUnique: eventFindUniqueMock, update: eventUpdateMock, }, }, })); // Mock the permissions module mock.module('@/lib/permissions', () => ({ canManageTournament: canManageTournamentMock, canDeleteTournament: canDeleteTournamentMock, })); // Cleanup after all tests in this file afterAll(() => { mock.restore('module'); }); // Import the route handler after mocking import { PUT } from '@/app/api/tournaments/[id]/route'; import { prisma } from '@/lib/prisma'; describe('Tournament Update API', () => { beforeEach(() => { // Clear all mock history before each test eventFindUniqueMock.mockClear(); eventUpdateMock.mockClear(); canManageTournamentMock.mockClear(); canDeleteTournamentMock.mockClear(); }); it('should update allowTies field when provided', async () => { // Mock existing tournament eventFindUniqueMock.mockImplementation(async () => ({ id: 1, name: 'Test Tournament', allowTies: false, targetScore: 5, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); // Mock successful update eventUpdateMock.mockImplementation(async () => ({ id: 1, name: 'Test Tournament', allowTies: true, targetScore: 5, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); const request = new Request('http://localhost/api/tournaments/1', { method: 'PUT', body: JSON.stringify({ name: 'Test Tournament', allowTies: true, targetScore: 5, }), }); const params = Promise.resolve({ id: '1' }); const response = await PUT(request, { params }); expect(response.status).toBe(200); expect(prisma.event.update).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ allowTies: true, }), }) ); }); it('should NOT modify allowTies when not provided in request', async () => { // Mock existing tournament eventFindUniqueMock.mockImplementation(async () => ({ id: 1, name: 'Test Tournament', allowTies: true, // This is the current value targetScore: 5, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); // Mock successful update (allowTies should remain unchanged) eventUpdateMock.mockImplementation(async () => ({ id: 1, name: 'Test Tournament', allowTies: true, // Should remain true, not reset to false targetScore: 5, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); const request = new Request('http://localhost/api/tournaments/1', { method: 'PUT', body: JSON.stringify({ name: 'Test Tournament', targetScore: 5, // allowTies not provided - should NOT be modified }), }); const params = Promise.resolve({ id: '1' }); const response = await PUT(request, { params }); expect(response.status).toBe(200); // When allowTies is not provided, it should NOT be in the update data // (it will keep its existing value in the database) expect(eventUpdateMock.mock.calls.length).toBeGreaterThan(0); const updateCallArgs = (eventUpdateMock.mock.calls as any[][])[0]; expect(updateCallArgs).toBeDefined(); if (updateCallArgs && updateCallArgs[0]) { const updateData = updateCallArgs[0]; expect((updateData as any).data.allowTies).toBeUndefined(); expect((updateData as any).data.name).toBe('Test Tournament'); expect((updateData as any).data.targetScore).toBe(5); } }); it('should preserve allowTies value when updating other fields', async () => { // Mock existing tournament with allowTies = true eventFindUniqueMock.mockImplementation(async () => ({ id: 1, name: 'Test Tournament', allowTies: true, targetScore: 5, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); // Mock successful update eventUpdateMock.mockImplementation(async () => ({ id: 1, name: 'Updated Tournament Name', allowTies: true, targetScore: 10, eventType: 'tournament', format: 'round_robin', status: 'planned', eventDate: null, description: null, maxParticipants: null, ownerId: null, createdAt: new Date(), updatedAt: new Date(), } as any)); const request = new Request('http://localhost/api/tournaments/1', { method: 'PUT', body: JSON.stringify({ name: 'Updated Tournament Name', allowTies: true, targetScore: 10, }), }); const params = Promise.resolve({ id: '1' }); const response = await PUT(request, { params }); expect(response.status).toBe(200); const updateCallArgs = (eventUpdateMock.mock.calls as any[][])[0]; expect(updateCallArgs).toBeDefined(); if (updateCallArgs && updateCallArgs[0]) { const updateData = updateCallArgs[0]; expect((updateData as any).data.allowTies).toBe(true); expect((updateData as any).data.name).toBe('Updated Tournament Name'); expect((updateData as any).data.targetScore).toBe(10); } }); });