import { describe, expect, it } from 'vitest'; import { getConnectorMeta } from '@rareindex/connectors'; import { loadFixture, listFixtures, runFixtureSuite } from '@rareindex/connectors/testing'; import createConnector, { languageFromSetCode } from './index.js'; const connector = createConnector(getConnectorMeta('ygoprodeck')); describe('ygoprodeck', () => { runFixtureSuite(connector, it, expect); it('emits one catalog item per printing with set code / rarity / language', async () => { const name = listFixtures('ygoprodeck').find((n) => n === '46986414') ?? listFixtures('ygoprodeck')[0]!; // Dark Magician const fx = loadFixture('ygoprodeck', name); const out = await connector.normalize(fx.raw); const cats = out.filter((r) => r.kind === 'catalog_item'); const payload = fx.raw.payload as { card: { card_sets: Array<{ set_code: string; set_rarity?: string }>; id: number } }; const distinct = new Set(payload.card.card_sets.map((s) => `${s.set_code}|${s.set_rarity ?? ''}`)).size; expect(cats).toHaveLength(distinct); const first = cats[0]!; if (first.kind !== 'catalog_item') throw new Error('kind'); expect(first.attributes.categorySlug).toBe('yugioh'); expect(first.attributes.identifiers.ygo_id).toBe(String(payload.card.id)); expect(first.attributes.identifiers.konami_id).toBeTruthy(); expect(first.attributes.number).toMatch(/^[A-Z0-9]+-[A-Z]*\d+/); expect(first.attributes.setCode).toBe(first.attributes.number!.split('-')[0]); expect(first.attributes.year).toBeNull(); // per-printing year unknown → never guessed // unique external ids per printing expect(new Set(cats.map((c) => c.kind === 'catalog_item' && c.externalId)).size).toBe(cats.length); }); it('records set_price per printing and card-level prices once', async () => { const fx = loadFixture('ygoprodeck', listFixtures('ygoprodeck')[0]!); const out = await connector.normalize(fx.raw); const obs = out.filter((r) => r.kind === 'price_observation'); const printingLevel = obs.filter((o) => o.kind === 'price_observation' && o.attributes.metadata.price_scope === 'printing'); const cardLevel = obs.filter((o) => o.kind === 'price_observation' && o.attributes.metadata.price_scope === 'card'); expect(printingLevel.length).toBeGreaterThan(0); expect(cardLevel.length).toBeGreaterThan(0); expect(cardLevel.length).toBeLessThanOrEqual(5); for (const o of printingLevel) if (o.kind === 'price_observation') expect(o.priceKind).toBe('guide_value'); const eur = cardLevel.find((o) => o.kind === 'price_observation' && o.currency === 'EUR'); expect(eur && eur.kind === 'price_observation' ? eur.attributes.metadata.priceSource : '').toBe('cardmarket'); }); it('derives language from set codes', () => { expect(languageFromSetCode('LOB-EN001')).toBe('English'); expect(languageFromSetCode('LOB-FR001')).toBe('French'); expect(languageFromSetCode('LOB-001')).toBeNull(); }); });