// @vitest-environment jsdom import { describe, it, expect, vi, afterEach } from 'vitest'; import { render, screen, cleanup, fireEvent, waitFor } from '@testing-library/react'; import ScannerCheckoutSheet, { ScannerCheckoutContent } from '../../components/scanner/ScannerCheckoutSheet'; import { VOCAB } from '../../lib/collection-vocabulary.js'; function createQueueFixture({ scannedCards = [ { id: 'card-1', name: 'Lightning Bolt', set: 'Alpha', cardNumber: '161', quantity: 1, condition: 'NM', isFoil: false, processed: false, confidence: 0.92, }, { id: 'card-2', name: 'Counterspell', set: 'Beta', cardNumber: '54', quantity: 1, condition: 'NM', isFoil: false, processed: false, confidence: 0.55, }, ], selectedCardIds = [], } = {}) { const selectedCards = new Set(selectedCardIds); return { scannedCards, collections: [{ id: 1, name: 'Trade Binder', is_system_collection: false }], selectedCards, isProcessing: false, addingCardIds: new Set(), toggleCardSelection: vi.fn((cardId) => { if (selectedCards.has(cardId)) { selectedCards.delete(cardId); } else { selectedCards.add(cardId); } }), incrementCardQuantity: vi.fn(), decrementCardQuantity: vi.fn(), updateCardMetadata: vi.fn(), removeScannedCard: vi.fn(), commitSelectedToOwned: vi.fn(async () => {}), commitSelectedToCollection: vi.fn(async () => {}), }; } describe('ScannerCheckoutSheet', () => { afterEach(() => cleanup()); it('renders header count for scanned cards', () => { const queue = createQueueFixture(); render( ); expect(screen.getByText('2 cards scanned')).toBeTruthy(); }); it('disables primary action when nothing is selected', () => { const queue = createQueueFixture({ selectedCardIds: [] }); queue.toggleCardSelection = vi.fn(); render( ); const primaryButton = screen.getByRole('button', { name: VOCAB.ADD_TO_MY_COLLECTION, }); expect(primaryButton.disabled).toBe(true); }); it('shows vocab labels on checkout actions', () => { const queue = createQueueFixture({ selectedCardIds: ['card-1'] }); render( ); expect( screen.getByRole('button', { name: new RegExp(VOCAB.ADD_TO_MY_COLLECTION) }) ).toBeTruthy(); expect(screen.getByRole('button', { name: VOCAB.ADD_TO_LIST })).toBeTruthy(); }); it('renders checkout sheet dialog without crashing', () => { const queue = createQueueFixture({ selectedCardIds: ['card-1'] }); expect(() => { render( ); }).not.toThrow(); expect(screen.getByRole('dialog')).toBeTruthy(); }); it('does not show an error banner when commit returns successful ids', async () => { const queue = createQueueFixture({ selectedCardIds: ['card-1'] }); queue.commitSelectedToOwned = vi.fn(async () => ['card-1']); render( ); fireEvent.click( screen.getByRole('button', { name: new RegExp(VOCAB.ADD_TO_MY_COLLECTION) }) ); await waitFor(() => { expect(queue.commitSelectedToOwned).toHaveBeenCalledTimes(1); }); expect(screen.queryByRole('alert')).toBeNull(); }); it('shows an error banner when commit returns no successful ids', async () => { const queue = createQueueFixture({ selectedCardIds: ['card-1'] }); queue.commitSelectedToOwned = vi.fn(async () => []); render( ); fireEvent.click( screen.getByRole('button', { name: new RegExp(VOCAB.ADD_TO_MY_COLLECTION) }) ); expect(await screen.findByRole('alert')).toBeTruthy(); }); });