import { describe, expect, it } from 'vitest'; import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { runFixtureSuite } from '@rareindex/connectors/testing'; import { localMeta } from '../_lib/local-meta.js'; import createConnector, { parseItemPage, salesHistorySitemaps } from './index.js'; const dir = path.dirname(fileURLToPath(import.meta.url)); const meta = localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8'))); const connector = createConnector(meta); /** Real prefetchedItemData captured live from https://www.fanaticscollect.com/weekly/1e389fce-6f23-11ed-a610-0a58a9feac02 (2026-09-08), trimmed. */ const SOLD_LISTING = { __typename: 'CollectListing', id: '1e389fce-6f23-11ed-a610-0a58a9feac02', title: '2003 Fleer Tradition LeBron James ROOKIE #261 PSA 9 MINT', listingType: 'WEEKLY', isManageable: false, certifiedSeller: 'Fanatics Collect', currentBid: { __typename: 'Money', amountInCents: 23000, currency: 'USD' }, auction: { __typename: 'CollectWeeklyAuction', id: '8d27de96-6f1d-11ed-ab20-0a58a9feac02', auctionIntegerId: 30, integerId: 172, name: '2022 Weekly Auction #1', shortName: 'WA1', payoutDate: '2022-02-16', startsAt: '2022-01-14T03:00:00Z', endsAt: '2022-01-24T03:00:00Z', status: 'CLOSED' }, integerId: 3093498, insertedAt: '2021-12-22T13:41:22Z', updatedAt: '2023-01-09T18:38:25Z', soldDate: null, lotString: 'WA1 Lot: 1100', imageSets: [{ __typename: 'CollectImageSet', large: 'https://dilxwvfkfup17.cloudfront.net/abc-large', medium: 'https://dilxwvfkfup17.cloudfront.net/abc-medium' }], slug: null, soldFor: null, startingPrice: { __typename: 'Money', amountInCents: 500, currency: 'USD' }, description: 'Welcome to our first Weekly Sunday Auction! This is one of over 3,600 items spanning all sports and genres, closing on the evening of Sunday, January 23rd.', status: 'STATUS_SOLD', bidCount: 27, collectSales: [{ __typename: 'CollectSale', soldDate: '2022-01-24T04:10:06Z', soldFor: { __typename: 'Money', amountInCents: 27600, currency: 'USD' } }], vaultItem: { __typename: 'CollectVaultItem', id: '0bf62e5c-6f1f-11ed-a6c4-0a58a9feac02', integerId: 732786 }, }; /** Real fixed-price (best offer) listing from /fixed/eb86cdda-a912-11f0-8fa5-0a58a9feac02/… — sold via offer, but no CollectSale exposed. */ const FIXED_LISTING = { __typename: 'CollectListing', id: '178984d1-fd50-473c-8e6d-3e96d63b5ba3', title: '2000 Pokemon Insert Card Ancient Mew CGC 5.5 EX+', listingType: 'BO', status: 'BO_STATUS_SOLD', soldDate: null, soldFor: null, startingPrice: { __typename: 'Money', amountInCents: 0, currency: 'USD' }, collectSales: [], vaultItem: { __typename: 'CollectVaultItem', id: '60ecaa72-89d8-11f0-85e1-02f5d6e69f97' }, imageSets: [{ __typename: 'CollectImageSet', large: 'https://cdn-vault.fanaticscollect.com/2025/9/4/rm2/large/v1503807_2020090306325159R_23.jpg' }], slug: '2000-pokemon-insert-card-ancient-mew-cgc-55-ex', description: '', }; /** Wrap an object in a Next.js flight chunk the way the live page does (JS-string escaped JSON). */ function flightHtml(listing: unknown): string { const line = `2f:["$","$L42",null,{"prefetchedItemData":${JSON.stringify(listing)},"foo":1}]\n`; return `x`; } const SITEMAP_INDEX = ` https://www.fanaticscollect.com/sitemap/pages.xml.gz https://www.fanaticscollect.com/sitemap/weekly-auction-1.xml.gz https://www.fanaticscollect.com/sitemap/sales-history-weekly-auction-1.xml.gz https://www.fanaticscollect.com/sitemap/sales-history-weekly-auction-2.xml.gz https://www.fanaticscollect.com/sitemap/sales-history-fixed-price-1.xml.gz https://www.fanaticscollect.com/sitemap/sales-history-fixed-price-7.xml.gz `; describe('fanatics-collect', () => { runFixtureSuite(connector, it, expect); it('parses the RSC flight payload of a sold weekly lot', () => { const url = 'https://www.fanaticscollect.com/weekly/1e389fce-6f23-11ed-a610-0a58a9feac02'; const p = parseItemPage(flightHtml(SOLD_LISTING), url, '2023-01-09')!; expect(p.kind).toBe('fc_item'); expect(p.listing).toMatchObject({ id: '1e389fce-6f23-11ed-a610-0a58a9feac02', listingType: 'WEEKLY', status: 'STATUS_SOLD', bidCount: 27, lotString: 'WA1 Lot: 1100' }); expect(p.listing.collectSales[0]).toEqual({ soldDate: '2022-01-24T04:10:06Z', soldFor: { amountInCents: 27600, currency: 'USD' } }); expect(p.listing.images).toEqual(['https://dilxwvfkfup17.cloudfront.net/abc-large']); expect(p.listing.auction).toMatchObject({ shortName: 'WA1', endsAt: '2022-01-24T03:00:00Z' }); expect((p.listing as Record).__typename).toBeUndefined(); }); it('normalises a sale with buyer premium included, hammer in metadata, PSA grade and lot number', async () => { const url = 'https://www.fanaticscollect.com/weekly/1e389fce-6f23-11ed-a610-0a58a9feac02'; const p = parseItemPage(flightHtml(SOLD_LISTING), url, '2023-01-09')!; const out = await connector.normalize({ url, externalId: p.listing.id, kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T10:00:00Z'), payload: p }); expect(out.length).toBe(1); const s = out[0]!; if (s.kind !== 'sale') throw new Error('expected sale'); expect(s).toMatchObject({ price: 276, currency: 'USD', buyerPremiumIncluded: true, auctionHouse: 'Fanatics Collect', lotNumber: '1100', saleType: 'auction', location: 'US', externalId: '1e389fce-6f23-11ed-a610-0a58a9feac02' }); expect(s.saleDate.toISOString()).toBe('2022-01-24T04:10:06.000Z'); expect(s.attributes.categorySlug).toBe('basketball_cards'); expect(s.attributes.year).toBe(2003); expect(s.attributes.metadata).toMatchObject({ hammer_price: 230, buyer_premium_pct: 20, auction_short_name: 'WA1', listing_type: 'WEEKLY' }); expect(s.attributes.identifiers).toEqual({ fanatics_listing_id: '1e389fce-6f23-11ed-a610-0a58a9feac02', fanatics_vault_item_id: '0bf62e5c-6f1f-11ed-a6c4-0a58a9feac02' }); expect(s.grade).toMatchObject({ grader: 'psa', grade: '9' }); expect(s.confidence).toBe(0.9); }); it('skips fixed-price pages that expose no CollectSale', async () => { const url = 'https://www.fanaticscollect.com/fixed/eb86cdda-a912-11f0-8fa5-0a58a9feac02/2000-pokemon-insert-card-ancient-mew-cgc-55-ex'; const p = parseItemPage(flightHtml(FIXED_LISTING), url)!; expect(p.listing.listingType).toBe('BO'); expect(p.listing.collectSales).toEqual([]); expect(await connector.normalize({ url, externalId: p.listing.id, kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: p })).toEqual([]); }); it('records fixed-price sales without a premium flag when a CollectSale exists', async () => { const url = 'https://www.fanaticscollect.com/fixed/178984d1-fd50-473c-8e6d-3e96d63b5ba3/x'; const p = parseItemPage(flightHtml({ ...FIXED_LISTING, collectSales: [{ __typename: 'CollectSale', soldDate: '2025-10-22T09:59:16.000Z', soldFor: { __typename: 'Money', amountInCents: 500, currency: 'USD' } }] }), url)!; const out = await connector.normalize({ url, externalId: p.listing.id, kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: p }); expect(out.length).toBe(1); const s = out[0]!; if (s.kind !== 'sale') throw new Error('expected sale'); expect(s).toMatchObject({ price: 5, saleType: 'fixed_price', buyerPremiumIncluded: null, lotNumber: null }); expect(s.attributes.categorySlug).toBe('pokemon'); expect(s.grade).toMatchObject({ grader: 'cgc', grade: '5.5' }); }); it('returns null for pages without listing JSON and orders sales-history sitemaps newest first', () => { expect(parseItemPage('nothing', 'https://www.fanaticscollect.com/weekly/x')).toBeNull(); expect(salesHistorySitemaps(SITEMAP_INDEX)).toEqual([ 'https://www.fanaticscollect.com/sitemap/sales-history-fixed-price-7.xml.gz', 'https://www.fanaticscollect.com/sitemap/sales-history-weekly-auction-2.xml.gz', 'https://www.fanaticscollect.com/sitemap/sales-history-fixed-price-1.xml.gz', 'https://www.fanaticscollect.com/sitemap/sales-history-weekly-auction-1.xml.gz', ]); }); it('recognises item URLs for lookup', () => { expect(connector.urlPatterns![0]!.test('https://www.fanaticscollect.com/weekly/1e389fce-6f23-11ed-a610-0a58a9feac02')).toBe(true); expect(connector.urlPatterns![0]!.test('https://www.fanaticscollect.com/fixed/eb86cdda-a912-11f0-8fa5-0a58a9feac02/slug')).toBe(true); expect(connector.urlPatterns![0]!.test('https://www.fanaticscollect.com/marketplace?type=WEEKLY')).toBe(false); }); });