SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
3.8 KB · 64 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import meta from './meta.json' with { type: 'json' };3import { localMeta } from '../_lib/local-meta.js';4import { listFixtures, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';5import createConnector, { PRICE_FIELDS, hasAnyPrice, parseProductName } from './index.js';6import { isoDay } from '../_g1-cards-eu-jp-lib/index.js';78const connector = createConnector(localMeta(meta));910describe('cardmarket-priceguide', () => {11  runFixtureSuite(connector, it, expect);1213  it('parses Cardmarket product names', () => {14    expect(parseProductName('Kakuna [Bug Bite | Primal Clash]')).toEqual({ name: 'Kakuna', number: null, version: null, disambiguation: 'Bug Bite | Primal Clash' });15    expect(parseProductName('Roronoa Zoro (OP01-001)')).toEqual({ name: 'Roronoa Zoro', number: 'OP01-001', version: null, disambiguation: null });16    expect(parseProductName('Yokomon (BT1-001)').number).toBe('BT1-001');17    expect(parseProductName('Auron (1-001)').number).toBe('1-001');18    expect(parseProductName('Forest (V.1)')).toEqual({ name: 'Forest', number: null, version: 'V.1', disambiguation: null });19    expect(parseProductName('Whis&#39;s Coercion').name).toBe("Whis's Coercion");20    // unknown parentheticals stay part of the name (never guessed as numbers)21    expect(parseProductName('Sol Ring (Extended Art)').name).toBe('Sol Ring (Extended Art)');22  });2324  it('dates observations with the file createdAt (source date, not fetch time)', () => {25    expect(isoDay('2026-09-07T02:48:04+0200')?.toISOString()).toBe('2026-09-07T00:00:00.000Z');26  });2728  it('detects foil rows and maps every price field to a priceKind', () => {29    expect(hasAnyPrice({ idProduct: 1, avg: null, low: null, 'trend-foil': 0.36 }, true)).toBe(true);30    expect(hasAnyPrice({ idProduct: 1, avg: null, low: null, 'trend-foil': 0.36 }, false)).toBe(false);31    expect(hasAnyPrice(null)).toBe(false);32    expect(PRICE_FIELDS.map(([, k]) => k)).toEqual(['mid', 'low', 'trend', 'market', 'average_7d', 'average_30d']);33  });3435  it('emits cardmarket_id identifiers, EUR observations and a foil variant when foil prices exist', async () => {36    for (const name of listFixtures('cardmarket-priceguide')) {37      const fx = loadFixture('cardmarket-priceguide', name);38      const out = await connector.normalize(fx.raw);39      const cats = out.filter((r) => r.kind === 'catalog_item');40      const obs = out.filter((r) => r.kind === 'price_observation');41      expect(cats.length).toBeGreaterThanOrEqual(1);42      expect(obs.length).toBeGreaterThanOrEqual(1);43      for (const c of cats) {44        if (c.kind !== 'catalog_item') continue;45        expect(c.attributes.identifiers.cardmarket_id).toMatch(/^\d+$/);46        expect(c.sourceUrl).toContain('downloads.s3.cardmarket.com');47      }48      for (const o of obs) {49        if (o.kind !== 'price_observation') continue;50        expect(o.currency).toBe('EUR');51        expect(o.price).toBeGreaterThan(0);52        expect(o.observationDate.getUTCHours()).toBe(0);53        expect(o.observationDate.getTime()).toBeLessThanOrEqual(Date.now());54        expect((o.attributes.metadata as { cardmarket_field: string }).cardmarket_field).toBeTruthy();55      }56      const payload = fx.raw.payload as { prices: Record<string, number | null> | null; single: boolean; game: { foilVariant: string } };57      const foilPresent = Boolean(payload.single && payload.prices && Object.entries(payload.prices).some(([k, v]) => k.endsWith('-foil') && typeof v === 'number' && v > 0));58      const foilCat = cats.find((c) => c.kind === 'catalog_item' && c.attributes.variant === payload.game.foilVariant);59      expect(Boolean(foilCat)).toBe(foilPresent);60      if (!payload.single) for (const c of cats) if (c.kind === 'catalog_item') expect(c.condition.completeness).toBe('sealed');61    }62  });63});64