import { describe, expect, it } from 'vitest'; import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; import { localMeta } from '../_lib/local-meta.js'; import { hibidCategory, isFirearm } from './categories.js'; import createConnector, { parseCatalog, parsePastAuctions, slugify } 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); /** Trimmed REAL Apollo state captured from https://hibid.com/catalog/752746/auction-200-silver-and-paper-money on 2026-09-08 (3 lots, contact details removed). */ const STATE = readFileSync(path.join(dir, 'fixtures.state.json'), 'utf8'); const CATALOG_HTML = `Auction 200 Silver and Paper Money | HiBid`; function withPage(pageNumber: number, results: string): string { return CATALOG_HTML.replace(/"pageNumber":1,"totalCount":3,"filteredCount":3,"results":\[[^\]]*\]/, `"pageNumber":${pageNumber},"totalCount":3,"filteredCount":3,"results":[${results}]`); } describe('hibid', () => { runFixtureSuite(connector, it, expect); it('parses the auction header and lots from the embedded Apollo state', () => { const cat = parseCatalog(CATALOG_HTML, 1)!; expect(cat.auction).toMatchObject({ id: '752746', eventName: 'Auction 200 Silver and Paper Money', currency: 'CAD', buyerPremium: 'Buyers Premium 18%', bidCloseDateTime: '2026-09-07T19:00:00' }); expect(cat.auction.auctioneer).toMatchObject({ name: 'Legacy Auctions', city: 'Leamington', state: 'ON', country: 'Canada' }); expect(cat.pageNumber).toBe(1); expect(cat.totalCount).toBe(3); expect(cat.lots.length).toBe(3); const sold = cat.lots.find((l) => l.lotNumber === '93')!; expect(sold).toMatchObject({ id: '308002776', title: '1-1954 DEVIL FACE 20 DOLLAR BILL C/E2791225', priceRealized: 48, quantitySold: 1, isClosed: true, categoryPath: 'Coins & Currency - Currency - World', mappable: true }); expect(sold.url).toBe('https://hibid.com/lot/308002776/1-1954-devil-face-20-dollar-bill-c-e2791225'); expect(cat.lots.find((l) => l.lotNumber === '91')!.priceRealized).toBeNull(); expect(cat.lots[0]!.image).toMatch(/^https:\/\/cdn\.hibid\.com\/img\.axd/); }); it('detects the end of a catalog (page 2 with no results)', () => { const cat = parseCatalog(withPage(2, ''), 2)!; expect(cat.pageNumber).toBe(2); expect(cat.lots.length).toBe(0); }); it('maps HiBid categories to taxonomy slugs and filters non-collectibles and firearms', () => { expect(hibidCategory('Coins & Currency - Currency - Canada', '1-1937 BANK OF CANADA 1 DOLLAR BILL S/N3599211')).toBe('banknotes'); expect(hibidCategory('Coins & Currency - Coins - Canada', '1967 Canada Silver Dollar')).toBe('coins'); expect(hibidCategory('Sports Memorabilia & Cards - Cards', '1986 Fleer Michael Jordan Rookie PSA 8')).toBe('basketball_cards'); expect(hibidCategory('Toys & Hobbies - Action Figures', 'Star Wars Kenner Luke Skywalker MOC')).toBe('action_figures'); expect(hibidCategory('Jewelry, Watches & Gemstones - Watches', 'Rolex Submariner 16610 wristwatch')).toBe('rolex'); expect(hibidCategory('Real Estate - Residential', '3 bedroom house')).toBeNull(); expect(hibidCategory('Construction & Farm - Tractors', 'John Deere 4020')).toBeNull(); expect(hibidCategory('Household - Kitchen', 'Kitchen aid mixer')).toBeNull(); expect(hibidCategory('Firearms & Military - Rifles', 'Winchester Model 70')).toBeNull(); // Liquidators file new merchandise under "Antiques & Collectibles" (seen live: ToyTexx wholesale sale) → filtered. expect(hibidCategory('Antiques & Collectibles - Collectibles - Bakeware', '15PCS Nonstick Roasting Pan with Removable Flat Rack')).toBeNull(); expect(hibidCategory('Antiques & Collectibles - Collectibles - Decorative - Ornaments', '10PCS Christmas Tree Building Sets, 730PC')).toBeNull(); expect(hibidCategory('Antiques & Collectibles - Collectibles - Advertising', 'INFORMATION ONLY - DO NOT BID')).toBeNull(); expect(hibidCategory('Antiques & Collectibles - Collectibles - Advertising', 'Coca-Cola porcelain sign 1950s')).toBe('advertising'); expect(hibidCategory('Antiques & Collectibles - Collectibles - Kitchen', 'Vintage Pyrex Gooseberry bowl 1958')).toBe('antiques'); expect(hibidCategory('Antiques & Collectibles - Collectibles', 'Vintage 1960s Zippo lighter')).toBe('lighters'); expect(isFirearm('Antiques & Collectibles - Collectibles Remington .22 caliber rifle')).toBe(true); expect(isFirearm('1-1954 DEVIL FACE 20 DOLLAR BILL')).toBe(false); expect(slugify('Elite Auction SALE – Fine Jewelry, Rolex Watches, Art & Coll')).toBe('elite-auction-sale-fine-jewelry-rolex-watches-art-coll'); }); it('parses the past-auction list (archived auctions + paging)', () => { // Real page shape reduced to one auction entry. const past = ``; const list = parsePastAuctions(past)!; expect(list).toMatchObject({ pageNumber: 2, totalCount: 1324, pageLength: 25 }); expect(list.auctions).toEqual([{ id: '770300', eventName: '09/07/2026 @ 10am CT - Annual Labor Day: Fine Auction', url: 'https://hibid.com/catalog/770300/09-07-2026-10am-ct-annual-labor-day-fine-auction', bidCloseDateTime: '2026-09-07T23:00:00', eventDateEnd: '2026-09-07T00:00:00', lotCount: 455, status: 'ARCHIVED' }]); }); it('normalises only closed lots with a published price realized (hammer, CAD, premium not included)', async () => { const cat = parseCatalog(CATALOG_HTML, 1)!; const payload = { kind: 'hibid_catalog_page', auction: cat.auction, page: 1, totalCount: cat.totalCount, lots: cat.lots.filter((l) => l.mappable).map(({ mappable: _m, ...rest }) => rest) }; const out = await connector.normalize({ url: 'https://hibid.com/catalog/752746/auction-200-silver-and-paper-money', externalId: 'catalog:752746:page:1', kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T08:00:00Z'), payload }); expect(out.length).toBe(1); const s = out[0]!; if (s.kind !== 'sale') throw new Error('expected sale'); expect(s).toMatchObject({ price: 48, currency: 'CAD', buyerPremiumIncluded: false, auctionHouse: 'Legacy Auctions (HiBid)', lotNumber: '93', location: 'Leamington, ON, Canada', quantity: 1, isBundle: false }); expect(s.saleDate.toISOString()).toBe('2026-09-07T19:00:00.000Z'); expect(s.attributes.categorySlug).toBe('banknotes'); expect(s.attributes.identifiers).toEqual({ hibid_lot_id: '308002776', hibid_auction_id: '752746' }); expect(s.attributes.metadata).toMatchObject({ buyer_premium_text: 'Buyers Premium 18%', category_path: 'Coins & Currency - Currency - World' }); expect(s.attributes.year).toBe(1954); }); it('skips unsupported currencies and firearms at normalisation time', async () => { const cat = parseCatalog(CATALOG_HTML, 1)!; const lots = cat.lots.filter((l) => l.mappable).map(({ mappable: _m, ...rest }) => rest); const gun = { ...lots[1]!, id: '1', title: 'Winchester Model 94 rifle .30-30', categoryPath: 'Antiques & Collectibles - Collectibles', priceRealized: 500 }; const mxn = await connector.normalize({ url: 'x', externalId: 'e', kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: { kind: 'hibid_catalog_page', auction: { ...cat.auction, currency: 'MXN' }, page: 1, totalCount: 3, lots } }); expect(mxn.length).toBe(0); const withGun = await connector.normalize({ url: 'x', externalId: 'e', kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: { kind: 'hibid_catalog_page', auction: cat.auction, page: 1, totalCount: 3, lots: [...lots, gun] } }); expect(withGun.map((r) => ('externalId' in r ? r.externalId : null))).toEqual(['308002776']); }); it('fixture sales are CAD/USD hammer prices dated by the auction close', async () => { const out = await connector.normalize(loadFixture('hibid', 'coins-1').raw); expect(out.length).toBeGreaterThan(0); for (const r of out) { if (r.kind !== 'sale') throw new Error('expected sale'); expect(['CAD', 'USD']).toContain(r.currency); expect(r.buyerPremiumIncluded).toBe(false); } }); });