ReprintModal.test.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * Tests for the ReprintModal component.
  3. */
  4. import { describe, it, expect, vi, beforeEach } from 'vitest';
  5. import { screen, waitFor } from '@testing-library/react';
  6. import userEvent from '@testing-library/user-event';
  7. import { render } from '../utils';
  8. import { ReprintModal } from '../../components/ReprintModal';
  9. import { http, HttpResponse } from 'msw';
  10. import { server } from '../mocks/server';
  11. const mockPrinters = [
  12. { id: 1, name: 'X1 Carbon', model: 'X1C', ip_address: '192.168.1.100', enabled: true, is_active: true },
  13. { id: 2, name: 'P1S', model: 'P1S', ip_address: '192.168.1.101', enabled: true, is_active: true },
  14. ];
  15. describe('ReprintModal', () => {
  16. const mockOnClose = vi.fn();
  17. const mockOnSuccess = vi.fn();
  18. beforeEach(() => {
  19. vi.clearAllMocks();
  20. server.use(
  21. http.get('/api/v1/printers/', () => {
  22. return HttpResponse.json(mockPrinters);
  23. }),
  24. http.get('/api/v1/archives/:id/plates', () => {
  25. return HttpResponse.json({ is_multi_plate: false, plates: [] });
  26. }),
  27. http.get('/api/v1/archives/:id/filament-requirements', () => {
  28. return HttpResponse.json({ filaments: [] });
  29. }),
  30. http.get('/api/v1/printers/:id/status', () => {
  31. return HttpResponse.json({ connected: true, state: 'IDLE', ams: [], vt_tray: null });
  32. }),
  33. http.post('/api/v1/archives/:id/reprint', () => {
  34. return HttpResponse.json({ success: true });
  35. })
  36. );
  37. });
  38. describe('rendering', () => {
  39. it('renders the modal title', () => {
  40. render(
  41. <ReprintModal
  42. archiveId={1}
  43. archiveName="Benchy"
  44. onClose={mockOnClose}
  45. onSuccess={mockOnSuccess}
  46. />
  47. );
  48. expect(screen.getByText('Re-print')).toBeInTheDocument();
  49. });
  50. it('shows archive name', () => {
  51. render(
  52. <ReprintModal
  53. archiveId={1}
  54. archiveName="Benchy"
  55. onClose={mockOnClose}
  56. onSuccess={mockOnSuccess}
  57. />
  58. );
  59. expect(screen.getByText('Benchy')).toBeInTheDocument();
  60. });
  61. it('shows printer selection buttons', async () => {
  62. render(
  63. <ReprintModal
  64. archiveId={1}
  65. archiveName="Benchy"
  66. onClose={mockOnClose}
  67. onSuccess={mockOnSuccess}
  68. />
  69. );
  70. await waitFor(() => {
  71. expect(screen.getByText('X1 Carbon')).toBeInTheDocument();
  72. expect(screen.getByText('P1S')).toBeInTheDocument();
  73. });
  74. });
  75. });
  76. describe('printer selection', () => {
  77. it('shows active printers as buttons', async () => {
  78. render(
  79. <ReprintModal
  80. archiveId={1}
  81. archiveName="Benchy"
  82. onClose={mockOnClose}
  83. onSuccess={mockOnSuccess}
  84. />
  85. );
  86. await waitFor(() => {
  87. // Printer buttons should be present
  88. expect(screen.getByText('X1 Carbon')).toBeInTheDocument();
  89. });
  90. });
  91. it('shows no printers message when none active', async () => {
  92. server.use(
  93. http.get('/api/v1/printers/', () => {
  94. return HttpResponse.json([]);
  95. })
  96. );
  97. render(
  98. <ReprintModal
  99. archiveId={1}
  100. archiveName="Benchy"
  101. onClose={mockOnClose}
  102. onSuccess={mockOnSuccess}
  103. />
  104. );
  105. await waitFor(() => {
  106. expect(screen.getByText('No active printers available')).toBeInTheDocument();
  107. });
  108. });
  109. });
  110. describe('actions', () => {
  111. it('has print button', () => {
  112. render(
  113. <ReprintModal
  114. archiveId={1}
  115. archiveName="Benchy"
  116. onClose={mockOnClose}
  117. onSuccess={mockOnSuccess}
  118. />
  119. );
  120. expect(screen.getByRole('button', { name: /print/i })).toBeInTheDocument();
  121. });
  122. it('has cancel button', () => {
  123. render(
  124. <ReprintModal
  125. archiveId={1}
  126. archiveName="Benchy"
  127. onClose={mockOnClose}
  128. onSuccess={mockOnSuccess}
  129. />
  130. );
  131. expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
  132. });
  133. it('calls onClose when cancel is clicked', async () => {
  134. const user = userEvent.setup();
  135. render(
  136. <ReprintModal
  137. archiveId={1}
  138. archiveName="Benchy"
  139. onClose={mockOnClose}
  140. onSuccess={mockOnSuccess}
  141. />
  142. );
  143. await user.click(screen.getByRole('button', { name: /cancel/i }));
  144. expect(mockOnClose).toHaveBeenCalled();
  145. });
  146. it('print button is disabled until printer is selected', async () => {
  147. render(
  148. <ReprintModal
  149. archiveId={1}
  150. archiveName="Benchy"
  151. onClose={mockOnClose}
  152. onSuccess={mockOnSuccess}
  153. />
  154. );
  155. // Print button should be disabled initially (no printer selected)
  156. const printButton = screen.getByRole('button', { name: /print/i });
  157. expect(printButton).toBeDisabled();
  158. });
  159. });
  160. });