deckhearth/test/lib/card-import/pokemon-bulk.test.js

116 lines
3.2 KiB
JavaScript
Raw Permalink Normal View History

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();
});
});