import { beforeEach, describe, expect, it, vi } from 'vitest'; vi.mock('../../../lib/sql.js', () => ({ sql: Object.assign(vi.fn(async () => ({ rows: [], rowCount: 0 })), { query: vi.fn(async (text, values) => { if (String(text).includes('SELECT id, scryfall_id')) { const ids = values?.[0] ?? []; return { rows: ids.map((scryfallId, index) => ({ id: index + 1, scryfall_id: scryfallId })), rowCount: ids.length, }; } return { rows: [], rowCount: 0 }; }), }), })); vi.mock('../../../lib/pricing/price-history.js', () => ({ recordPriceSnapshots: vi.fn(async (rows) => rows.length), })); vi.mock('../../../lib/card-import/pokemon-github.js', () => ({ fetchPokemonSets: vi.fn(async () => [{ id: 'me3', name: 'Perfect Order', printedTotal: 88 }]), fetchPokemonSetCards: vi.fn(async () => [ { id: 'me3-18', name: 'Seel', supertype: 'Pokémon', number: '18', rarity: 'Common', types: ['Water'], }, ]), mapGithubCardForInsert: vi.fn((card, setMeta) => ({ externalId: card.id, name: card.name, setName: setMeta.name, setCode: setMeta.id, cardNumber: `${card.number}/${setMeta.printedTotal}`, rarity: card.rarity, cardType: card.supertype, types: card.types, flavorText: null, hp: null, imageSmall: null, imageLarge: null, })), })); import { sql } from '../../../lib/sql.js'; import { recordPriceSnapshots } from '../../../lib/pricing/price-history.js'; import { mapPokemonBulkRow, runBulkPokemonSync, } from '../../../lib/card-import/pokemon-bulk.js'; describe('mapPokemonBulkRow', () => { it('includes TCGdex prices and prices_updated_at when pricing is provided', () => { const row = mapPokemonBulkRow( { externalId: 'me3-18', name: 'Seel', setName: 'Perfect Order', setCode: 'me3', cardNumber: '18/88', rarity: 'Common', cardType: 'Pokémon', types: ['Water'], flavorText: null, hp: null, imageSmall: null, imageLarge: null, }, { unlimited: 'Legal' }, { currentPrice: 0.1, marketPrice: 0.2, currency: 'USD' } ); expect(row.currentPrice).toBe(0.1); expect(row.marketPrice).toBe(0.2); expect(row.pricesUpdatedAt).toBeInstanceOf(Date); }); }); describe('runBulkPokemonSync', () => { beforeEach(() => { vi.mocked(sql.query).mockClear(); vi.mocked(recordPriceSnapshots).mockClear(); }); it('enriches rows from TCGdex and reports match counts', async () => { const fetchTcgdexSetCards = vi.fn(async () => [ { id: 'me3-18', localId: '18', name: 'Seel', set: { cardCount: { official: 88 } }, pricing: { tcgplayer: { normal: { lowPrice: 0.1, marketPrice: 0.2 } }, }, }, ]); const summary = await runBulkPokemonSync({ fetchTcgdexSetCards, query: sql.query, setDelayMs: 0, }); expect(summary.pricesMatched).toBe(1); expect(summary.unmatchedCount).toBe(0); expect(summary.snapshotsWritten).toBeGreaterThan(0); expect(recordPriceSnapshots).toHaveBeenCalled(); expect(sql.query).toHaveBeenCalled(); }); });