import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { act, screen } from '@testing-library/react'; import { render } from '../utils'; import { CameraTile } from '../../components/CameraTile'; // The shared render() util mounts AuthProvider, which fires an async // /auth/me probe on mount. Each test absorbs that settle with a single // `await act(async () => {})` after render so the AuthProvider state // update doesn't bleed into the assertion phase as an act() warning. async function flushMicrotasks() { await act(async () => { await Promise.resolve(); }); } describe('CameraTile', () => { beforeEach(() => { vi.useFakeTimers(); vi.spyOn(global, 'fetch').mockResolvedValue(new Response(null, { status: 200 })); }); afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); }); it('renders the live stream URL in live mode', async () => { render( , ); await flushMicrotasks(); const img = screen.getByAltText('X1C-Lab') as HTMLImageElement; expect(img.src).toContain('/api/v1/printers/42/camera/stream'); expect(img.src).toContain('fps=8'); }); it('renders the snapshot URL and refreshes on the interval', async () => { render( , ); await flushMicrotasks(); const initial = (screen.getByAltText('P1S-Garage') as HTMLImageElement).src; expect(initial).toContain('/api/v1/printers/7/camera/snapshot'); await act(async () => { vi.advanceTimersByTime(1500); }); const refreshed = (screen.getByAltText('P1S-Garage') as HTMLImageElement).src; expect(refreshed).toContain('/api/v1/printers/7/camera/snapshot'); expect(refreshed).not.toBe(initial); }); it('shows an offline placeholder when not connected', async () => { render( , ); await flushMicrotasks(); expect(screen.queryByAltText('A1-Offline')).toBeNull(); }); it('shows the paused placeholder in paused mode', async () => { render( , ); await flushMicrotasks(); expect(screen.queryByAltText('H2D-Booth')).toBeNull(); }); it('POSTs /camera/stop when leaving live mode', async () => { const fetchMock = vi.spyOn(global, 'fetch').mockResolvedValue( new Response(null, { status: 200 }), ); const { rerender } = render( , ); await flushMicrotasks(); fetchMock.mockClear(); await act(async () => { rerender( , ); }); const stopCalls = fetchMock.mock.calls.filter(([url]) => String(url).includes('/api/v1/printers/11/camera/stop'), ); expect(stopCalls.length).toBeGreaterThan(0); }); });