From fd0dcdf77fa262da78ec88dc33144fe01b346150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Gierwia=C5=82o?= Date: Thu, 20 Nov 2025 00:05:24 +0100 Subject: [PATCH] test: improve test cleanup with selective deletion - Replace deleteMany({}) with selective deletion by username/email/slug in: - events.test.js (target specific test users/events only) - matches.test.js (target specific test users/events only) - csrf.test.js (target csrftest user only) - Replace delete() with deleteMany() for resilient cleanup: - matches.test.js (2 inline cleanups) - socket-webrtc.test.js (1 inline cleanup) - Update TODO.md with test status and future UX/UI improvements Test improvement: 189/223 passing (84.8%), up from 145/223 (65%) --- backend/src/__tests__/csrf.test.js | 20 +++++- backend/src/__tests__/events.test.js | 66 +++++++++++++++++--- backend/src/__tests__/matches.test.js | 66 +++++++++++++++++--- backend/src/__tests__/socket-webrtc.test.js | 2 +- docs/TODO.md | 69 +++++++++++++++++++++ 5 files changed, 200 insertions(+), 23 deletions(-) diff --git a/backend/src/__tests__/csrf.test.js b/backend/src/__tests__/csrf.test.js index 0b2c753..0c61710 100644 --- a/backend/src/__tests__/csrf.test.js +++ b/backend/src/__tests__/csrf.test.js @@ -6,11 +6,27 @@ const securityConfig = require('../config/security'); // Clean up database before and after tests beforeAll(async () => { - await prisma.user.deleteMany({}); + // Only delete test user, not all users + await prisma.user.deleteMany({ + where: { + OR: [ + { username: 'csrftest' }, + { email: 'csrf@example.com' } + ] + } + }); }); afterAll(async () => { - await prisma.user.deleteMany({}); + // Only delete test user, not all users + await prisma.user.deleteMany({ + where: { + OR: [ + { username: 'csrftest' }, + { email: 'csrf@example.com' } + ] + } + }); await prisma.$disconnect(); }); diff --git a/backend/src/__tests__/events.test.js b/backend/src/__tests__/events.test.js index 0cc68a8..3ae9b28 100644 --- a/backend/src/__tests__/events.test.js +++ b/backend/src/__tests__/events.test.js @@ -182,16 +182,62 @@ beforeAll(async () => { }, 30000); afterAll(async () => { - // Clean up - await prisma.eventUserHeat.deleteMany({}); - await prisma.rating.deleteMany({}); - await prisma.message.deleteMany({}); - await prisma.match.deleteMany({}); - await prisma.chatRoom.deleteMany({}); - await prisma.eventCheckinToken.deleteMany({}); - await prisma.eventParticipant.deleteMany({}); - await prisma.event.deleteMany({}); - await prisma.user.deleteMany({}); + // Clean up - only delete test data, not all data + const testUsernames = ['john_dancer', 'sarah_swings', 'mike_blues']; + const testEmails = ['john@example.com', 'sarah@example.com', 'mike@example.com']; + const testEventSlugs = ['test-dance-festival-2025', 'test-another-event-2025']; + + // Find test events + const testEvents = await prisma.event.findMany({ + where: { slug: { in: testEventSlugs } }, + select: { id: true } + }); + const testEventIds = testEvents.map(e => e.id); + + // Find test users + const testUsers = await prisma.user.findMany({ + where: { + OR: [ + { username: { in: testUsernames } }, + { email: { in: testEmails } } + ] + }, + select: { id: true } + }); + const testUserIds = testUsers.map(u => u.id); + + // Delete related data for test users and events only + if (testUserIds.length > 0) { + await prisma.eventUserHeat.deleteMany({ where: { userId: { in: testUserIds } } }); + await prisma.rating.deleteMany({ where: { raterId: { in: testUserIds } } }); + await prisma.message.deleteMany({ where: { userId: { in: testUserIds } } }); + await prisma.match.deleteMany({ + where: { + OR: [ + { user1Id: { in: testUserIds } }, + { user2Id: { in: testUserIds } } + ] + } + }); + } + + if (testEventIds.length > 0) { + await prisma.chatRoom.deleteMany({ where: { eventId: { in: testEventIds } } }); + await prisma.eventCheckinToken.deleteMany({ where: { eventId: { in: testEventIds } } }); + await prisma.eventParticipant.deleteMany({ where: { eventId: { in: testEventIds } } }); + await prisma.event.deleteMany({ where: { id: { in: testEventIds } } }); + } + + // Delete test users + await prisma.user.deleteMany({ + where: { + OR: [ + { username: { in: testUsernames } }, + { email: { in: testEmails } } + ] + } + }); + await prisma.$disconnect(); }); diff --git a/backend/src/__tests__/matches.test.js b/backend/src/__tests__/matches.test.js index d59f74d..6e7668c 100644 --- a/backend/src/__tests__/matches.test.js +++ b/backend/src/__tests__/matches.test.js @@ -126,14 +126,60 @@ beforeAll(async () => { }); afterAll(async () => { - // Clean up - await prisma.rating.deleteMany({}); - await prisma.message.deleteMany({}); - await prisma.match.deleteMany({}); - await prisma.chatRoom.deleteMany({}); - await prisma.eventParticipant.deleteMany({}); - await prisma.event.deleteMany({}); - await prisma.user.deleteMany({}); + // Clean up - only delete test data, not all data + const testUsernames = ['john_dancer', 'sarah_swings', 'mike_moves', 'outsider']; + const testEmails = ['john@example.com', 'sarah@example.com', 'mike@example.com', 'outsider@example.com']; + const testEventSlugs = ['test-dance-festival']; + + // Find test users + const testUsers = await prisma.user.findMany({ + where: { + OR: [ + { username: { in: testUsernames } }, + { email: { in: testEmails } } + ] + }, + select: { id: true } + }); + const testUserIds = testUsers.map(u => u.id); + + // Find test events + const testEvents = await prisma.event.findMany({ + where: { slug: { in: testEventSlugs } }, + select: { id: true } + }); + const testEventIds = testEvents.map(e => e.id); + + // Delete related data for test users and events only + if (testUserIds.length > 0) { + await prisma.rating.deleteMany({ where: { raterId: { in: testUserIds } } }); + await prisma.message.deleteMany({ where: { userId: { in: testUserIds } } }); + await prisma.match.deleteMany({ + where: { + OR: [ + { user1Id: { in: testUserIds } }, + { user2Id: { in: testUserIds } } + ] + } + }); + } + + if (testEventIds.length > 0) { + await prisma.chatRoom.deleteMany({ where: { eventId: { in: testEventIds } } }); + await prisma.eventParticipant.deleteMany({ where: { eventId: { in: testEventIds } } }); + await prisma.event.deleteMany({ where: { id: { in: testEventIds } } }); + } + + // Delete test users + await prisma.user.deleteMany({ + where: { + OR: [ + { username: { in: testUsernames } }, + { email: { in: testEmails } } + ] + } + }); + await prisma.$disconnect(); }); @@ -290,7 +336,7 @@ describe('Matches API Tests', () => { expect(response.body).toHaveProperty('success', false); // Clean up - await prisma.user.delete({ where: { id: testUser3.id } }); + await prisma.user.deleteMany({ where: { id: testUser3.id } }); }); it('should return 404 for non-existent match slug', async () => { @@ -351,7 +397,7 @@ describe('Matches API Tests', () => { expect(response.body).toHaveProperty('success', false); // Clean up - await prisma.match.delete({ where: { slug: newMatch.slug } }); + await prisma.match.deleteMany({ where: { slug: newMatch.slug } }); }); }); diff --git a/backend/src/__tests__/socket-webrtc.test.js b/backend/src/__tests__/socket-webrtc.test.js index 7bd2f9b..19a65a1 100644 --- a/backend/src/__tests__/socket-webrtc.test.js +++ b/backend/src/__tests__/socket-webrtc.test.js @@ -229,7 +229,7 @@ describe('Socket.IO WebRTC Signaling', () => { expect(error.message).toContain('authorized'); // Cleanup - await prisma.match.delete({ where: { id: unauthorizedMatch.id } }); + await prisma.match.deleteMany({ where: { id: unauthorizedMatch.id } }); }); }); diff --git a/docs/TODO.md b/docs/TODO.md index 7bc5b84..6ae6ee7 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -11,6 +11,75 @@ **Also Completed:** 1.6 (Competition Heats System - Backend & Frontend) - ✅ COMPLETED **Progress:** ~72% complete +### 🔧 CURRENT STATUS - Backend Tests (2025-11-20) + +**Test Status:** 189/223 passing (84.8%) - ✅ Significant improvement! +- **Before:** 145/223 (65%) +- **After fixes:** 189/223 (84.8%) +- **Improvement:** +44 tests (+19.8%) + +**✅ Fixed:** +1. Test cleanup - replaced `deleteMany({})` with selective deletion: + - `backend/src/__tests__/events.test.js` - selective deletion by username/email/slug + - `backend/src/__tests__/matches.test.js` - selective deletion by username/email/slug + - `backend/src/__tests__/csrf.test.js` - selective deletion by username/email +2. Cleanup resilience - replaced `delete()` with `deleteMany()`: + - `backend/src/__tests__/socket.test.js` - all afterAll + inline cleanup + - `backend/src/__tests__/matches.test.js` - inline cleanup (2 locations) + - `backend/src/__tests__/socket-webrtc.test.js` - inline cleanup +3. Socket tests fixes: + - Changed `eventId` → `slug` in socket event handlers + - Added `EventParticipant` creation before join_event_room + - Added safety checks before creating FK relationships +4. Auth tests fixes: + - `app.test.js` - CORS origin localhost:8080 + - `security.js` - added localhost:3000 to allowed origins (dev) + - `auth-phase1.5.test.js` - fixed error message expectations + +**❌ Remaining issues (34 failing tests in 3 test suites):** +- `users.test.js` - ??? (unknown errors, needs analysis) +- `events.test.js` - ??? (unknown errors, despite cleanup fixes) +- `matches.test.js` - PASS individually, FAIL in suite (race conditions?) + +**⏳ TODO:** +1. Check detailed errors in `users.test.js` +2. Check detailed errors in `events.test.js` +3. Investigate race conditions in `matches.test.js` +4. Potentially add test isolation (beforeEach cleanup) +5. Consider using transactions in tests + +**Commits made:** +- `test: fix socket.test.js cleanup and event room parameters` +- `test: improve test cleanup - selective deletion instead of wiping tables` + +### 📋 FUTURE UX/UI IMPROVEMENTS + +**Dashboard Page (Post-Login):** +- [ ] Create `/dashboard` route as default landing page after login +- [ ] Show current user information (profile summary, stats) +- [ ] Quick access buttons to active chats (event rooms, match chats) +- [ ] Display ongoing discussions/conversations +- [ ] Show upcoming events user is registered for +- [ ] Recent activity feed (new matches, messages, ratings) +- [ ] Navigation shortcuts to key features + +**Event Chat Sidebar Enhancements:** +- [ ] Add competitor number display for each user in sidebar +- [ ] Show user nationality (flag + country code) +- [ ] Expand user info cards in sidebar: + - Competition heats (already implemented) + - Competitor number + - Country/nationality + - User role/level + - Years of experience (if available in profile) + - Average rating (if rated) +- [ ] Consider expandable user cards (click to see more details) +- [ ] Add filtering options: + - By nationality + - By division/level + - By competitor number range +- [ ] Improve mobile responsiveness for extended sidebar info + ### ✅ Completed - Phase 0: Frontend mockup with all views - Phase 1: Backend Foundation