| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- /**
- * Tests for the unified PrintModal component.
- *
- * The PrintModal supports three modes:
- * - 'reprint': Immediate print from archive (multi-printer support)
- * - 'add-to-queue': Schedule print to queue (multi-printer support)
- * - 'edit-queue-item': Edit existing queue item (single printer)
- */
- import { describe, it, expect, vi, beforeEach } from 'vitest';
- import { screen, waitFor } from '@testing-library/react';
- import userEvent from '@testing-library/user-event';
- import { render } from '../utils';
- import { PrintModal } from '../../components/PrintModal';
- import { http, HttpResponse } from 'msw';
- import { server } from '../mocks/server';
- import type { PrintQueueItem } from '../../api/client';
- const mockPrinters = [
- { id: 1, name: 'X1 Carbon', model: 'X1C', ip_address: '192.168.1.100', enabled: true, is_active: true },
- { id: 2, name: 'P1S', model: 'P1S', ip_address: '192.168.1.101', enabled: true, is_active: true },
- ];
- const createMockQueueItem = (overrides: Partial<PrintQueueItem> = {}): PrintQueueItem => ({
- id: 1,
- printer_id: 1,
- archive_id: 1,
- position: 1,
- 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,
- status: 'pending',
- started_at: null,
- completed_at: null,
- error_message: null,
- created_at: '2024-01-01T00:00:00Z',
- archive_name: 'Test Print',
- archive_thumbnail: null,
- printer_name: 'Test Printer',
- print_time_seconds: 3600,
- ...overrides,
- });
- describe('PrintModal', () => {
- const mockOnClose = vi.fn();
- const mockOnSuccess = vi.fn();
- beforeEach(() => {
- vi.clearAllMocks();
- server.use(
- http.get('/api/v1/printers/', () => {
- return HttpResponse.json(mockPrinters);
- }),
- http.get('/api/v1/archives/:id/plates', () => {
- return HttpResponse.json({ is_multi_plate: false, plates: [] });
- }),
- http.get('/api/v1/archives/:id/filament-requirements', () => {
- return HttpResponse.json({ filaments: [] });
- }),
- http.get('/api/v1/printers/:id/status', () => {
- return HttpResponse.json({ connected: true, state: 'IDLE', ams: [], vt_tray: [] });
- }),
- http.post('/api/v1/archives/:id/reprint', () => {
- return HttpResponse.json({ success: true });
- }),
- http.post('/api/v1/queue/', () => {
- return HttpResponse.json({ id: 1, status: 'pending' });
- }),
- http.patch('/api/v1/queue/:id', () => {
- return HttpResponse.json({ id: 1, status: 'pending' });
- })
- );
- });
- describe('reprint mode', () => {
- it('renders the modal title', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- expect(screen.getByText('Re-print')).toBeInTheDocument();
- });
- it('shows archive name', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- expect(screen.getByText('Benchy')).toBeInTheDocument();
- });
- it('shows printer selection with checkboxes for multi-select', async () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- await waitFor(() => {
- expect(screen.getByText('X1 Carbon')).toBeInTheDocument();
- expect(screen.getByText('P1S')).toBeInTheDocument();
- });
- });
- it('has print button', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- // Get the submit button specifically (not printer selection buttons)
- const submitButton = screen.getByRole('button', { name: /^print$/i });
- expect(submitButton).toBeInTheDocument();
- });
- it('has cancel button', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
- });
- it('calls onClose when cancel is clicked', async () => {
- const user = userEvent.setup();
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- await user.click(screen.getByRole('button', { name: /cancel/i }));
- expect(mockOnClose).toHaveBeenCalled();
- });
- it('print button is disabled until printer is selected', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- // Get the submit button specifically (not printer selection buttons)
- const printButton = screen.getByRole('button', { name: /^print$/i });
- expect(printButton).toBeDisabled();
- });
- it('shows no printers message when none active', async () => {
- server.use(
- http.get('/api/v1/printers/', () => {
- return HttpResponse.json([]);
- })
- );
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- await waitFor(() => {
- expect(screen.getByText('No active printers available')).toBeInTheDocument();
- });
- });
- it('shows print options toggle', () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- onSuccess={mockOnSuccess}
- />
- );
- expect(screen.getByText('Print Options')).toBeInTheDocument();
- });
- });
- describe('add-to-queue mode', () => {
- it('renders the modal title', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Schedule Print')).toBeInTheDocument();
- });
- it('shows archive name', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Test Print')).toBeInTheDocument();
- });
- it('shows add button', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByRole('button', { name: /add to queue/i })).toBeInTheDocument();
- });
- it('shows cancel button', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
- });
- it('shows Queue Only option', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Queue Only')).toBeInTheDocument();
- });
- it('shows power off option', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText(/power off/i)).toBeInTheDocument();
- });
- it('shows schedule options', () => {
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('ASAP')).toBeInTheDocument();
- expect(screen.getByText('Scheduled')).toBeInTheDocument();
- });
- it('calls onClose when cancel is clicked', async () => {
- const user = userEvent.setup();
- render(
- <PrintModal
- mode="add-to-queue"
- archiveId={1}
- archiveName="Test Print"
- onClose={mockOnClose}
- />
- );
- await user.click(screen.getByRole('button', { name: /cancel/i }));
- expect(mockOnClose).toHaveBeenCalled();
- });
- });
- describe('edit-queue-item mode', () => {
- it('renders the modal title', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Edit Queue Item')).toBeInTheDocument();
- });
- it('shows save button', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
- });
- it('shows cancel button', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
- });
- it('shows print options toggle', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Print Options')).toBeInTheDocument();
- });
- it('shows Queue Only option', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText('Queue Only')).toBeInTheDocument();
- });
- it('shows power off option', () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- expect(screen.getByText(/power off/i)).toBeInTheDocument();
- });
- it('calls onClose when cancel button is clicked', async () => {
- const user = userEvent.setup();
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- const cancelButton = screen.getByRole('button', { name: /cancel/i });
- await user.click(cancelButton);
- expect(mockOnClose).toHaveBeenCalled();
- });
- it('shows printer selector for single selection', async () => {
- const item = createMockQueueItem();
- render(
- <PrintModal
- mode="edit-queue-item"
- archiveId={1}
- archiveName="Test Print"
- queueItem={item}
- onClose={mockOnClose}
- />
- );
- // PrinterSelector shows printer names directly
- await waitFor(() => {
- expect(screen.getByText('P1S')).toBeInTheDocument();
- });
- });
- });
- describe('multi-printer selection', () => {
- it('shows select all button when multiple printers available', async () => {
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- />
- );
- await waitFor(() => {
- expect(screen.getByText('Select all')).toBeInTheDocument();
- });
- });
- it('shows selected count when multiple printers selected', async () => {
- const user = userEvent.setup();
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- />
- );
- await waitFor(() => {
- expect(screen.getByText('Select all')).toBeInTheDocument();
- });
- await user.click(screen.getByText('Select all'));
- await waitFor(() => {
- expect(screen.getByText(/2 printers selected/)).toBeInTheDocument();
- });
- });
- it('updates button text when multiple printers selected', async () => {
- const user = userEvent.setup();
- render(
- <PrintModal
- mode="reprint"
- archiveId={1}
- archiveName="Benchy"
- onClose={mockOnClose}
- />
- );
- await waitFor(() => {
- expect(screen.getByText('Select all')).toBeInTheDocument();
- });
- await user.click(screen.getByText('Select all'));
- await waitFor(() => {
- expect(screen.getByRole('button', { name: /print to 2 printers/i })).toBeInTheDocument();
- });
- });
- });
- });
|