| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /**
- * 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(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Print Queue')).toBeInTheDocument();
- });
- });
- it('renders the page description', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Schedule and manage your print jobs')).toBeInTheDocument();
- });
- });
- it('shows summary cards', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- // Check for the page title (Print Queue is the h1)
- expect(screen.getByText('Print Queue')).toBeInTheDocument();
- });
- });
- it('shows filter dropdowns', async () => {
- render(<QueuePage />);
- 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(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Test Print 1')).toBeInTheDocument();
- });
- });
- it('shows active printing items', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Active Print')).toBeInTheDocument();
- expect(screen.getByText('Currently Printing')).toBeInTheDocument();
- });
- });
- it('shows completed items in history', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Completed Print')).toBeInTheDocument();
- });
- });
- it('shows status badges', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- // Queue items should be visible with status indicators
- expect(screen.getByText('Test Print 1')).toBeInTheDocument();
- });
- });
- it('shows printer names', async () => {
- render(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('No prints scheduled')).toBeInTheDocument();
- });
- });
- });
- describe('filtering', () => {
- it('has printer filter options', async () => {
- const user = userEvent.setup();
- render(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Clear History')).toBeInTheDocument();
- });
- });
- it('opens confirm modal when clicking clear history', async () => {
- const user = userEvent.setup();
- render(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- 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(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('G-code')).toBeInTheDocument();
- });
- });
- it('does not show G-code badge when gcode_injection is false', async () => {
- render(<QueuePage />);
- await waitFor(() => {
- expect(screen.getByText('Test Print 1')).toBeInTheDocument();
- });
- expect(screen.queryByText('G-code')).not.toBeInTheDocument();
- });
- });
- });
|