/** * Tests for the QueuePage component. */ import { describe, it, expect, beforeEach, vi } from 'vitest'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { render } from '../utils'; import { QueuePage } from '../../pages/QueuePage'; import { http, HttpResponse } from 'msw'; import { server } from '../mocks/server'; // Mock queue data const mockQueueItems = [ { id: 1, printer_id: 1, archive_id: 1, position: 1, status: 'pending', scheduled_time: null, require_previous_success: false, auto_off_after: false, manual_start: false, ams_mapping: null, plate_id: null, bed_levelling: true, flow_cali: false, vibration_cali: true, layer_inspect: false, timelapse: false, use_ams: true, started_at: null, completed_at: null, error_message: null, created_at: '2024-01-01T00:00:00Z', archive_name: 'Test Print 1', archive_thumbnail: '/thumb1.png', printer_name: 'Test Printer', print_time_seconds: 3600, }, { id: 2, printer_id: 1, archive_id: 2, position: 2, status: 'printing', scheduled_time: null, require_previous_success: false, auto_off_after: true, manual_start: false, ams_mapping: null, plate_id: null, bed_levelling: true, flow_cali: false, vibration_cali: true, layer_inspect: false, timelapse: false, use_ams: true, started_at: '2024-01-01T10:00:00Z', completed_at: null, error_message: null, created_at: '2024-01-01T00:00:00Z', archive_name: 'Active Print', archive_thumbnail: '/thumb2.png', printer_name: 'Test Printer', print_time_seconds: 7200, }, { id: 3, printer_id: 1, archive_id: 3, position: 3, status: 'completed', scheduled_time: null, require_previous_success: false, auto_off_after: false, manual_start: false, ams_mapping: null, plate_id: null, bed_levelling: true, flow_cali: false, vibration_cali: true, layer_inspect: false, timelapse: false, use_ams: true, started_at: '2024-01-01T08:00:00Z', completed_at: '2024-01-01T09:00:00Z', error_message: null, created_at: '2024-01-01T00:00:00Z', archive_name: 'Completed Print', archive_thumbnail: '/thumb3.png', printer_name: 'Test Printer', print_time_seconds: 1800, }, ]; const mockPrinters = [ { id: 1, name: 'Test Printer', ip_address: '192.168.1.100', serial_number: 'TESTSERIAL0001', access_code: '12345678', model: 'X1C', enabled: true, created_at: '2024-01-01T00:00:00Z', }, ]; describe('QueuePage', () => { beforeEach(() => { // Mock localStorage.getItem to return expected defaults for queue page vi.mocked(localStorage.getItem).mockImplementation((key: string) => { if (key === 'queue.historyCollapsed') return 'false'; // expanded if (key === 'queue.viewMode') return 'list'; return null; }); // Setup MSW handlers for this test server.use( http.get('/api/v1/queue/', () => { return HttpResponse.json(mockQueueItems); }), http.get('/api/v1/printers/', () => { return HttpResponse.json(mockPrinters); }), http.delete('/api/v1/queue/:id', () => { return HttpResponse.json({ success: true }); }), http.post('/api/v1/queue/:id/cancel', () => { return HttpResponse.json({ success: true }); }), http.post('/api/v1/queue/:id/start', () => { return HttpResponse.json({ success: true }); }), http.post('/api/v1/queue/:id/stop', () => { return HttpResponse.json({ success: true }); }), http.post('/api/v1/queue/reorder', () => { return HttpResponse.json({ success: true }); }) ); }); describe('rendering', () => { it('renders the page title', async () => { render(); await waitFor(() => { expect(screen.getByText('Print Queue')).toBeInTheDocument(); }); }); it('renders the page description', async () => { render(); await waitFor(() => { expect(screen.getByText('Schedule and manage your print jobs')).toBeInTheDocument(); }); }); it('shows summary cards', async () => { render(); await waitFor(() => { // Check for the page title (Print Queue is the h1) expect(screen.getByText('Print Queue')).toBeInTheDocument(); }); }); it('shows filter dropdowns', async () => { render(); await waitFor(() => { expect(screen.getByText('All Printers')).toBeInTheDocument(); expect(screen.getByText('All Status')).toBeInTheDocument(); }); }); }); describe('queue items display', () => { it('shows pending queue items', async () => { render(); await waitFor(() => { expect(screen.getByText('Test Print 1')).toBeInTheDocument(); }); }); it('shows active printing items', async () => { render(); await waitFor(() => { expect(screen.getByText('Active Print')).toBeInTheDocument(); expect(screen.getByText('Currently Printing')).toBeInTheDocument(); }); }); it('shows completed items in history', async () => { render(); await waitFor(() => { expect(screen.getByText('Completed Print')).toBeInTheDocument(); }); }); it('shows status badges', async () => { render(); await waitFor(() => { // Queue items should be visible with status indicators expect(screen.getByText('Test Print 1')).toBeInTheDocument(); }); }); it('shows printer names', async () => { render(); await waitFor(() => { const printerElements = screen.getAllByText('Test Printer'); expect(printerElements.length).toBeGreaterThan(0); }); }); it('renders queue items with plate_id correctly', async () => { // Override with queue items that have plate_id set server.use( http.get('/api/v1/queue/', () => { return HttpResponse.json([ { ...mockQueueItems[0], plate_id: 2, archive_name: 'Multi-plate Print', }, ]); }) ); render(); await waitFor(() => { expect(screen.getByText('Multi-plate Print')).toBeInTheDocument(); }); }); }); describe('empty state', () => { it('shows empty state when no queue items', async () => { server.use( http.get('/api/v1/queue/', () => { return HttpResponse.json([]); }) ); render(); await waitFor(() => { expect(screen.getByText('No prints scheduled')).toBeInTheDocument(); }); }); }); describe('filtering', () => { it('has printer filter options', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('All Printers')).toBeInTheDocument(); }); const printerSelect = screen.getByDisplayValue('All Printers'); await user.click(printerSelect); expect(screen.getByText('Unassigned')).toBeInTheDocument(); }); it('has status filter options', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('All Status')).toBeInTheDocument(); }); const statusSelect = screen.getByDisplayValue('All Status'); await user.click(statusSelect); expect(screen.getByRole('option', { name: 'Pending' })).toBeInTheDocument(); expect(screen.getByRole('option', { name: 'Printing' })).toBeInTheDocument(); expect(screen.getByRole('option', { name: 'Completed' })).toBeInTheDocument(); }); }); describe('queue actions', () => { it('shows edit button for pending items', async () => { render(); await waitFor(() => { expect(screen.getByText('Test Print 1')).toBeInTheDocument(); }); // Find the edit button (Pencil icon) const editButtons = screen.getAllByTitle('Edit'); expect(editButtons.length).toBeGreaterThan(0); }); it('shows cancel button for pending items', async () => { render(); await waitFor(() => { expect(screen.getByText('Test Print 1')).toBeInTheDocument(); }); const cancelButtons = screen.getAllByTitle('Cancel'); expect(cancelButtons.length).toBeGreaterThan(0); }); it('shows stop button for printing items', async () => { render(); await waitFor(() => { expect(screen.getByText('Active Print')).toBeInTheDocument(); }); const stopButtons = screen.getAllByTitle('Stop Print'); expect(stopButtons.length).toBeGreaterThan(0); }); it('shows re-queue button for history items', async () => { render(); await waitFor(() => { expect(screen.getByText('Completed Print')).toBeInTheDocument(); }); const requeueButtons = screen.getAllByTitle('Re-queue'); expect(requeueButtons.length).toBeGreaterThan(0); }); }); describe('clear history', () => { it('shows clear history button when history exists', async () => { render(); await waitFor(() => { expect(screen.getByText('Clear History')).toBeInTheDocument(); }); }); it('opens confirm modal when clicking clear history', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Clear History')).toBeInTheDocument(); }); const clearButton = screen.getByRole('button', { name: /clear history/i }); await user.click(clearButton); await waitFor(() => { expect(screen.getByText(/Are you sure you want to remove all/i)).toBeInTheDocument(); }); }); }); describe('staged items', () => { it('shows staged badge for manual_start items', async () => { server.use( http.get('/api/v1/queue/', () => { return HttpResponse.json([ { ...mockQueueItems[0], manual_start: true, }, ]); }) ); render(); await waitFor(() => { expect(screen.getByText('Staged')).toBeInTheDocument(); }); }); it('shows start button for staged items', async () => { server.use( http.get('/api/v1/queue/', () => { return HttpResponse.json([ { ...mockQueueItems[0], manual_start: true, }, ]); }) ); render(); await waitFor(() => { expect(screen.getByTitle('Start Print')).toBeInTheDocument(); }); }); }); describe('auto power off badge', () => { it('shows power off badge when auto_off_after is true', async () => { render(); await waitFor(() => { expect(screen.getByText('Auto power off')).toBeInTheDocument(); }); }); }); describe('gcode injection badge', () => { it('shows G-code badge when gcode_injection is true', async () => { const itemsWithGcode = mockQueueItems.map((item, i) => i === 0 ? { ...item, gcode_injection: true } : item ); server.use( http.get('/api/v1/queue/', () => HttpResponse.json(itemsWithGcode)), ); render(); await waitFor(() => { expect(screen.getByText('G-code')).toBeInTheDocument(); }); }); it('does not show G-code badge when gcode_injection is false', async () => { render(); await waitFor(() => { expect(screen.getByText('Test Print 1')).toBeInTheDocument(); }); expect(screen.queryByText('G-code')).not.toBeInTheDocument(); }); }); });