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.1 KB · 65 lines typescript
Raw Blame History
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, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';7import createConnector, { parseSellPage, parseVersions } from './index.js';8import { yen } from '../_g1-cards-eu-jp-lib/index.js';910const connector = createConnector(localMeta(meta));1112describe('yuyu-tei', () => {13  runFixtureSuite(connector, it, expect);1415  it('parses yen prices in the shop format', () => {16    expect(yen('118,000 円')).toBe(118000);17    expect(yen('2,980 円')).toBe(2980);18    expect(yen('¥ 187,614')).toBe(187614);19    expect(yen('売り切れ')).toBeNull();20  });2122  it('parses the saved sell page: rarity sections, numbers, prices, stock, kizu flag', () => {23    const doc = readFileSync(path.join(fixtureDir('yuyu-tei'), 'sell-page.html'), 'utf8');24    const { setName, items } = parseSellPage(doc);25    expect(setName).toMatch(/^\[/);26    expect(items.length).toBeGreaterThan(50);27    const first = items[0]!;28    expect(first.url).toMatch(/^https:\/\/yuyu-tei\.jp\/sell\/poc\/card\//);29    expect(first.number).toMatch(/^\d+\/\d+$/);30    expect(first.rarity).toBeTruthy();31    expect(first.priceJpy).toBeGreaterThan(0);32    expect(first.stock).not.toBeNull();33    expect(first.image).toMatch(/^https:\/\/card\.yuyu-tei\.jp\//);34    expect(items.every((i) => i.kizu === false)).toBe(true);35    // the expansion filter (vers[] checkboxes) is rendered on sell pages too: code + "[M6] name" label36    const versions = parseVersions(doc);37    expect(versions.length).toBeGreaterThan(20);38    expect(versions[0]).toMatchObject({ code: expect.stringMatching(/^[a-z0-9-]+$/), name: expect.stringMatching(/^\[/) });39  });4041  it('emits JPY listings (never sales) plus catalog items with Japanese language and set code', async () => {42    const fx = loadFixture('yuyu-tei', 'pokemon-set');43    const out = await connector.normalize(fx.raw);44    const listings = out.filter((r) => r.kind === 'listing');45    const cats = out.filter((r) => r.kind === 'catalog_item');46    expect(listings.length).toBeGreaterThan(0);47    expect(cats.length).toBe(listings.length);48    for (const l of listings) {49      if (l.kind !== 'listing') continue;50      expect(l.currency).toBe('JPY');51      expect(l.price).toBeGreaterThan(0);52      expect(l.seller).toBe('Yuyu-tei');53      expect(l.attributes.language).toBe('Japanese');54      expect(l.attributes.setCode).toMatch(/^[A-Z0-9-]+$/i);55      expect(l.attributes.categorySlug).toBe('pokemon');56      expect(['available', 'ended']).toContain(l.availability);57    }58    const op = loadFixture('yuyu-tei', 'one-piece-set');59    const oout = await connector.normalize(op.raw);60    for (const r of oout) if ('attributes' in r) expect(r.attributes.categorySlug).toBe('one_piece_card_game');61    const numbered = oout.find((r) => r.kind === 'catalog_item' && r.attributes.number);62    expect(numbered && numbered.kind === 'catalog_item' ? numbered.attributes.number : null).toMatch(/^[A-Z]+\d+-\d+$/);63  });64});65