TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { describe, expect, it } from 'vitest';2import { readFileSync } from 'node:fs';3import path from 'node:path';4import meta from './meta.json' with { type: 'json' };5import { localMeta } from '../_lib/local-meta.js';6import { fixtureDir, listFixtures, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';7import createConnector, { LANGUAGES, apiUrl, parseCardsets, parseProductName } from './index.js';89const connector = createConnector(localMeta(meta));1011describe('hareruya', () => {12 runFixtureSuite(connector, it, expect);1314 it('parses product names and builds the JSON endpoint URL the page uses', () => {15 expect(parseProductName('《Black Lotus》[2ED]')).toEqual({ name: 'Black Lotus', setCode: '2ED', number: null });16 expect(parseProductName('《Black Lotus》[2ED] 茶R')).toEqual({ name: 'Black Lotus', setCode: '2ED', number: null });17 expect(parseProductName('(001)《Ugin, Eye of the Storms》[TDM]')).toEqual({ name: 'Ugin, Eye of the Storms', setCode: 'TDM', number: '001' });18 expect(parseProductName(null)).toEqual({ name: null, setCode: null, number: null });19 expect(apiUrl('429', 2, 60)).toBe('https://www.hareruyamtg.com/en/products/search/unisearch_api?fq.category_id=1&fq.cardset=429&fq.price=1%7E%2A&rows=60&page=2');20 expect(LANGUAGES['1']).toBe('Japanese');21 expect(LANGUAGES['2']).toBe('English');22 });2324 it('reads the card-set options from the saved public search form', () => {25 const sets = parseCardsets(readFileSync(path.join(fixtureDir('hareruya'), 'search-form.html'), 'utf8'));26 expect(sets.length).toBeGreaterThan(100);27 expect(sets.every((s) => /^\d+$/.test(s.id))).toBe(true);28 expect(sets[0]!.name.length).toBeGreaterThan(2);29 });3031 it('emits one JPY listing per offer with language, foil variant and set', async () => {32 for (const name of listFixtures('hareruya')) {33 const fx = loadFixture('hareruya', name);34 const out = await connector.normalize(fx.raw);35 const docs = (fx.raw.payload as { docs: unknown[] }).docs;36 if (!docs.length) {37 // empty result page (a set announced but not yet stocked) → no records, no crash38 expect(out).toEqual([]);39 continue;40 }41 expect(out.length).toBeGreaterThan(0);42 const ids = new Set<string>();43 for (const r of out) {44 if (r.kind !== 'listing') continue;45 expect(r.currency).toBe('JPY');46 expect(r.price).toBeGreaterThan(0);47 expect(Number.isInteger(r.price)).toBe(true);48 expect(r.seller).toBe('Hareruya');49 expect(r.attributes.set).toBe((fx.raw.payload as { cardset: { name: string } }).cardset.name);50 expect(r.sourceUrl).toMatch(/^https:\/\/www\.hareruyamtg\.com\/en\/products\/detail\/\d+\?lang=[A-Z]{2}/);51 expect(r.condition.condition).toBeNull(); // condition codes are never guessed52 expect(ids.has(r.externalId!)).toBe(false);53 ids.add(r.externalId!);54 if (r.attributes.variant) expect(r.attributes.variant).toBe('Foil');55 }56 }57 });58});59