PrintModalEditSave.test.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * Saving an edited queue item reports and closes once.
  3. *
  4. * The update mutation toasted, called onSuccess and closed the dialog on its
  5. * own, and the submit handler then did all three again: two "Queue item
  6. * updated" toasts, two closes, and on a failure two error toasts.
  7. */
  8. import { screen, waitFor } from '@testing-library/react';
  9. import userEvent from '@testing-library/user-event';
  10. import { http, HttpResponse } from 'msw';
  11. import { describe, it, expect, vi, beforeEach } from 'vitest';
  12. import { render } from '../utils';
  13. import { server } from '../mocks/server';
  14. const mockShowToast = vi.fn();
  15. vi.mock('../../contexts/ToastContext', async (importOriginal) => {
  16. const actual = await importOriginal<typeof import('../../contexts/ToastContext')>();
  17. return { ...actual, useToast: () => ({ showToast: mockShowToast }) };
  18. });
  19. import { PrintModal } from '../../components/PrintModal';
  20. const queueItem = {
  21. id: 9, printer_id: 1, archive_id: 1, position: 1, scheduled_time: null, require_previous_success: false,
  22. auto_off_after: false, gcode_injection: false, manual_start: false, ams_mapping: null, plate_id: null,
  23. bed_levelling: true, flow_cali: false, vibration_cali: true, layer_inspect: false, timelapse: false,
  24. use_ams: true, status: 'pending', started_at: null, completed_at: null, error_message: null,
  25. created_at: '2024-01-01T00:00:00Z', archive_name: 'Edit Print', archive_thumbnail: null,
  26. printer_name: 'X1 Carbon', print_time_seconds: 3600, batch_id: null, batch_name: null,
  27. };
  28. function renderModal(onClose = vi.fn(), onSuccess = vi.fn()) {
  29. render(
  30. <PrintModal
  31. mode="edit-queue-item"
  32. archiveId={1}
  33. archiveName="Edit Print"
  34. queueItem={queueItem as never}
  35. onClose={onClose}
  36. onSuccess={onSuccess}
  37. />,
  38. );
  39. return { onClose, onSuccess };
  40. }
  41. describe('PrintModal edit-queue-item save', () => {
  42. beforeEach(() => {
  43. vi.clearAllMocks();
  44. server.use(
  45. http.get('/api/v1/printers/', () =>
  46. HttpResponse.json([{ id: 1, name: 'X1 Carbon', model: 'X1C', ip_address: '192.168.1.100', enabled: true, is_active: true }]),
  47. ),
  48. http.get('/api/v1/printers/:id/status', () => HttpResponse.json({ connected: true, state: 'IDLE', ams: [], vt_tray: [] })),
  49. http.get('/api/v1/archives/:id', () => HttpResponse.json({ id: 1, sliced_for_model: null })),
  50. http.get('/api/v1/archives/:id/plates', () => HttpResponse.json({ is_multi_plate: false, plates: [] })),
  51. http.get('/api/v1/archives/:id/filament-requirements', () => HttpResponse.json({ filaments: [] })),
  52. );
  53. });
  54. it('toasts, reports success and closes once', async () => {
  55. server.use(http.patch('/api/v1/queue/:id', () => HttpResponse.json({ id: 9, status: 'pending' })));
  56. const user = userEvent.setup();
  57. const { onClose, onSuccess } = renderModal();
  58. await user.click(await screen.findByRole('button', { name: /save/i }));
  59. await waitFor(() => expect(onClose).toHaveBeenCalled());
  60. // Let anything still queued behind the first close run before counting.
  61. await new Promise((r) => setTimeout(r, 50));
  62. expect(mockShowToast).toHaveBeenCalledTimes(1);
  63. expect(onSuccess).toHaveBeenCalledTimes(1);
  64. expect(onClose).toHaveBeenCalledTimes(1);
  65. });
  66. it('shows one error toast on a failure and stays open', async () => {
  67. server.use(
  68. http.patch('/api/v1/queue/:id', () => HttpResponse.json({ detail: 'Queue item is printing' }, { status: 409 })),
  69. );
  70. const user = userEvent.setup();
  71. const { onClose } = renderModal();
  72. await user.click(await screen.findByRole('button', { name: /save/i }));
  73. await waitFor(() => expect(mockShowToast).toHaveBeenCalled());
  74. await new Promise((r) => setTimeout(r, 50));
  75. expect(mockShowToast).toHaveBeenCalledTimes(1);
  76. expect(mockShowToast.mock.calls[0][1]).toBe('error');
  77. expect(onClose).not.toHaveBeenCalled();
  78. });
  79. });