deckhearth/test/components/ScannerDestinationPicker.test.js
Randall Stillwell 1e248bdf2b test(scanner): cover redesign API and component surfaces
Add vitest specs for user-cards quantity validation, scan upload-image
auth/rate-limit/MIME gates, ScannerDestinationPicker, and ScannedCardItem.
Suite grows 21 → 37 tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 14:26:13 -05:00

94 lines
2.8 KiB
JavaScript

// @vitest-environment jsdom
import { afterEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import ScannerDestinationPicker from '../../components/ScannerDestinationPicker.js';
const COLLECTIONS = [
{ id: 1, name: 'Modern Staples', tcg: 'MTG' },
{ id: 2, name: 'Pokémon Binder', tcg: 'Pokemon' },
];
const DECKS = [
{ id: 10, name: 'Commander', game: 'mtg' },
{ id: 11, name: 'Standard', game: 'pokemon' },
];
describe('ScannerDestinationPicker', () => {
afterEach(() => cleanup());
it('shows the active destination type with aria-pressed', () => {
render(
<ScannerDestinationPicker
gameFilter="All"
onGameFilterChange={vi.fn()}
destination={{ type: 'owned', id: null, label: 'My owned cards' }}
onDestinationChange={vi.fn()}
collections={COLLECTIONS}
decks={DECKS}
/>
);
expect(screen.getByRole('button', { name: /owned/i }).getAttribute('aria-pressed')).toBe('true');
expect(screen.getByRole('button', { name: /collection/i }).getAttribute('aria-pressed')).toBe('false');
});
it('calls onDestinationChange when switching to a collection', () => {
const onDestinationChange = vi.fn();
render(
<ScannerDestinationPicker
gameFilter="All"
onGameFilterChange={vi.fn()}
destination={{ type: 'owned', id: null, label: 'My owned cards' }}
onDestinationChange={onDestinationChange}
collections={COLLECTIONS}
decks={DECKS}
/>
);
fireEvent.click(screen.getByRole('button', { name: /collection/i }));
expect(onDestinationChange).toHaveBeenCalledWith({
type: 'collection',
id: 1,
label: 'Modern Staples',
});
});
it('filters decks by game and disables deck toggle when none match', () => {
render(
<ScannerDestinationPicker
gameFilter="MTG"
onGameFilterChange={vi.fn()}
destination={{ type: 'deck', id: 10, label: 'Commander' }}
onDestinationChange={vi.fn()}
collections={COLLECTIONS}
decks={DECKS}
/>
);
expect(screen.getByRole('button', { name: /deck/i }).disabled).toBe(false);
expect(screen.queryByText(/Standard/)).toBeNull();
});
it('calls onGameFilterChange when the game select changes', () => {
const onGameFilterChange = vi.fn();
render(
<ScannerDestinationPicker
gameFilter="All"
onGameFilterChange={onGameFilterChange}
destination={{ type: 'owned', id: null, label: 'My owned cards' }}
onDestinationChange={vi.fn()}
collections={COLLECTIONS}
decks={DECKS}
/>
);
fireEvent.change(screen.getByRole('combobox', { name: /game filter/i }), {
target: { value: 'Lorcana' },
});
expect(onGameFilterChange).toHaveBeenCalledWith('Lorcana');
});
});