import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { RouteManager } from './RouteManager'; const groups = [ { id: 'grp_1', name: 'Alpha', platform: 'whatsapp', isActive: true }, { id: 'grp_2', name: 'Beta', platform: 'whatsapp', isActive: true }, { id: 'grp_3', name: 'Gamma', platform: 'whatsapp', isActive: true }, ]; const routes = [ { id: 'rt_1', sourceGroupId: 'grp_1', targetGroupId: 'grp_2', sourceGroup: { name: 'Alpha' }, targetGroup: { name: 'Beta' }, }, ]; let fetchSpy: jest.SpyInstance; beforeEach(() => { fetchSpy = jest.spyOn(global, 'fetch'); }); afterEach(() => { jest.restoreAllMocks(); }); describe('RouteManager', () => { it('renders routes grouped by source group', () => { render(); expect(screen.getByText('Alpha')).toBeInTheDocument(); expect(screen.getByText('Beta')).toBeInTheDocument(); }); it('shows source dropdown and target checkboxes', () => { render(); expect(screen.getByRole('combobox')).toBeInTheDocument(); expect(screen.queryByRole('checkbox')).not.toBeInTheDocument(); }); it('shows target checkboxes when a source is selected', () => { render(); fireEvent.change(screen.getByRole('combobox'), { target: { value: 'grp_1' } }); expect(screen.getAllByRole('checkbox')).toHaveLength(2); }); it('calls POST /api/routes/batch with selected targetIds', async () => { fetchSpy.mockResolvedValueOnce( new Response( JSON.stringify([ { id: 'rt_new', sourceGroupId: 'grp_1', targetGroupId: 'grp_2', sourceGroup: { name: 'Alpha' }, targetGroup: { name: 'Beta' } }, { id: 'rt_new2', sourceGroupId: 'grp_1', targetGroupId: 'grp_3', sourceGroup: { name: 'Alpha' }, targetGroup: { name: 'Gamma' } }, ]), { status: 201, headers: { 'Content-Type': 'application/json' } }, ), ); render(); fireEvent.change(screen.getByRole('combobox'), { target: { value: 'grp_1' } }); const checkboxes = screen.getAllByRole('checkbox'); fireEvent.click(checkboxes[0]); fireEvent.click(checkboxes[1]); fireEvent.click(screen.getByRole('button', { name: /create 2 routes/i })); await waitFor(() => { expect(fetchSpy).toHaveBeenCalledWith( '/api/routes/batch', expect.objectContaining({ method: 'POST', body: JSON.stringify({ sourceGroupId: 'grp_1', targetGroupIds: ['grp_2', 'grp_3'] }), }), ); }); }); it('shows error message on 409 conflict', async () => { fetchSpy.mockResolvedValueOnce( new Response( JSON.stringify({ message: 'Routes already exist for: Beta' }), { status: 409, headers: { 'Content-Type': 'application/json' } }, ), ); render(); fireEvent.change(screen.getByRole('combobox'), { target: { value: 'grp_1' } }); fireEvent.click(screen.getAllByRole('checkbox')[0]); fireEvent.click(screen.getByRole('button', { name: /create 1 route/i })); await waitFor(() => { expect(screen.getByText('Routes already exist for: Beta')).toBeInTheDocument(); }); }); it('shows a delete button for each existing route', () => { render(); const deleteBtn = screen.getByRole('button', { name: /delete route to beta/i }); expect(deleteBtn).toBeInTheDocument(); }); it('calls DELETE /api/routes/:id when a route is deleted', async () => { fetchSpy.mockResolvedValueOnce(new Response(null, { status: 204 })); render(); fireEvent.click(screen.getByRole('button', { name: /delete route to beta/i })); await waitFor(() => { expect(fetchSpy).toHaveBeenCalledWith( '/api/routes/rt_1', expect.objectContaining({ method: 'DELETE' }), ); }); }); });