/**
* 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();
});
});
});