import { describe, expect, it } from 'vitest'; import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { missingRequirements } from '@rareindex/connectors'; import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; import { localMeta } from '../_lib/local-meta.js'; import createConnector, { numistaCategory, TypeSchema } from './index.js'; const dir = path.dirname(fileURLToPath(import.meta.url)); const meta = localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8'))); const connector = createConnector(meta); describe('numista', () => { runFixtureSuite(connector, it, expect); it('is gated on NUMISTA_API_KEY', () => { expect(meta.requires).toEqual(['NUMISTA_API_KEY']); expect(missingRequirements(meta, {})).toEqual(['NUMISTA_API_KEY']); expect(missingRequirements(meta, { NUMISTA_API_KEY: 'k' })).toEqual([]); }); it('normalises documented types into catalog items with N# identifiers and per-grade guide values', async () => { const fx = loadFixture('numista', 'types-canada-doc-example'); const out = await connector.normalize(fx.raw); const items = out.filter((r) => r.kind === 'catalog_item'); const obs = out.filter((r) => r.kind === 'price_observation'); expect(items.length).toBe(2); expect(obs.length).toBe(3); // f, vf and the documented "gradde: xf" typo const victoria = items[0]!; if (victoria.kind !== 'catalog_item') throw new Error('item'); expect(victoria.attributes).toMatchObject({ categorySlug: 'coins', name: '5 Cents - Victoria', year: 1858, material: 'silver' }); expect(victoria.attributes.identifiers).toMatchObject({ numista_id: '420', km_number: '2' }); expect(victoria.attributes.metadata).toMatchObject({ issuer: 'Canada', issuer_code: 'canada', max_year: 1901, denomination: '5 Cents', attribution: 'Source: Numista (N#420)' }); expect(victoria.sourceUrl).toBe('https://en.numista.com/420'); const xf = obs.find((r) => r.kind === 'price_observation' && r.grade.grade === 'XF'); if (!xf || xf.kind !== 'price_observation') throw new Error('xf'); expect(xf).toMatchObject({ priceKind: 'guide_value', price: 380, currency: 'EUR', condition: { condition: 'extremely_fine', conditionRaw: 'xf' } }); expect(xf.observationDate.toISOString()).toBe('2026-09-08T09:00:00.000Z'); }); it('maps Numista categories', () => { expect(numistaCategory(TypeSchema.parse({ id: 1, title: 'x', category: 'coin' }))).toBe('coins'); expect(numistaCategory(TypeSchema.parse({ id: 2, title: 'x', category: 'banknote' }))).toBe('banknotes'); expect(numistaCategory(TypeSchema.parse({ id: 3, title: 'x', category: 'exonumia' }))).toBe('medals'); }); });