InventoryPageGroupRestore.test.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /**
  2. * Restore on an archived spool inside an expanded group row of the table.
  3. * The group row passed a no-op to its members, so the button did nothing.
  4. */
  5. import { describe, it, expect, beforeEach, afterEach } from 'vitest';
  6. import { screen, waitFor, fireEvent } from '@testing-library/react';
  7. import { render } from '../utils';
  8. import InventoryPageRouter from '../../pages/InventoryPage';
  9. import { http, HttpResponse } from 'msw';
  10. import { server } from '../mocks/server';
  11. const baseSettings = {
  12. auto_archive: true,
  13. save_thumbnails: true,
  14. capture_finish_photo: true,
  15. default_filament_cost: 25.0,
  16. currency: 'USD',
  17. energy_cost_per_kwh: 0.15,
  18. energy_tracking_mode: 'total',
  19. spoolman_enabled: false,
  20. spoolman_url: '',
  21. spoolman_sync_mode: 'auto',
  22. spoolman_disable_weight_sync: false,
  23. spoolman_report_partial_usage: true,
  24. check_updates: true,
  25. check_printer_firmware: true,
  26. include_beta_updates: false,
  27. language: 'en',
  28. notification_language: 'en',
  29. bed_cooled_threshold: 35,
  30. ams_humidity_good: 40,
  31. ams_humidity_fair: 60,
  32. ams_temp_good: 28,
  33. ams_temp_fair: 35,
  34. ams_history_retention_days: 30,
  35. per_printer_mapping_expanded: false,
  36. date_format: 'system',
  37. time_format: 'system',
  38. default_printer_id: null,
  39. dark_style: 'classic',
  40. dark_background: 'neutral',
  41. dark_accent: 'green',
  42. light_style: 'classic',
  43. light_background: 'neutral',
  44. light_accent: 'green',
  45. ftp_retry_enabled: true,
  46. ftp_retry_count: 3,
  47. ftp_retry_delay: 2,
  48. ftp_timeout: 30,
  49. mqtt_enabled: false,
  50. mqtt_broker: '',
  51. mqtt_port: 1883,
  52. mqtt_username: '',
  53. mqtt_password: '',
  54. mqtt_topic_prefix: 'bambuddy',
  55. mqtt_use_tls: false,
  56. external_url: '',
  57. ha_enabled: false,
  58. ha_url: '',
  59. ha_token: '',
  60. ha_url_from_env: false,
  61. ha_token_from_env: false,
  62. ha_env_managed: false,
  63. library_disk_warning_gb: 5.0,
  64. camera_view_mode: 'window',
  65. preferred_slicer: 'bambu_studio',
  66. prometheus_enabled: false,
  67. prometheus_token: '',
  68. low_stock_threshold: 20.0,
  69. };
  70. const archivedSpool = {
  71. // Archived spool: 500 g consumed. Pre-fix this consumption disappeared
  72. // from "Total Consumed" the moment the spool was archived (#1390 fb).
  73. id: 2,
  74. material: 'PETG',
  75. subtype: null,
  76. brand: 'eSun',
  77. color_name: 'Blue',
  78. rgba: '0000FFFF',
  79. label_weight: 1000,
  80. core_weight: 250,
  81. weight_used: 500,
  82. weight_used_baseline: 0,
  83. slicer_filament: null,
  84. slicer_filament_name: null,
  85. nozzle_temp_min: null,
  86. nozzle_temp_max: null,
  87. note: null,
  88. added_full: null,
  89. last_used: null,
  90. encode_time: null,
  91. tag_uid: null,
  92. tray_uuid: null,
  93. data_origin: null,
  94. tag_type: null,
  95. archived_at: '2026-04-01T00:00:00Z',
  96. created_at: '2025-01-02T00:00:00Z',
  97. updated_at: '2025-01-02T00:00:00Z',
  98. k_profiles: [],
  99. cost_per_kg: null,
  100. last_scale_weight: null,
  101. last_weighed_at: null,
  102. };
  103. describe('InventoryPage — restore inside a group row', () => {
  104. const restored: number[] = [];
  105. beforeEach(() => {
  106. restored.length = 0;
  107. server.use(
  108. http.get('/api/v1/settings/', () => HttpResponse.json(baseSettings)),
  109. http.get('/api/v1/inventory/spools', () =>
  110. // Only unused, unassigned spools are grouped.
  111. HttpResponse.json([
  112. { ...archivedSpool, weight_used: 0 },
  113. { ...archivedSpool, id: 3, weight_used: 0 },
  114. ]),
  115. ),
  116. http.get('/api/v1/inventory/assignments', () => HttpResponse.json([])),
  117. http.get('/api/v1/spoolman/settings', () => HttpResponse.json({ spoolman_enabled: 'false' })),
  118. http.post('/api/v1/inventory/spools/:id/restore', ({ params }) => {
  119. restored.push(Number(params.id));
  120. return HttpResponse.json({ ...archivedSpool, id: Number(params.id), archived_at: null });
  121. }),
  122. );
  123. });
  124. afterEach(() => {
  125. localStorage.removeItem('bambuddy-inventory-group');
  126. });
  127. it('restores the spool whose button was clicked', async () => {
  128. render(<InventoryPageRouter />);
  129. fireEvent.click(await screen.findByRole('button', { name: 'Archived' }));
  130. fireEvent.click(screen.getByRole('button', { name: 'Group' }));
  131. const header = await screen.findByText('#2, #3');
  132. fireEvent.click(header.closest('tr')!);
  133. const buttons = await screen.findAllByTitle('Restore');
  134. fireEvent.click(buttons[0]);
  135. await waitFor(() => expect(restored).toHaveLength(1));
  136. expect([2, 3]).toContain(restored[0]);
  137. });
  138. });