import { render, screen, act, cleanup, waitFor } from '@testing-library/react'; import ConnectedRobots from '../../../src/pages/ConnectedRobots/ConnectedRobots'; // Mock event source const mockInstances: MockEventSource[] = []; class MockEventSource { url: string; onmessage: ((event: MessageEvent) => void) | null = null; closed = false; constructor(url: string) { this.url = url; mockInstances.push(this); } sendMessage(data: string) { // Trigger whatever the component listens to this.onmessage?.({ data } as MessageEvent); } close() { this.closed = true; } } // mock event source generation with fake function that returns our fake mock source beforeAll(() => { // Cast globalThis to a type exposing EventSource and assign a mocked constructor. (globalThis as unknown as { EventSource?: typeof EventSource }).EventSource = jest.fn((url: string) => new MockEventSource(url)) as unknown as typeof EventSource; }); // clean after tests afterEach(() => { cleanup(); jest.restoreAllMocks(); mockInstances.length = 0; }); describe('ConnectedRobots', () => { test('renders initial state correctly', () => { render(); // Check initial texts (before connection) expect(screen.getByText('Is robot currently connected?')).toBeInTheDocument(); expect(screen.getByText(/Robot is currently:\s*checking/i)).toBeInTheDocument(); expect( screen.getByText(/If checking continues, make sure CB is properly loaded/i) ).toBeInTheDocument(); }); test('updates to connected when message data is true', async () => { render(); const eventSource = mockInstances[0]; expect(eventSource).toBeDefined(); // Check state after getting 'true' message await act(async () => { eventSource.sendMessage('true'); }); await waitFor(() => { expect(screen.getByText(/connected! 🟢/i)).toBeInTheDocument(); }); }); test('updates to not connected when message data is false', async () => { render(); const eventSource = mockInstances[0]; // Check statew after getting 'false' message await act(async () => { eventSource.sendMessage('false'); }); await waitFor(() => { expect(screen.getByText(/not connected.*🔴/i)).toBeInTheDocument(); }); }); test('handles invalid JSON gracefully', async () => { const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); render(); const eventSource = mockInstances[0]; await act(async () => { eventSource.sendMessage('not-json'); }); expect(logSpy).toHaveBeenCalledWith( 'Ping message not in correct format:', 'not-json' ); }); test('closes EventSource on unmount', () => { render(); const eventSource = mockInstances[0]; const closeSpy = jest.spyOn(eventSource, 'close'); cleanup(); expect(closeSpy).toHaveBeenCalled(); expect(eventSource.closed).toBe(true); }); });