/** * WSDC Controller Tests (Phase 1.5) * Tests for WSDC API proxy functionality */ const request = require('supertest'); const app = require('../app'); // Mock fetch globally global.fetch = jest.fn(); describe('WSDC Controller Tests (Phase 1.5)', () => { beforeEach(() => { fetch.mockClear(); }); describe('GET /api/wsdc/lookup', () => { it('should lookup dancer by WSDC ID successfully', async () => { const mockDancerData = { dancer_wsdcid: 26997, dancer_first: 'Radoslaw', dancer_last: 'Gierwialo', recent_year: 2025 }; fetch.mockResolvedValue({ ok: true, json: async () => mockDancerData }); const response = await request(app) .get('/api/wsdc/lookup?id=26997'); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.dancer).toMatchObject({ wsdcId: 26997, firstName: 'Radoslaw', lastName: 'Gierwialo' }); }); it('should return 400 if WSDC ID is missing', async () => { const response = await request(app) .get('/api/wsdc/lookup'); expect(response.status).toBe(400); expect(response.body.error).toBe('Bad Request'); expect(response.body.message).toContain('WSDC ID is required'); }); it('should return 400 for invalid WSDC ID format', async () => { const response = await request(app) .get('/api/wsdc/lookup?id=abc123'); expect(response.status).toBe(400); expect(response.body.error).toBe('Bad Request'); expect(response.body.message).toContain('Invalid WSDC ID format'); }); it('should return 400 for WSDC ID too long', async () => { const response = await request(app) .get('/api/wsdc/lookup?id=12345678901'); // 11 digits expect(response.status).toBe(400); expect(response.body.error).toBe('Bad Request'); }); it('should return 404 if dancer not found', async () => { fetch.mockResolvedValue({ ok: true, json: async () => ({}) // Empty response }); const response = await request(app) .get('/api/wsdc/lookup?id=99999'); expect(response.status).toBe(404); expect(response.body.error).toBe('Not Found'); expect(response.body.message).toContain('not found'); }); it('should return 502 if WSDC API fails', async () => { fetch.mockResolvedValue({ ok: false, status: 500, statusText: 'Internal Server Error' }); const response = await request(app) .get('/api/wsdc/lookup?id=26997'); expect(response.status).toBe(502); expect(response.body.error).toBe('Bad Gateway'); }); it('should handle network errors', async () => { fetch.mockRejectedValue(new Error('Network error')); const response = await request(app) .get('/api/wsdc/lookup?id=26997'); expect(response.status).toBe(500); expect(response.body.error).toBe('Internal Server Error'); }); it('should call WSDC API with correct URL', async () => { fetch.mockResolvedValue({ ok: true, json: async () => ({ dancer_wsdcid: 26997, dancer_first: 'Test', dancer_last: 'User' }) }); await request(app) .get('/api/wsdc/lookup?id=26997'); expect(fetch).toHaveBeenCalledWith( 'https://points.worldsdc.com/lookup2020/find?q=26997' ); }); it('should validate numeric WSDC IDs only', async () => { const invalidIds = ['abc', '123abc', 'test', '!@#$']; for (const id of invalidIds) { const response = await request(app) .get(`/api/wsdc/lookup?id=${id}`); expect(response.status).toBe(400); } }); it('should accept valid numeric WSDC IDs', async () => { fetch.mockResolvedValue({ ok: true, json: async () => ({ dancer_wsdcid: 123, dancer_first: 'Test', dancer_last: 'User' }) }); const validIds = ['1', '123', '12345', '1234567890']; for (const id of validIds) { const response = await request(app) .get(`/api/wsdc/lookup?id=${id}`); expect(response.status).toBe(200); } }); it('should include optional fields if available', async () => { const mockDancerData = { dancer_wsdcid: 26997, dancer_first: 'Radoslaw', dancer_last: 'Gierwialo', recent_year: 2025, dominate_data: { short_dominate_role: 'Leader' } }; fetch.mockResolvedValue({ ok: true, json: async () => mockDancerData }); const response = await request(app) .get('/api/wsdc/lookup?id=26997'); expect(response.status).toBe(200); expect(response.body.dancer.recentYear).toBe(2025); expect(response.body.dancer.dominateRole).toBe('Leader'); }); it('should handle missing optional fields gracefully', async () => { const mockDancerData = { dancer_wsdcid: 26997, dancer_first: 'Test', dancer_last: 'User' // No recent_year or dominate_data }; fetch.mockResolvedValue({ ok: true, json: async () => mockDancerData }); const response = await request(app) .get('/api/wsdc/lookup?id=26997'); expect(response.status).toBe(200); expect(response.body.dancer.dominateRole).toBeNull(); }); it('should log errors for debugging', async () => { const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); fetch.mockRejectedValue(new Error('Test error')); await request(app) .get('/api/wsdc/lookup?id=26997'); expect(consoleSpy).toHaveBeenCalled(); consoleSpy.mockRestore(); }); }); });