bb6be245b7
## Summary This PR implements the tournament schedule tab functionality and fixes all remaining E2E test failures. ### Changes Included 1. **Tournament Schedule Feature** - Added tournament schedule page at `/admin/tournaments/[id]/schedule` - Implemented "Generate Schedule" button functionality - Added schedule generation logic for round-robin tournaments 2. **E2E Test Fixes** - Fixed database connection issues in production builds - Improved test reliability with better error handling and debugging - Updated test infrastructure to use environment variables instead of hardcoded values 3. **CI/CD Updates** - Added E2E test job to PR workflow - Configured tests to run against development database - Moved database password to Gitea secrets 4. **Code Quality** - Removed hardcoded passwords from codebase - Improved Prisma client configuration - Enhanced authentication and navigation components ### Test Results All 16 E2E test scenarios are now passing: - Authentication tests: ✅ - Registration tests: ✅ - Tournament schedule tests: ✅ - Player schedule tests: ✅ - Admin navigation tests: ✅ ### Database Configuration - Tests run against `euchre_camp_dev` database - Production builds use environment variables for database configuration - Database password stored in Gitea secrets as `DB_PASSWORD` ### CI Pipeline The PR workflow now includes: 1. Unit tests 2. E2E tests (using production build) 3. Version bump analysis E2E tests must pass before PR can be merged. Reviewed-on: #27 Co-authored-by: David Gwilliam <dhgwilliam@gmail.com> Co-committed-by: David Gwilliam <dhgwilliam@gmail.com>
275 lines
6.6 KiB
TypeScript
275 lines
6.6 KiB
TypeScript
/**
|
|
* Test Utilities for EuchreCamp
|
|
*
|
|
* Provides helper functions for creating and cleaning up test data
|
|
*/
|
|
|
|
import { prisma } from '@/lib/prisma';
|
|
import type { User, Player, Event, Match } from '@prisma/client';
|
|
|
|
// Track created test records for cleanup
|
|
const createdRecords = {
|
|
users: [] as string[],
|
|
players: [] as number[],
|
|
events: [] as number[],
|
|
matches: [] as number[],
|
|
};
|
|
|
|
/**
|
|
* Create a test user with optional player association
|
|
*/
|
|
export async function createTestUser(options: {
|
|
email?: string;
|
|
name?: string;
|
|
role?: string;
|
|
playerId?: number | null;
|
|
} = {}) {
|
|
const timestamp = Date.now();
|
|
const email = options.email || `test-user-${timestamp}@example.com`;
|
|
const name = options.name || `Test User ${timestamp}`;
|
|
const role = options.role || 'player';
|
|
|
|
const user = await prisma.user.create({
|
|
data: {
|
|
email,
|
|
name,
|
|
role,
|
|
playerId: options.playerId,
|
|
},
|
|
});
|
|
|
|
createdRecords.users.push(user.id);
|
|
return user;
|
|
}
|
|
|
|
/**
|
|
* Create a test player
|
|
*/
|
|
export async function createTestPlayer(options: {
|
|
name?: string;
|
|
currentElo?: number;
|
|
} = {}) {
|
|
const timestamp = Date.now();
|
|
const name = options.name || `Test Player ${timestamp}`;
|
|
|
|
const player = await prisma.player.create({
|
|
data: {
|
|
name,
|
|
normalizedName: name.toLowerCase(),
|
|
currentElo: options.currentElo || 1000,
|
|
},
|
|
});
|
|
|
|
createdRecords.players.push(player.id);
|
|
return player;
|
|
}
|
|
|
|
/**
|
|
* Create a test event (tournament)
|
|
*/
|
|
export async function createTestEvent(options: {
|
|
name?: string;
|
|
ownerId?: string;
|
|
} = {}) {
|
|
const timestamp = Date.now();
|
|
const name = options.name || `Test Event ${timestamp}`;
|
|
|
|
const event = await prisma.event.create({
|
|
data: {
|
|
name,
|
|
eventType: 'tournament',
|
|
format: 'round_robin',
|
|
status: 'planned',
|
|
ownerId: options.ownerId,
|
|
},
|
|
});
|
|
|
|
createdRecords.events.push(event.id);
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* Create a test match
|
|
*/
|
|
export async function createTestMatch(options: {
|
|
eventId?: number;
|
|
team1P1Id: number;
|
|
team1P2Id: number;
|
|
team2P1Id: number;
|
|
team2P2Id: number;
|
|
team1Score?: number;
|
|
team2Score?: number;
|
|
}) {
|
|
const timestamp = Date.now();
|
|
|
|
const match = await prisma.match.create({
|
|
data: {
|
|
eventId: options.eventId,
|
|
player1P1Id: options.team1P1Id,
|
|
player1P2Id: options.team1P2Id,
|
|
player2P1Id: options.team2P1Id,
|
|
player2P2Id: options.team2P2Id,
|
|
team1Score: options.team1Score ?? 10,
|
|
team2Score: options.team2Score ?? 5,
|
|
status: 'completed',
|
|
},
|
|
});
|
|
|
|
createdRecords.matches.push(match.id);
|
|
return match;
|
|
}
|
|
|
|
/**
|
|
* Clean up all created test records
|
|
*/
|
|
export async function cleanupTestRecords() {
|
|
console.log('🧹 Cleaning up test records...');
|
|
|
|
try {
|
|
// Delete matches first (they reference players)
|
|
if (createdRecords.matches.length > 0) {
|
|
await prisma.match.deleteMany({
|
|
where: { id: { in: createdRecords.matches } },
|
|
});
|
|
console.log(` Deleted ${createdRecords.matches.length} matches`);
|
|
}
|
|
|
|
// Delete events
|
|
if (createdRecords.events.length > 0) {
|
|
await prisma.event.deleteMany({
|
|
where: { id: { in: createdRecords.events } },
|
|
});
|
|
console.log(` Deleted ${createdRecords.events.length} events`);
|
|
}
|
|
|
|
// Delete users first (to break player associations)
|
|
if (createdRecords.users.length > 0) {
|
|
await prisma.user.deleteMany({
|
|
where: { id: { in: createdRecords.users } },
|
|
});
|
|
console.log(` Deleted ${createdRecords.users.length} users`);
|
|
}
|
|
|
|
// Delete players
|
|
if (createdRecords.players.length > 0) {
|
|
await prisma.player.deleteMany({
|
|
where: { id: { in: createdRecords.players } },
|
|
});
|
|
console.log(` Deleted ${createdRecords.players.length} players`);
|
|
}
|
|
|
|
// Reset tracking
|
|
createdRecords.users = [];
|
|
createdRecords.players = [];
|
|
createdRecords.events = [];
|
|
createdRecords.matches = [];
|
|
|
|
console.log('✅ Test records cleaned up successfully');
|
|
} catch (error) {
|
|
console.error('❌ Error cleaning up test records:', error);
|
|
// Still reset tracking to avoid trying to delete again
|
|
createdRecords.users = [];
|
|
createdRecords.players = [];
|
|
createdRecords.events = [];
|
|
createdRecords.matches = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get count of created records (for assertions)
|
|
*/
|
|
export function getCreatedRecordCounts() {
|
|
return {
|
|
users: createdRecords.users.length,
|
|
players: createdRecords.players.length,
|
|
events: createdRecords.events.length,
|
|
matches: createdRecords.matches.length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Clean up test users by email pattern
|
|
*/
|
|
export async function cleanupTestUsersByEmailPattern(pattern: string = 'test-') {
|
|
try {
|
|
const result = await prisma.user.deleteMany({
|
|
where: {
|
|
email: {
|
|
contains: pattern,
|
|
},
|
|
},
|
|
});
|
|
console.log(` Deleted ${result.count} test users matching pattern "${pattern}"`);
|
|
return result.count;
|
|
} catch (error) {
|
|
console.error('❌ Error cleaning up test users:', error);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean up test players by name pattern
|
|
*/
|
|
export async function cleanupTestPlayersByNamePattern(pattern: string = 'Test ') {
|
|
try {
|
|
const result = await prisma.player.deleteMany({
|
|
where: {
|
|
name: {
|
|
contains: pattern,
|
|
},
|
|
},
|
|
});
|
|
console.log(` Deleted ${result.count} test players matching pattern "${pattern}"`);
|
|
return result.count;
|
|
} catch (error) {
|
|
console.error('❌ Error cleaning up test players:', error);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean up all test data (aggressive cleanup)
|
|
*/
|
|
export async function cleanupAllTestData() {
|
|
console.log('🧹 Aggressive cleanup of all test data...');
|
|
|
|
try {
|
|
// Delete test users first
|
|
const userResult = await prisma.user.deleteMany({
|
|
where: {
|
|
email: {
|
|
contains: 'test-',
|
|
},
|
|
},
|
|
});
|
|
console.log(` Deleted ${userResult.count} test users`);
|
|
|
|
// Delete test players
|
|
const playerResult = await prisma.player.deleteMany({
|
|
where: {
|
|
name: {
|
|
contains: 'Test ',
|
|
},
|
|
},
|
|
});
|
|
console.log(` Deleted ${playerResult.count} test players`);
|
|
|
|
// Delete test events
|
|
const eventResult = await prisma.event.deleteMany({
|
|
where: {
|
|
name: {
|
|
contains: 'Test ',
|
|
},
|
|
},
|
|
});
|
|
console.log(` Deleted ${eventResult.count} test events`);
|
|
|
|
console.log('✅ All test data cleaned up');
|
|
} catch (error) {
|
|
console.error('❌ Error during aggressive cleanup:', error);
|
|
}
|
|
}
|
|
|
|
// Export cleanup function for global setup/teardown
|
|
export const testCleanup = cleanupTestRecords;
|