FeedDirectionModal.test.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * Tests for FeedDirectionModal — the "which hotend?" question a Filament Track
  3. * Switch forces onto every load.
  4. */
  5. import { describe, it, expect, vi, afterEach } from 'vitest';
  6. import { screen, cleanup } from '@testing-library/react';
  7. import userEvent from '@testing-library/user-event';
  8. import { render } from '../utils';
  9. import { FeedDirectionModal } from '../../components/FeedDirectionModal';
  10. import type { ExtruderSlot } from '../../api/client';
  11. const empty: ExtruderSlot = { ams_id: null, slot_id: null, has_filament: false };
  12. describe('FeedDirectionModal', () => {
  13. const defaultProps = {
  14. slotLabel: 'A3',
  15. amsId: 0,
  16. slotId: 2,
  17. extruderSlots: { '0': empty, '1': empty },
  18. onConfirm: vi.fn(),
  19. onCancel: vi.fn(),
  20. };
  21. afterEach(() => {
  22. cleanup();
  23. vi.clearAllMocks();
  24. });
  25. it('names the slot being loaded', () => {
  26. render(<FeedDirectionModal {...defaultProps} />);
  27. expect(screen.getByText('Load A3 to which nozzle?')).toBeInTheDocument();
  28. });
  29. it('will not confirm until a hotend is picked', async () => {
  30. const user = userEvent.setup();
  31. render(<FeedDirectionModal {...defaultProps} />);
  32. // No default selection: an unattended Enter must not feed an arbitrary
  33. // hotend, which is why BambuStudio starts with neither radio checked.
  34. expect(screen.getByRole('button', { name: 'Confirm' })).toBeDisabled();
  35. await user.click(screen.getByRole('button', { name: /Left nozzle/ }));
  36. expect(screen.getByRole('button', { name: 'Confirm' })).toBeEnabled();
  37. });
  38. it('reports the left hotend as extruder 1 and the right as 0', async () => {
  39. const user = userEvent.setup();
  40. const onConfirm = vi.fn();
  41. render(<FeedDirectionModal {...defaultProps} onConfirm={onConfirm} />);
  42. await user.click(screen.getByRole('button', { name: /Left nozzle/ }));
  43. await user.click(screen.getByRole('button', { name: 'Confirm' }));
  44. expect(onConfirm).toHaveBeenCalledWith(1);
  45. await user.click(screen.getByRole('button', { name: /Right nozzle/ }));
  46. await user.click(screen.getByRole('button', { name: 'Confirm' }));
  47. expect(onConfirm).toHaveBeenLastCalledWith(0);
  48. });
  49. it('disables a hotend already fed from this very slot', () => {
  50. render(
  51. <FeedDirectionModal
  52. {...defaultProps}
  53. extruderSlots={{
  54. '0': { ams_id: 0, slot_id: 2, has_filament: true },
  55. '1': empty,
  56. }}
  57. />
  58. );
  59. expect(screen.getByRole('button', { name: /Right nozzle/ })).toBeDisabled();
  60. expect(screen.getByRole('button', { name: /Left nozzle/ })).toBeEnabled();
  61. });
  62. it('leaves both hotends offered when the loaded slot is a different one', () => {
  63. render(
  64. <FeedDirectionModal
  65. {...defaultProps}
  66. extruderSlots={{
  67. '0': { ams_id: 1, slot_id: 2, has_filament: true },
  68. '1': empty,
  69. }}
  70. />
  71. );
  72. expect(screen.getByRole('button', { name: /Right nozzle/ })).toBeEnabled();
  73. });
  74. it('cancels on Escape', async () => {
  75. const onCancel = vi.fn();
  76. const user = userEvent.setup();
  77. render(<FeedDirectionModal {...defaultProps} onCancel={onCancel} />);
  78. await user.keyboard('{Escape}');
  79. expect(onCancel).toHaveBeenCalled();
  80. });
  81. });