PrinterQueueWidget.test.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /**
  2. * Tests for the PrinterQueueWidget component.
  3. *
  4. * This is a compact widget that shows "Next in queue" with the first pending
  5. * item's name and a "+N" badge if there are more items. Returns null when empty.
  6. */
  7. import { describe, it, expect, beforeEach } from 'vitest';
  8. import { screen, waitFor } from '@testing-library/react';
  9. import { render } from '../utils';
  10. import { PrinterQueueWidget } from '../../components/PrinterQueueWidget';
  11. import { http, HttpResponse } from 'msw';
  12. import { server } from '../mocks/server';
  13. const mockQueueItems = [
  14. {
  15. id: 1,
  16. printer_id: 1,
  17. archive_id: 1,
  18. position: 1,
  19. status: 'pending',
  20. archive_name: 'First Print',
  21. printer_name: 'X1 Carbon',
  22. print_time_seconds: 3600,
  23. scheduled_time: null,
  24. },
  25. {
  26. id: 2,
  27. printer_id: 1,
  28. archive_id: 2,
  29. position: 2,
  30. status: 'pending',
  31. archive_name: 'Second Print',
  32. printer_name: 'X1 Carbon',
  33. print_time_seconds: 7200,
  34. scheduled_time: null,
  35. },
  36. ];
  37. describe('PrinterQueueWidget', () => {
  38. beforeEach(() => {
  39. server.use(
  40. http.get('/api/v1/queue/', ({ request }) => {
  41. const url = new URL(request.url);
  42. const printerId = url.searchParams.get('printer_id');
  43. if (printerId === '1') {
  44. return HttpResponse.json(mockQueueItems);
  45. }
  46. return HttpResponse.json([]);
  47. })
  48. );
  49. });
  50. describe('rendering', () => {
  51. it('shows next in queue label', async () => {
  52. render(<PrinterQueueWidget printerId={1} />);
  53. await waitFor(() => {
  54. expect(screen.getByText('Next in queue')).toBeInTheDocument();
  55. });
  56. });
  57. it('shows first pending item name', async () => {
  58. render(<PrinterQueueWidget printerId={1} />);
  59. await waitFor(() => {
  60. expect(screen.getByText('First Print')).toBeInTheDocument();
  61. });
  62. });
  63. it('shows additional items badge when multiple pending', async () => {
  64. render(<PrinterQueueWidget printerId={1} />);
  65. await waitFor(() => {
  66. // Shows "+1" badge since there are 2 items
  67. expect(screen.getByText('+1')).toBeInTheDocument();
  68. });
  69. });
  70. it('shows Waiting for unscheduled items', async () => {
  71. render(<PrinterQueueWidget printerId={1} />);
  72. await waitFor(() => {
  73. expect(screen.getByText('Waiting')).toBeInTheDocument();
  74. });
  75. });
  76. });
  77. describe('empty state', () => {
  78. it('renders nothing when no pending items', async () => {
  79. const { container } = render(<PrinterQueueWidget printerId={999} />);
  80. // Wait for query to resolve
  81. await waitFor(() => {
  82. // Widget returns null when empty, so container should have no visible widget
  83. expect(container.querySelector('a[href="/queue"]')).not.toBeInTheDocument();
  84. });
  85. });
  86. });
  87. describe('single item', () => {
  88. it('does not show badge when only one item', async () => {
  89. server.use(
  90. http.get('/api/v1/queue/', () => {
  91. return HttpResponse.json([mockQueueItems[0]]);
  92. })
  93. );
  94. render(<PrinterQueueWidget printerId={1} />);
  95. await waitFor(() => {
  96. expect(screen.getByText('First Print')).toBeInTheDocument();
  97. });
  98. // Should not have a "+N" badge
  99. expect(screen.queryByText(/^\+\d+$/)).not.toBeInTheDocument();
  100. });
  101. });
  102. describe('link behavior', () => {
  103. it('links to queue page', async () => {
  104. render(<PrinterQueueWidget printerId={1} />);
  105. await waitFor(() => {
  106. const link = screen.getByRole('link');
  107. expect(link).toHaveAttribute('href', '/queue');
  108. });
  109. });
  110. });
  111. });