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%
7.9 KB · 82 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import { readFileSync } from 'node:fs';3import path from 'node:path';4import { fileURLToPath } from 'node:url';5import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';6import { localMeta } from '../../api/_lib/local-meta.js';7import createConnector, { parseCategoryPage, parseResultsPage, parseSaleHeader } from './index.js';8import { parseAuctionDate, parseCoinGrade, realized } from '../_g5-numismatics-lib/index.js';910const dir = path.dirname(fileURLToPath(import.meta.url));11const connector = createConnector(localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8'))));1213const RESULTS = `<table><tr><td class="firmcell"><a href="https://www.numisbids.com/firmprofile/1"><img src="x.gif" alt="CNG"></a></td><td><a href="https://www.numisbids.com/event/14682"><b>Electronic Auction 616</b></a> <a class="descr" href="https://www.numisbids.com/r.php?e=14682">- CNG</a><br> <a class="descr" href="https://www.numisbids.com/event/14682">1114 Lots of Ancient and World Coins</a></td><td width="80px"><a href="https://www.numisbids.com/pr/11008">Prices realized</a></td><td class="date"><div class="innerdate"><div class="datetext">2nd</div></div></td></tr>14<tr><td class="firmcell"><a href="https://www.numisbids.com/firmprofile/354"><img src="x.gif" alt="Java Auction"></a></td><td><a href="https://www.numisbids.com/event/14638"><b>Auction 32</b></a> <a class="descr" href="https://www.numisbids.com/r.php?e=14638">- Java Auction</a><br> <a class="descr" href="https://www.numisbids.com/event/14638">Coins &amp; Banknotes</a></td><td width="80px"></td><td class="date"><div class="innerdate"><div class="datetext">5th - 6th</div></div></td></tr></table>`;1516const SALE = `<ul><li><a href="https://www.numisbids.com/sale/5000/category/153040">Banknotes (677)</a></li><li><a href="https://www.numisbids.com/sale/5000/category/153044">Medals (191)</a></li></ul>17<div class="salestatus"><a class="firminfopopup" href="https://www.numisbids.com/firminformation/211?sid=5000"><img src="l.gif"></a><div class="text"><span class="name">Goudwisselkantoor Veilingen</span><br><b>Auction 1182 and 1183</b>&nbsp;&nbsp;8,11 Oct 2021<br><b><a href="https://www.numisbids.com/pr/5000">View prices realized</a></b></div></div>18<div class="salenav salenav-top"><span class="small">Page 2 of 7</span>&nbsp;&nbsp;<a href="https://www.numisbids.com/sale/5000/category/153040?pg=3">Next&nbsp;»</a></div>19<div class="browse"><a class="anchor" name="l101"></a><div class="browsetext-top"><div class="left"><span class="lot"><a href="https://www.numisbids.com/sale/5000/lot/101">Lot 101</a></span></div><div class="right"><span class="estimate">Estimate: <span class="rateclick" data-message="x">50 EUR</span></span></div></div><div class="browseimg"><a href="https://www.numisbids.com/sale/5000/lot/101"><img src="https://media.numisbids.com/sales/hosted/gwk/1182/thumb00101.jpg" alt="Lot 101 image"></a></div><div class="browsetext"><span class="summary"><a href="https://www.numisbids.com/sale/5000/lot/101">Netherlands, 10 Gulden 1953 banknote, Pick 85, PMG 66 EPQ, Gem Uncirculated...</a></span><div class="bottom"><div class="right"><div class="realized">Price realized: <span class="rateclick" data-message="x">70 EUR</span></div></div></div></div></div>20<div class="browse"><a class="anchor" name="l102"></a><div class="browsetext-top"><div class="left"><span class="lot"><a href="https://www.numisbids.com/sale/5000/lot/102">Lot 102</a></span></div><div class="right"><span class="estimate">Estimate: <span class="rateclick" data-message="x">100 EUR</span></span></div></div><div class="browseimg"><a href="https://www.numisbids.com/sale/5000/lot/102"><img src="https://media.numisbids.com/sales/hosted/gwk/1182/thumb00102.jpg" alt="Lot 102 image"></a></div><div class="browsetext"><span class="summary"><a href="https://www.numisbids.com/sale/5000/lot/102">Lot of 25 banknotes, Netherlands Indies, various, mostly VF</a></span><div class="bottom"><div class="right"></div></div></div></div>`;2122describe('numisbids', () => {23  runFixtureSuite(connector, it, expect);2425  it('parses the results page: only sales with a "Prices realized" link on NumisBids', () => {26    const r = parseResultsPage(RESULTS);27    expect(r).toEqual([{ sid: '11008', eventId: '14682', firm: 'CNG', title: 'Electronic Auction 616', subtitle: '1114 Lots of Ancient and World Coins', dayText: '2nd' }]);28  });2930  it('parses the sale header, category list and paginated category page', () => {31    const h = parseSaleHeader(SALE, '5000');32    expect(h).not.toBeNull();33    expect(h!.sale).toEqual({ sid: '5000', firm: 'Goudwisselkantoor Veilingen', title: 'Auction 1182 and 1183', dateText: '8,11 Oct 2021' });34    expect(h!.hasPrices).toBe(true);35    expect(h!.categories).toEqual([{ cid: '153040', name: 'Banknotes', count: 677 }, { cid: '153044', name: 'Medals', count: 191 }]);36    const p = parseCategoryPage(SALE, h!.sale, h!.categories[0]!, 'https://www.numisbids.com/sale/5000/category/153040?pg=2');37    expect(p.page).toBe(2);38    expect(p.totalPages).toBe(7);39    expect(p.lots.length).toBe(2);40    expect(p.lots[0]).toMatchObject({ lotNumber: '101', estimateText: '50 EUR', realizedText: '70 EUR', image: 'https://media.numisbids.com/sales/hosted/gwk/1182/thumb00101.jpg', url: 'https://www.numisbids.com/sale/5000/lot/101' });41    expect(p.lots[1]!.realizedText).toBeNull();42  });4344  it('normalises sold lots as hammer sales in the printed currency, dated by the sale header', async () => {45    const h = parseSaleHeader(SALE, '5000')!;46    const payload = parseCategoryPage(SALE, h.sale, h.categories[0]!, 'u');47    const out = await connector.normalize({ url: 'u', externalId: 'x', kind: 'sale', engine: 'firecrawl', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload });48    expect(out.length).toBe(1); // lot 102 unsold49    const s = out[0]!;50    if (s.kind !== 'sale') throw new Error('sale');51    expect(s).toMatchObject({ price: 70, currency: 'EUR', buyerPremiumIncluded: false, lotNumber: '101', auctionHouse: 'Goudwisselkantoor Veilingen', isBundle: false });52    expect(s.saleDate.toISOString()).toBe('2021-10-08T00:00:00.000Z');53    expect(s.attributes.categorySlug).toBe('banknotes');54    expect(s.attributes.country).toBe('NL');55    expect(s.attributes.year).toBe(1953);56    expect(s.grade).toMatchObject({ grader: 'pmg', grade: '66 EPQ' });57    expect(s.attributes.identifiers.numisbids_lot).toBe('5000/101');58    expect(s.attributes.metadata.estimate).toBe(50);59  });6061  it('helpers: dates, prices, grades', () => {62    expect(parseAuctionDate('2 Sep 2026')?.toISOString()).toBe('2026-09-02T00:00:00.000Z');63    expect(parseAuctionDate('8,11 Oct 2021')?.toISOString()).toBe('2021-10-08T00:00:00.000Z');64    expect(parseAuctionDate('7-11 Sep 2026')?.toISOString()).toBe('2026-09-07T00:00:00.000Z');65    expect(realized('160 USD')).toEqual({ amount: 160, currency: 'USD' });66    expect(realized("CHF 1'200")).toEqual({ amount: 1200, currency: 'CHF' });67    expect(realized('--')).toBeNull();68    expect(realized('W/D')).toBeNull();69    expect(parseCoinGrade('1881-S Morgan Dollar PCGS MS65+ CAC #12345678')).toMatchObject({ grader: 'pcgs', grade: 'MS65+', qualifier: 'CAC', certificationNumber: '12345678' });70    expect(parseCoinGrade('NGC AU 58 1911 Sovereign')).toMatchObject({ grader: 'ngc', grade: 'AU58' });71    expect(parseCoinGrade('Kings of Mercia, Coenwulf Penny, good very fine')).toMatchObject({ grader: null, grade: null, conditionRaw: 'good very fine' });72  });7374  it('fixture lots normalise to hammer sales in USD', async () => {75    const out = await connector.normalize(loadFixture('numisbids', 'category-page-celtic').raw);76    expect(out.length).toBe(14);77    for (const r of out) if (r.kind === 'sale') expect(r).toMatchObject({ currency: 'USD', buyerPremiumIncluded: false, auctionHouse: 'Classical Numismatic Group, Inc.' });78    const fx = loadFixture('numisbids', 'category-page-paginated');79    expect((fx.raw.payload as { totalPages: number }).totalPages).toBe(3);80  });81});82