Fix: allowTies not saved when editing tournaments (closes #6) #12
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* E2E Test: Tournament Edit with allowTies
|
||||||
|
*
|
||||||
|
* User Story: As a tournament admin, I want to edit tournament settings including allowTies
|
||||||
|
*
|
||||||
|
* Acceptance Criteria:
|
||||||
|
* - Can edit tournament settings
|
||||||
|
* - allowTies checkbox can be toggled
|
||||||
|
* - allowTies value is saved correctly
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import { prisma } from '@/lib/prisma';
|
||||||
|
|
||||||
|
test.describe('Tournament Edit - allowTies functionality', () => {
|
||||||
|
let tournamentId: number;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
// Create a test tournament for editing
|
||||||
|
const tournament = await prisma.event.create({
|
||||||
|
data: {
|
||||||
|
name: 'Test Tournament for AllowTies Edit',
|
||||||
|
eventType: 'tournament',
|
||||||
|
format: 'round_robin',
|
||||||
|
status: 'planned',
|
||||||
|
allowTies: false,
|
||||||
|
targetScore: 5,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
tournamentId = tournament.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
// Clean up test tournament
|
||||||
|
if (tournamentId) {
|
||||||
|
await prisma.event.delete({
|
||||||
|
where: { id: tournamentId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should display allowTies checkbox on edit form', async ({ page }) => {
|
||||||
|
// Navigate to tournament edit page
|
||||||
|
await page.goto(`/admin/tournaments/${tournamentId}/edit`);
|
||||||
|
|
||||||
|
// Wait for form to load
|
||||||
|
await expect(page.locator('text=Tournament Name')).toBeVisible();
|
||||||
|
|
||||||
|
// Check that allowTies checkbox exists
|
||||||
|
const allowTiesCheckbox = page.locator('input[name="allowTies"]');
|
||||||
|
await expect(allowTiesCheckbox).toBeVisible();
|
||||||
|
await expect(allowTiesCheckbox).not.toBeChecked();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should save allowTies when toggled to true', async ({ page }) => {
|
||||||
|
// Navigate to tournament edit page
|
||||||
|
await page.goto(`/admin/tournaments/${tournamentId}/edit`);
|
||||||
|
|
||||||
|
// Wait for form to load
|
||||||
|
await expect(page.locator('text=Tournament Name')).toBeVisible();
|
||||||
|
|
||||||
|
// Toggle allowTies checkbox
|
||||||
|
const allowTiesCheckbox = page.locator('input[name="allowTies"]');
|
||||||
|
await allowTiesCheckbox.check();
|
||||||
|
await expect(allowTiesCheckbox).toBeChecked();
|
||||||
|
|
||||||
|
// Submit form
|
||||||
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
|
// Wait for success message
|
||||||
|
await expect(page.locator('text=Tournament updated successfully')).toBeVisible({ timeout: 5000 });
|
||||||
|
|
||||||
|
// Verify allowTies was saved by checking the database
|
||||||
|
const updatedTournament = await prisma.event.findUnique({
|
||||||
|
where: { id: tournamentId },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(updatedTournament?.allowTies).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should save allowTies when toggled to false', async ({ page }) => {
|
||||||
|
// First, set allowTies to true
|
||||||
|
await prisma.event.update({
|
||||||
|
where: { id: tournamentId },
|
||||||
|
data: { allowTies: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Navigate to tournament edit page
|
||||||
|
await page.goto(`/admin/tournaments/${tournamentId}/edit`);
|
||||||
|
|
||||||
|
// Wait for form to load
|
||||||
|
await expect(page.locator('text=Tournament Name')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify checkbox is checked
|
||||||
|
const allowTiesCheckbox = page.locator('input[name="allowTies"]');
|
||||||
|
await expect(allowTiesCheckbox).toBeChecked();
|
||||||
|
|
||||||
|
// Uncheck allowTies checkbox
|
||||||
|
await allowTiesCheckbox.uncheck();
|
||||||
|
await expect(allowTiesCheckbox).not.toBeChecked();
|
||||||
|
|
||||||
|
// Submit form
|
||||||
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
|
// Wait for success message
|
||||||
|
await expect(page.locator('text=Tournament updated successfully')).toBeVisible({ timeout: 5000 });
|
||||||
|
|
||||||
|
// Verify allowTies was saved by checking the database
|
||||||
|
const updatedTournament = await prisma.event.findUnique({
|
||||||
|
where: { id: tournamentId },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(updatedTournament?.allowTies).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for tournament update functionality
|
||||||
|
* Tests the allowTies field is properly saved when updating tournaments
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { prisma } from '@/lib/prisma';
|
||||||
|
|
||||||
|
// Mock the prisma client
|
||||||
|
vi.mock('@/lib/prisma', () => ({
|
||||||
|
prisma: {
|
||||||
|
event: {
|
||||||
|
findUnique: vi.fn(),
|
||||||
|
update: vi.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock the permissions module
|
||||||
|
vi.mock('@/lib/permissions', () => ({
|
||||||
|
canManageTournament: vi.fn().mockResolvedValue({ allowed: true }),
|
||||||
|
canDeleteTournament: vi.fn().mockResolvedValue({ allowed: true }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Import the route handler after mocking
|
||||||
|
import { PUT } from '@/app/api/tournaments/[id]/route';
|
||||||
|
|
||||||
|
describe('Tournament Update API', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update allowTies field when provided', async () => {
|
||||||
|
// Mock existing tournament
|
||||||
|
vi.mocked(prisma.event.findUnique).mockResolvedValue({
|
||||||
|
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
|
||||||
|
vi.mocked(prisma.event.update).mockResolvedValue({
|
||||||
|
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(vi.mocked(prisma.event.update)).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: expect.objectContaining({
|
||||||
|
allowTies: true,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should default allowTies to false when not provided', async () => {
|
||||||
|
// Mock existing tournament
|
||||||
|
vi.mocked(prisma.event.findUnique).mockResolvedValue({
|
||||||
|
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
|
||||||
|
vi.mocked(prisma.event.update).mockResolvedValue({
|
||||||
|
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);
|
||||||
|
|
||||||
|
const request = new Request('http://localhost/api/tournaments/1', {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'Test Tournament',
|
||||||
|
targetScore: 5,
|
||||||
|
// allowTies not provided
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = Promise.resolve({ id: '1' });
|
||||||
|
const response = await PUT(request, { params });
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(vi.mocked(prisma.event.update)).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: expect.objectContaining({
|
||||||
|
allowTies: false, // Should default to false
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should preserve allowTies value when updating other fields', async () => {
|
||||||
|
// Mock existing tournament with allowTies = true
|
||||||
|
vi.mocked(prisma.event.findUnique).mockResolvedValue({
|
||||||
|
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
|
||||||
|
vi.mocked(prisma.event.update).mockResolvedValue({
|
||||||
|
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 updateCall = vi.mocked(prisma.event.update).mock.calls[0][0];
|
||||||
|
expect(updateCall.data.allowTies).toBe(true);
|
||||||
|
expect(updateCall.data.name).toBe('Updated Tournament Name');
|
||||||
|
expect(updateCall.data.targetScore).toBe(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -52,6 +52,7 @@ export default function EditTournamentForm({ tournament }: EditTournamentFormPro
|
|||||||
maxParticipants: formData.maxParticipants ? parseInt(formData.maxParticipants) : null,
|
maxParticipants: formData.maxParticipants ? parseInt(formData.maxParticipants) : null,
|
||||||
eventDate: formData.eventDate ? new Date(formData.eventDate).toISOString() : null,
|
eventDate: formData.eventDate ? new Date(formData.eventDate).toISOString() : null,
|
||||||
targetScore: formData.targetScore ? parseInt(formData.targetScore) : null,
|
targetScore: formData.targetScore ? parseInt(formData.targetScore) : null,
|
||||||
|
allowTies: formData.allowTies,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user