PurgeOldFilesModal.test.tsx 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /**
  2. * Tests for the admin Purge Old Files modal (#1008).
  3. *
  4. * Covers: preview round-trip populates count + size + sample filenames,
  5. * confirm button stays disabled until preview returns count > 0, confirm
  6. * round-trip posts the correct payload and closes the modal.
  7. */
  8. import { describe, it, expect, afterEach, vi } from 'vitest';
  9. import { screen, waitFor } from '@testing-library/react';
  10. import userEvent from '@testing-library/user-event';
  11. import { http, HttpResponse } from 'msw';
  12. import { render } from '../utils';
  13. import { server } from '../mocks/server';
  14. import { PurgeOldFilesModal } from '../../components/PurgeOldFilesModal';
  15. afterEach(() => server.resetHandlers());
  16. describe('PurgeOldFilesModal', () => {
  17. it('displays preview counts and sample filenames returned by the backend', async () => {
  18. server.use(
  19. http.get('*/library/purge/preview', () =>
  20. HttpResponse.json({
  21. count: 3,
  22. total_bytes: 5_242_880,
  23. sample_filenames: ['a.3mf', 'b.3mf', 'c.3mf'],
  24. older_than_days: 90,
  25. include_never_printed: true,
  26. }),
  27. ),
  28. );
  29. render(<PurgeOldFilesModal onClose={vi.fn()} />);
  30. await screen.findByText(/3 files/i);
  31. expect(screen.getByText('a.3mf')).toBeInTheDocument();
  32. expect(screen.getByText('b.3mf')).toBeInTheDocument();
  33. expect(screen.getByText('c.3mf')).toBeInTheDocument();
  34. });
  35. it('leaves the confirm button disabled when the preview returns zero matches', async () => {
  36. server.use(
  37. http.get('*/library/purge/preview', () =>
  38. HttpResponse.json({
  39. count: 0,
  40. total_bytes: 0,
  41. sample_filenames: [],
  42. older_than_days: 90,
  43. include_never_printed: true,
  44. }),
  45. ),
  46. );
  47. render(<PurgeOldFilesModal onClose={vi.fn()} />);
  48. await screen.findByText(/0 files/i);
  49. // The confirm button label contains the count; it should be disabled.
  50. const confirm = screen.getByRole('button', { name: /Move 0 to trash/i });
  51. expect(confirm).toBeDisabled();
  52. });
  53. it('invokes the purge endpoint and closes the modal on confirm', async () => {
  54. let purgeBody: { older_than_days: number; include_never_printed: boolean } | null = null;
  55. server.use(
  56. http.get('*/library/purge/preview', () =>
  57. HttpResponse.json({
  58. count: 2,
  59. total_bytes: 1024,
  60. sample_filenames: ['x.3mf', 'y.3mf'],
  61. older_than_days: 90,
  62. include_never_printed: true,
  63. }),
  64. ),
  65. http.post('*/library/purge', async ({ request }) => {
  66. purgeBody = (await request.json()) as typeof purgeBody;
  67. return HttpResponse.json({ moved_to_trash: 2 });
  68. }),
  69. );
  70. const onClose = vi.fn();
  71. render(<PurgeOldFilesModal onClose={onClose} />);
  72. await screen.findByText(/2 files/i);
  73. await userEvent.click(screen.getByRole('button', { name: /Move 2 to trash/i }));
  74. await waitFor(() => expect(onClose).toHaveBeenCalled());
  75. expect(purgeBody).toEqual({ older_than_days: 90, include_never_printed: true });
  76. });
  77. });