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%
2.7 KB · 48 lines typescript
Raw Blame History
1/** Live fixture capture for magi: two series pages (Pokémon, Yu-Gi-Oh! incl. a SOLD item) + one sold item page. Usage: pnpm tsx connectors/api/magi/_capture.ts */2import { mkdirSync, writeFileSync } from 'node:fs';3import path from 'node:path';4import { fixtureDir, saveFixture } from '@rareindex/connectors/testing';5import meta from './meta.json' with { type: 'json' };6import { parseItemPage, parseSeriesPage, type MagiPayload, type MagiSeed } from './index.js';7import { HTML_HEADERS } from '../_g1-cards-eu-jp-lib/index.js';89const SITE = 'https://magi.camp';10const text = async (u: string) => (await fetch(u, { headers: HTML_HEADERS })).text();11const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));12mkdirSync(fixtureDir('magi'), { recursive: true });13const seeds = meta.config.seeds as MagiSeed[];1415let soldUrl: string | null = null;16for (const [series, name, keep] of [['31', 'pokemon-series-page1', 24], ['34', 'yugioh-series-page1', 24]] as const) {17  const seed = seeds.find((s) => s.series === series)!;18  const url = `${SITE}/series/${series}/items`;19  const doc = await text(url);20  if (series === '31') writeFileSync(path.join(fixtureDir('magi'), 'series-page.html'), doc);21  const { items, hasNext, heading } = parseSeriesPage(doc);22  // keep the first `keep` items but make sure a SOLD item is included when the page has one23  const sold = items.find((i) => i.sold);24  const kept = items.slice(0, keep);25  if (sold && !kept.includes(sold)) kept[kept.length - 1] = sold;26  if (sold) soldUrl = soldUrl ?? sold.url;27  const payload: MagiPayload = { type: 'list', seed, page: 1, items: kept };28  saveFixture('magi', name, {29    raw: { url, externalId: `series:${series}:p1`, kind: 'listing', engine: 'api', fetchedAt: new Date(), payload },30    expect: { minCount: 5, kinds: ['listing'], requiredFields: ['price', 'attributes.name'] },31    note: `Live capture ${new Date().toISOString().slice(0, 10)} — ${url} (${heading}; ${items.length} items, hasNext=${hasNext}, sold on page: ${items.filter((i) => i.sold).length}; first ${kept.length} kept)`,32  });33  console.log(name, heading, items.length, hasNext, kept[0], sold?.title);34  await wait(4000);35}3637if (soldUrl) {38  const doc = await text(soldUrl);39  const item = parseItemPage(doc, soldUrl)!;40  const payload: MagiPayload = { type: 'item', seed: null, ...item };41  saveFixture('magi', 'sold-item-page', {42    raw: { url: soldUrl, externalId: item.id, kind: 'listing', engine: 'api', fetchedAt: new Date(), payload },43    expect: { minCount: 0, kinds: ['listing'] },44    note: `Live capture ${new Date().toISOString().slice(0, 10)} — ${soldUrl} JSON-LD Product (availability ${item.availability}); lookup path`,45  });46  console.log('sold item', item);47}48