import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { screen, fireEvent } from '@testing-library/react'; import { render } from '../utils'; import { SpoolmanFilamentPicker } from '../../components/spool-form/SpoolmanFilamentPicker'; import type { SpoolmanFilamentEntry } from '../../api/client'; vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string, fallback?: string) => fallback ?? key, }), })); const FILAMENTS: SpoolmanFilamentEntry[] = [ { id: 1, name: 'PLA Basic', material: 'PLA', color_hex: 'FF0000', color_name: 'Red', weight: 1000, spool_weight: 196, vendor: { id: 1, name: 'Bambu Lab' }, }, { id: 2, name: 'PETG', material: 'PETG', color_hex: '00FF00', color_name: 'Green', weight: 1000, spool_weight: null, vendor: { id: 2, name: 'Bambu Lab' }, }, { id: 3, name: 'ABS Basic', material: 'ABS', color_hex: null, color_name: null, weight: 1000, spool_weight: 250, vendor: null, }, ]; function openDropdown() { const trigger = screen.getByRole('button', { name: /spoolman/i }); fireEvent.click(trigger); } describe('SpoolmanFilamentPicker', () => { it('renders the trigger button with catalog label when nothing selected', () => { render( ); expect(screen.getByText('inventory.spoolmanFilamentCatalog')).toBeTruthy(); }); it('shows all filaments when dropdown is opened', () => { render( ); openDropdown(); expect(screen.getByText(/Bambu Lab — PLA Basic/)).toBeTruthy(); expect(screen.getByText(/Bambu Lab — PETG/)).toBeTruthy(); expect(screen.getByText(/ABS Basic/)).toBeTruthy(); }); it('filters by search term (material)', () => { render( ); openDropdown(); const searchInput = screen.getByPlaceholderText('inventory.pickFromSpoolmanCatalog'); fireEvent.change(searchInput, { target: { value: 'PETG' } }); expect(screen.getAllByText(/PETG/).length).toBeGreaterThan(0); expect(screen.queryByText(/PLA Basic/)).toBeNull(); expect(screen.queryByText(/ABS Basic/)).toBeNull(); }); it('filters by vendor name', () => { render( ); openDropdown(); const searchInput = screen.getByPlaceholderText('inventory.pickFromSpoolmanCatalog'); fireEvent.change(searchInput, { target: { value: 'Bambu' } }); // ABS Basic has no vendor — should be filtered out expect(screen.queryByText(/ABS Basic/)).toBeNull(); }); it('calls onSelect with the correct filament when an item is clicked', () => { const onSelect = vi.fn(); render( ); openDropdown(); fireEvent.click(screen.getByText(/Bambu Lab — PLA Basic/)); expect(onSelect).toHaveBeenCalledOnce(); expect(onSelect).toHaveBeenCalledWith(FILAMENTS[0]); }); it('shows empty state when no filaments match search', () => { render( ); openDropdown(); const searchInput = screen.getByPlaceholderText('inventory.pickFromSpoolmanCatalog'); fireEvent.change(searchInput, { target: { value: 'xyzzy-not-found' } }); expect(screen.getByText('inventory.noSpoolmanFilaments')).toBeTruthy(); }); it('shows loading spinner when isLoading is true', () => { render( ); // Trigger button shows spinner (Loader2 icon with animate-spin) const spinners = document.querySelectorAll('.animate-spin'); expect(spinners.length).toBeGreaterThan(0); }); it('shows selected filament name in trigger button', () => { render( ); // Should display the selected filament in the trigger expect(screen.getByText(/Bambu Lab — PLA Basic/)).toBeTruthy(); }); it('filters by color_name', () => { render( ); openDropdown(); const searchInput = screen.getByPlaceholderText('inventory.pickFromSpoolmanCatalog'); fireEvent.change(searchInput, { target: { value: 'Green' } }); // PETG has color_name 'Green' — should match expect(screen.getAllByText(/PETG/).length).toBeGreaterThan(0); // PLA Basic has color_name 'Red' — should be filtered out expect(screen.queryByText(/PLA Basic/)).toBeNull(); }); });