TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { readFileSync } from 'node:fs';2import path from 'node:path';3import { describe, expect, it } from 'vitest';4import meta from './meta.json' with { type: 'json' };5import { localMeta } from '../../api/_lib/local-meta.js';6import { fixtureDir, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';7import createConnector, { monthFromCode, parseResultsPage, parseSchedule, type PagePayload } from './index.js';8import { sessionEndMonth } from '../../api/_g6-comics-toys-games-lib/comics.js';910const connector = createConnector(localMeta(meta));1112describe('comiclink', () => {13 runFixtureSuite(connector, it, expect);1415 it('discovers past sessions from the schedule page with their closing month (real HTML slice)', () => {16 const html = readFileSync(path.join(fixtureDir('comiclink'), 'schedule-trimmed.html'), 'utf8');17 const sessions = parseSchedule(html);18 expect(sessions.length).toBeGreaterThan(40);19 const spring26 = sessions.find((s) => s.code === '2026-Spring-Comics');20 expect(spring26).toMatchObject({ label: 'Spring Featured: Comics (5-6/26)', endYear: 2026, endMonth: 6, isArt: false });21 expect(sessions.find((s) => s.code === '2026-Spring-ComicArt')?.isArt).toBe(true);22 expect(sessions.find((s) => s.code === '2023-1-Premium')).toMatchObject({ endYear: 2023, endMonth: 1, isArt: false });23 expect(sessions.find((s) => s.code === '2020-12-1-Featured')).toMatchObject({ endYear: 2020, endMonth: 12 });24 expect(sessions.find((s) => s.code === '2022-Fall-Comics')).toMatchObject({ endYear: 2022, endMonth: 11 });25 // newest first26 expect((sessions[0]!.endYear ?? 0) * 100 + (sessions[0]!.endMonth ?? 0)).toBeGreaterThanOrEqual((sessions[5]!.endYear ?? 0) * 100 + (sessions[5]!.endMonth ?? 0));27 });2829 it('parses session month codes and labels', () => {30 expect(monthFromCode('2019-11-ComicAuction', 2019)).toEqual({ year: 2019, month: 11 });31 expect(monthFromCode('2023-1-Premium', 2023)).toEqual({ year: 2023, month: 1 });32 expect(monthFromCode('2021-Fall-Comics', 2021)).toBeNull();33 expect(sessionEndMonth('Fall Featured 11-12/21)', 2021)).toEqual({ year: 2021, month: 12 });34 expect(sessionEndMonth('Summer Featured (Aug-Sept)', 2022)).toEqual({ year: 2022, month: 9 });35 expect(sessionEndMonth('Jan/Feb 2024 Premium Auction Session: Comic Books', null)).toEqual({ year: 2024, month: 2 });36 expect(sessionEndMonth('no month here', null)).toBeNull();37 });3839 it('parses result blocks (title / SOLD in grade / price / item link) from the saved page', () => {40 const fx = loadFixture('comiclink', 'results-2026-Spring-Comics');41 const p = fx.raw.payload as PagePayload;42 const items = parseResultsPage(p.snapshot!);43 expect(items.length).toBe(6);44 expect(items[0]).toMatchObject({ itemId: '1963193', title: 'ACTION COMICS #1', gradeLine: 'CGC 8.5 VF+', price: 601333 });45 expect(items[0]!.image).toMatch(/^https:\/\/www\.comiclink\.com\/img\/comics\//);46 for (const it of items) expect(it.price).toBeGreaterThan(0);47 });4849 it('normalises to month-precision auction sales with grader/grade and publisher family', async () => {50 const out = await connector.normalize(loadFixture('comiclink', 'results-2026-Spring-Comics').raw);51 expect(out.length).toBe(40);52 const first = out[0];53 if (first?.kind !== 'sale') throw new Error('expected sale');54 expect(first.saleDate.toISOString()).toBe('2026-06-01T00:00:00.000Z');55 expect(first.attributes).toMatchObject({ categorySlug: 'dc_comics', series: 'Action Comics', number: '1' });56 expect(first.grade).toMatchObject({ grader: 'cgc', grade: '8.5' });57 expect(first.attributes.metadata.sale_date_precision).toBe('month');58 expect(first.buyerPremiumIncluded).toBeNull();59 expect(first.auctionHouse).toBe('ComicLink');60 expect(first.currency).toBe('USD');61 expect(first.sourceUrl).toBe('https://www.comiclink.com/auctions/item.asp?id=1963193');62 });6364 it('skips sessions without a source month instead of inventing a date', async () => {65 const fx = loadFixture('comiclink', 'results-2026-Spring-Comics');66 const p = fx.raw.payload as PagePayload;67 const out = await connector.normalize({ ...fx.raw, payload: { ...p, session: { ...p.session, endMonth: null, endYear: null } } });68 expect(out).toEqual([]);69 });70});71