BulkEditSpoolsModal.test.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /**
  2. * Bulk edit: the field list must only offer fields the active inventory
  3. * backend can actually store (#2870).
  4. *
  5. * In Spoolman mode a spool has no material number, category or low-stock
  6. * override of its own — SpoolmanInventoryUpdate has no such fields, so the
  7. * payload dumps to {} and the route answers 400 "update must include at
  8. * least one field". The user ticks a box, types a value, clicks Apply and
  9. * gets an error. Filtering the list is the fix.
  10. */
  11. import React from 'react';
  12. import { describe, it, expect, vi } from 'vitest';
  13. import { screen } from '@testing-library/react';
  14. import { render } from '../utils';
  15. import { BulkEditSpoolsModal } from '../../components/BulkEditSpoolsModal';
  16. vi.mock('react-i18next', () => ({
  17. useTranslation: () => ({
  18. t: (key: string) => key,
  19. }),
  20. }));
  21. const baseProps = {
  22. isOpen: true,
  23. selectedCount: 3,
  24. isPending: false,
  25. availableLocations: [],
  26. availableMaterials: [],
  27. availableSubtypes: [],
  28. availableBrands: [],
  29. availableCategories: [],
  30. availableMaterialNumbers: [],
  31. availableSlicerFilaments: [],
  32. availableSlicerFilamentNames: [],
  33. onClose: vi.fn(),
  34. onApply: vi.fn(),
  35. };
  36. const INTERNAL_ONLY = [
  37. 'inventory.materialNumber',
  38. 'inventory.category',
  39. 'inventory.lowStockThresholdOverride',
  40. ];
  41. describe('BulkEditSpoolsModal field list', () => {
  42. it('offers the internal-only fields in internal mode', () => {
  43. render(<BulkEditSpoolsModal {...baseProps} spoolmanMode={false} />);
  44. for (const key of INTERNAL_ONLY) {
  45. expect(screen.getByText(key)).toBeTruthy();
  46. }
  47. });
  48. it('hides every field Spoolman cannot store in Spoolman mode', () => {
  49. render(<BulkEditSpoolsModal {...baseProps} spoolmanMode={true} />);
  50. for (const key of INTERNAL_ONLY) {
  51. expect(screen.queryByText(key)).toBeNull();
  52. }
  53. // The fields Spoolman does accept stay.
  54. expect(screen.getByText('inventory.material')).toBeTruthy();
  55. expect(screen.getByText('inventory.note')).toBeTruthy();
  56. expect(screen.getByText('inventory.costPerKg')).toBeTruthy();
  57. });
  58. it('defaults to internal mode when the prop is omitted', () => {
  59. render(<BulkEditSpoolsModal {...baseProps} />);
  60. expect(screen.getByText('inventory.materialNumber')).toBeTruthy();
  61. });
  62. });