HeaterHistoryModal.test.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * Tests for the HeaterHistoryModal component.
  3. */
  4. import { describe, it, expect, vi, beforeEach } from 'vitest';
  5. import { screen, waitFor, fireEvent } from '@testing-library/react';
  6. import { render } from '../utils';
  7. import { HeaterHistoryModal } from '../../components/HeaterHistoryModal';
  8. import { api } from '../../api/client';
  9. vi.mock('../../api/client', () => ({
  10. api: {
  11. getPrinterSensorHistory: vi.fn(),
  12. getSettings: vi.fn().mockResolvedValue({}),
  13. updateSettings: vi.fn().mockResolvedValue({}),
  14. },
  15. }));
  16. vi.mock('recharts', () => ({
  17. LineChart: ({ children }: { children: React.ReactNode }) => <div data-testid="line-chart">{children}</div>,
  18. Line: () => null,
  19. XAxis: () => null,
  20. YAxis: () => null,
  21. CartesianGrid: () => null,
  22. Tooltip: () => null,
  23. ResponsiveContainer: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  24. Legend: () => null,
  25. }));
  26. const mockResponse = {
  27. printer_id: 1,
  28. series: [
  29. {
  30. sensor_kind: 'nozzle' as const,
  31. data: [
  32. { recorded_at: '2024-12-11T10:00:00Z', value: 210, target: 220 },
  33. { recorded_at: '2024-12-11T10:05:00Z', value: 215, target: 220 },
  34. { recorded_at: '2024-12-11T10:10:00Z', value: 220, target: 220 },
  35. ],
  36. min_value: 210,
  37. max_value: 220,
  38. avg_value: 215,
  39. },
  40. {
  41. sensor_kind: 'bed' as const,
  42. data: [
  43. { recorded_at: '2024-12-11T10:00:00Z', value: 55, target: 60 },
  44. { recorded_at: '2024-12-11T10:05:00Z', value: 60, target: 60 },
  45. ],
  46. min_value: 55,
  47. max_value: 60,
  48. avg_value: 57.5,
  49. },
  50. {
  51. sensor_kind: 'chamber' as const,
  52. data: [],
  53. min_value: null,
  54. max_value: null,
  55. avg_value: null,
  56. },
  57. ],
  58. };
  59. const defaultProps = {
  60. isOpen: true,
  61. onClose: vi.fn(),
  62. printerId: 1,
  63. printerName: 'Test Printer',
  64. initialKind: 'nozzle' as const,
  65. availableKinds: ['nozzle', 'bed', 'chamber'] as const,
  66. };
  67. describe('HeaterHistoryModal', () => {
  68. beforeEach(() => {
  69. vi.clearAllMocks();
  70. (api.getPrinterSensorHistory as ReturnType<typeof vi.fn>).mockResolvedValue(mockResponse);
  71. });
  72. it('renders nothing when closed', () => {
  73. render(<HeaterHistoryModal {...defaultProps} isOpen={false} />);
  74. expect(screen.queryByText(/Heater History/i)).not.toBeInTheDocument();
  75. });
  76. it('renders title + printer name when open', async () => {
  77. render(<HeaterHistoryModal {...defaultProps} />);
  78. await waitFor(() => {
  79. expect(screen.getByText(/Heater History/i)).toBeInTheDocument();
  80. expect(screen.getByText('Test Printer')).toBeInTheDocument();
  81. });
  82. });
  83. it('shows current nozzle value from last data point', async () => {
  84. render(<HeaterHistoryModal {...defaultProps} />);
  85. await waitFor(() => {
  86. // current=220, target=220, max=220 — multiple matches are expected.
  87. expect(screen.getAllByText(/220°C/).length).toBeGreaterThan(0);
  88. });
  89. });
  90. it('switches series when bed mode button clicked', async () => {
  91. render(<HeaterHistoryModal {...defaultProps} />);
  92. await waitFor(() => {
  93. expect(screen.getByText('Test Printer')).toBeInTheDocument();
  94. });
  95. const bedButtons = screen.getAllByText(/^Bed$/);
  96. fireEvent.click(bedButtons[0]);
  97. await waitFor(() => {
  98. // 60 = current bed value (and max, and target).
  99. expect(screen.getAllByText(/60°C/).length).toBeGreaterThan(0);
  100. });
  101. });
  102. it('shows empty state when series has no data', async () => {
  103. render(<HeaterHistoryModal {...defaultProps} initialKind="chamber" />);
  104. await waitFor(() => {
  105. expect(screen.getByText(/No data recorded yet/i)).toBeInTheDocument();
  106. });
  107. });
  108. it('close button triggers onClose', async () => {
  109. const onClose = vi.fn();
  110. render(<HeaterHistoryModal {...defaultProps} onClose={onClose} />);
  111. await waitFor(() => {
  112. expect(screen.getByText('Test Printer')).toBeInTheDocument();
  113. });
  114. fireEvent.click(screen.getByLabelText(/Close/i));
  115. expect(onClose).toHaveBeenCalled();
  116. });
  117. });