PrintersPageSpeed.test.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /**
  2. * Tests for the print speed control feature on the PrintersPage.
  3. *
  4. * The printer-card refactor in #1661 replaced the visible "100%" / "50%"
  5. * speed badge with an icon-only Gauge button. These tests now target the
  6. * button via data-testid="speed-control" instead of the percentage text.
  7. * The dropdown still shows the same translated labels (Silent (50%),
  8. * Standard (100%), Sport (124%), Ludicrous (166%)).
  9. */
  10. import { describe, it, expect, beforeEach } from 'vitest';
  11. import { screen, waitFor } from '@testing-library/react';
  12. import userEvent from '@testing-library/user-event';
  13. import { render } from '../utils';
  14. import { PrintersPage } from '../../pages/PrintersPage';
  15. import { http, HttpResponse } from 'msw';
  16. import { server } from '../mocks/server';
  17. const mockPrinters = [
  18. {
  19. id: 1,
  20. name: 'X1 Carbon',
  21. ip_address: '192.168.1.100',
  22. serial_number: '00M09A350100001',
  23. access_code: '12345678',
  24. model: 'X1C',
  25. enabled: true,
  26. nozzle_diameter: 0.4,
  27. nozzle_type: 'hardened_steel',
  28. location: 'Workshop',
  29. auto_archive: true,
  30. created_at: '2024-01-01T00:00:00Z',
  31. updated_at: '2024-01-01T00:00:00Z',
  32. },
  33. ];
  34. const mockPrintingStatus = {
  35. connected: true,
  36. state: 'RUNNING',
  37. progress: 42,
  38. layer_num: 10,
  39. total_layers: 100,
  40. temperatures: {
  41. nozzle: 220,
  42. bed: 60,
  43. chamber: 35,
  44. },
  45. remaining_time: 3600,
  46. filename: 'test_print.3mf',
  47. wifi_signal: -50,
  48. vt_tray: [],
  49. speed_level: 2,
  50. };
  51. const mockIdleStatus = {
  52. connected: true,
  53. state: 'IDLE',
  54. progress: 0,
  55. layer_num: 0,
  56. total_layers: 0,
  57. temperatures: {
  58. nozzle: 25,
  59. bed: 25,
  60. chamber: 25,
  61. },
  62. remaining_time: 0,
  63. filename: null,
  64. wifi_signal: -50,
  65. vt_tray: [],
  66. speed_level: 2,
  67. };
  68. describe('PrintersPage - Print Speed Control', () => {
  69. beforeEach(() => {
  70. server.use(
  71. http.get('/api/v1/printers/', () => {
  72. return HttpResponse.json(mockPrinters);
  73. }),
  74. http.get('/api/v1/queue/', () => {
  75. return HttpResponse.json([]);
  76. })
  77. );
  78. });
  79. describe('speed control button', () => {
  80. it('renders and is enabled when printer is printing', async () => {
  81. server.use(
  82. http.get('/api/v1/printers/:id/status', () => {
  83. return HttpResponse.json(mockPrintingStatus);
  84. })
  85. );
  86. render(<PrintersPage />);
  87. await waitFor(() => {
  88. const button = screen.getByTestId('speed-control');
  89. expect(button).toBeInTheDocument();
  90. expect(button).toBeEnabled();
  91. });
  92. });
  93. it('is disabled when printer is idle', async () => {
  94. server.use(
  95. http.get('/api/v1/printers/:id/status', () => {
  96. return HttpResponse.json(mockIdleStatus);
  97. })
  98. );
  99. render(<PrintersPage />);
  100. await waitFor(() => {
  101. const button = screen.getByTestId('speed-control');
  102. expect(button).toBeDisabled();
  103. });
  104. });
  105. });
  106. describe('speed dropdown menu', () => {
  107. it('opens speed menu on click when printing', async () => {
  108. const user = userEvent.setup();
  109. server.use(
  110. http.get('/api/v1/printers/:id/status', () => {
  111. return HttpResponse.json(mockPrintingStatus);
  112. })
  113. );
  114. render(<PrintersPage />);
  115. await waitFor(() => {
  116. expect(screen.getByTestId('speed-control')).toBeEnabled();
  117. });
  118. await user.click(screen.getByTestId('speed-control'));
  119. await waitFor(() => {
  120. expect(screen.getByText('Silent (50%)')).toBeInTheDocument();
  121. expect(screen.getByText('Standard (100%)')).toBeInTheDocument();
  122. expect(screen.getByText('Sport (124%)')).toBeInTheDocument();
  123. expect(screen.getByText('Ludicrous (166%)')).toBeInTheDocument();
  124. });
  125. });
  126. it('displays all four speed options in the dropdown', async () => {
  127. const user = userEvent.setup();
  128. server.use(
  129. http.get('/api/v1/printers/:id/status', () => {
  130. return HttpResponse.json(mockPrintingStatus);
  131. })
  132. );
  133. render(<PrintersPage />);
  134. await waitFor(() => {
  135. expect(screen.getByTestId('speed-control')).toBeEnabled();
  136. });
  137. await user.click(screen.getByTestId('speed-control'));
  138. await waitFor(() => {
  139. const options = [
  140. screen.getByText('Silent (50%)'),
  141. screen.getByText('Standard (100%)'),
  142. screen.getByText('Sport (124%)'),
  143. screen.getByText('Ludicrous (166%)'),
  144. ];
  145. expect(options).toHaveLength(4);
  146. options.forEach((opt) => expect(opt).toBeInTheDocument());
  147. });
  148. });
  149. it('calls the API with the correct mode when a speed option is selected', async () => {
  150. const user = userEvent.setup();
  151. let capturedMode: number | null = null;
  152. server.use(
  153. http.get('/api/v1/printers/:id/status', () => {
  154. return HttpResponse.json(mockPrintingStatus);
  155. }),
  156. http.post('/api/v1/printers/:id/print-speed', async ({ request }) => {
  157. const url = new URL(request.url);
  158. capturedMode = Number(url.searchParams.get('mode'));
  159. return HttpResponse.json({ success: true, message: 'Speed set' });
  160. })
  161. );
  162. render(<PrintersPage />);
  163. await waitFor(() => {
  164. expect(screen.getByTestId('speed-control')).toBeEnabled();
  165. });
  166. await user.click(screen.getByTestId('speed-control'));
  167. await waitFor(() => {
  168. expect(screen.getByText('Sport (124%)')).toBeInTheDocument();
  169. });
  170. await user.click(screen.getByText('Sport (124%)'));
  171. await waitFor(() => {
  172. expect(capturedMode).toBe(3);
  173. });
  174. });
  175. it('closes the dropdown after selecting a speed option', async () => {
  176. const user = userEvent.setup();
  177. server.use(
  178. http.get('/api/v1/printers/:id/status', () => {
  179. return HttpResponse.json(mockPrintingStatus);
  180. }),
  181. http.post('/api/v1/printers/:id/print-speed', () => {
  182. return HttpResponse.json({ success: true, message: 'Speed set' });
  183. })
  184. );
  185. render(<PrintersPage />);
  186. await waitFor(() => {
  187. expect(screen.getByTestId('speed-control')).toBeEnabled();
  188. });
  189. await user.click(screen.getByTestId('speed-control'));
  190. await waitFor(() => {
  191. expect(screen.getByText('Silent (50%)')).toBeInTheDocument();
  192. });
  193. await user.click(screen.getByText('Silent (50%)'));
  194. await waitFor(() => {
  195. expect(screen.queryByText('Silent (50%)')).not.toBeInTheDocument();
  196. });
  197. });
  198. it.each([
  199. { mode: 1, label: 'Silent (50%)' },
  200. { mode: 2, label: 'Standard (100%)' },
  201. { mode: 3, label: 'Sport (124%)' },
  202. { mode: 4, label: 'Ludicrous (166%)' },
  203. ])('selecting $label sends mode=$mode', async ({ mode, label }) => {
  204. const user = userEvent.setup();
  205. let capturedMode: number | null = null;
  206. server.use(
  207. http.get('/api/v1/printers/:id/status', () => {
  208. return HttpResponse.json({ ...mockPrintingStatus, speed_level: 2 });
  209. }),
  210. http.post('/api/v1/printers/:id/print-speed', async ({ request }) => {
  211. const url = new URL(request.url);
  212. capturedMode = Number(url.searchParams.get('mode'));
  213. return HttpResponse.json({ success: true, message: 'Speed set' });
  214. })
  215. );
  216. render(<PrintersPage />);
  217. await waitFor(() => {
  218. expect(screen.getByTestId('speed-control')).toBeEnabled();
  219. });
  220. await user.click(screen.getByTestId('speed-control'));
  221. await waitFor(() => {
  222. expect(screen.getByText(label)).toBeInTheDocument();
  223. });
  224. await user.click(screen.getByText(label));
  225. await waitFor(() => {
  226. expect(capturedMode).toBe(mode);
  227. });
  228. });
  229. });
  230. });