import { beforeEach, describe, expect, it, vi } from 'vitest'; vi.mock('../../../lib/pricing/price-history.js', () => ({ recordPriceSnapshots: vi.fn(async (rows) => rows.length), })); import { recordPriceSnapshots } from '../../../lib/pricing/price-history.js'; import { enrichLorcanaRowWithFolio, mapLorcanaCard, runBulkLorcanaSync, } from '../../../lib/card-import/lorcana-bulk.js'; import { buildFolioPriceIndex } from '../../../lib/pricing/foolio-client.js'; describe('mapLorcanaCard pricing', () => { it('includes price fields when Foilio pricing is provided', () => { const mapped = mapLorcanaCard( { Unique_ID: 'TFC-001', Name: 'Ariel - On Human Legs', Set_Name: 'The First Chapter', Set_ID: 'TFC', Card_Num: 1, }, { currentPrice: 1.25, marketPrice: 1.5, currency: 'USD' } ); expect(mapped.currentPrice).toBe(1.25); expect(mapped.marketPrice).toBe(1.5); expect(mapped.pricesUpdatedAt).toBeInstanceOf(Date); }); }); describe('enrichLorcanaRowWithFolio', () => { it('matches by card id and tracks matched/unmatched counts', () => { const index = buildFolioPriceIndex([ { card_id: 'TFC-001', usd_low: 1, usd_market: 2 }, ]); const stats = { pricesMatched: 0, unmatchedCount: 0 }; const enriched = enrichLorcanaRowWithFolio( mapLorcanaCard({ Unique_ID: 'TFC-001', Name: 'Ariel - On Human Legs', Set_ID: 'TFC', }), index, stats ); expect(enriched.currentPrice).toBe(1); expect(enriched.marketPrice).toBe(2); expect(stats.pricesMatched).toBe(1); expect(stats.unmatchedCount).toBe(0); }); it('increments unmatchedCount when no feed row matches', () => { const stats = { pricesMatched: 0, unmatchedCount: 0 }; const enriched = enrichLorcanaRowWithFolio( mapLorcanaCard({ Unique_ID: 'TFC-999', Name: 'Unknown', Set_ID: 'TFC', }), buildFolioPriceIndex([]), stats ); expect(enriched.currentPrice ?? null).toBeNull(); expect(stats.unmatchedCount).toBe(1); }); }); describe('runBulkLorcanaSync', () => { beforeEach(() => { vi.mocked(recordPriceSnapshots).mockClear(); vi.restoreAllMocks(); }); it('fetches Foilio feed once and reports price match summary', async () => { const fetchFolioIndex = vi.fn(async () => buildFolioPriceIndex([ { card_id: 'TFC-001', usd_low: 0.5, usd_market: 0.75 }, ])); vi.stubGlobal('fetch', vi.fn(async () => ({ ok: true, json: async () => ([ { Unique_ID: 'TFC-001', Name: 'Ariel - On Human Legs', Set_Name: 'The First Chapter', Set_ID: 'TFC', Card_Num: 1, Gamemode: 'Lorcana', }, ]), }))); const query = vi.fn(async (text, values) => { if (String(text).includes('SELECT id, scryfall_id')) { return { rows: [{ id: 1, scryfall_id: 'TFC-001' }], rowCount: 1 }; } return { rows: [], rowCount: 0 }; }); const summary = await runBulkLorcanaSync({ sql: { query }, fetchFolioIndex, }); expect(fetchFolioIndex).toHaveBeenCalledTimes(1); expect(summary.pricesMatched).toBe(1); expect(summary.unmatchedCount).toBe(0); expect(summary.upserted).toBe(1); expect(recordPriceSnapshots).toHaveBeenCalled(); }); });