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%
5.7 KB · 62 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import type { NormalizedRecord } from '@rareindex/shared';3import { ConnectorMetaSchema } from '@rareindex/connectors';4import { listFixtures, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';5import metaJson from './meta.json' with { type: 'json' };6import createConnector, { parseAuDate, parseResultsIndex, parseResultsPage } from './index.js';78const meta = ConnectorMetaSchema.parse(metaJson);9const connector = createConnector(meta);10const attrsOf = (r: NormalizedRecord) => {11  if (!('attributes' in r)) throw new Error(`record kind ${r.kind} has no attributes`);12  return r.attributes;13};1415const INDEX = `<section class="flexible-auction-calendar-item col-2"> <div class="flexible-auction-calendar-item__date"> <p>7&nbsp;September</p> </div> <div class="flexible-auction-calendar-item__image" onclick="location.href='/custom_asp/searchresults.asp?type=result&st=D&amp;pg=1&amp;ps=100&amp;sale_no=IT127++';"></div> <div class="flexible-auction-calendar-item__lot"> <p>Sale IT127</p> </div> <div class="flexible-auction-calendar-item__heading"> <h3>Modern Design</h3> </div> <div class="flexible-auction-calendar-item__auction-details"> <p class="flexible-auction-calendar-item__sub-title">AUCTION</p> <p>Monday 7 Sep 2026, 10:00am</p> <p class="online">Timed Online Auction (Melbourne)</p> </div></section>16<section class="flexible-auction-calendar-item col-2"><h3>Fine Jewels Sydney</h3><a href="/custom_asp/searchresults.asp?type=result&st=D&amp;pg=1&amp;ps=100&amp;sale_no=LJ8818+">Browse</a><div class="flexible-auction-calendar-item__auction-details"><p>Monday 17 Aug 2026, 6:30pm</p><p class="online">Live Auction (Sydney)</p></div></section>`;1718const PAGE = `<h1>Fine Jewels Sydney</h1><p> Sale: LJ8818<br> 17 August 2026, 6:30pm <em>36-40 Queen Street, Woollahra</em> </p>19<section class="flexible-auction-item auction-collection-item col-2 col-md-1"> <a id="40936777"></a> <a href="https://auctions.leonardjoel.com.au/asp/fullCatalogue.asp?salelot=LJ8818+++201+&amp;refno=40936777&saletype= "><div class="flexible-auction-item__image" style="background-image: url(https://auctions.leonardjoel.com.au/Thumb//777/40936777tn.jpg);"></div></a> <div class="flexible-auction-item__heading"> <h6>Lot 201</h6> <h4>ROBERT CLERC EGYPTIAN COLLECTION LAPIS LAZULI, EMERALD, QUARTZ AND DIAMOND NECKLACE, CIRCA 1993 Property of a Private New South Wa...</h4> </div> <div class="flexible-auction-item__lot"> <p>Estimate:<br/> $4,600&nbsp;-&nbsp;5,500<p><b>Sold for $8,500</b></p></i> </div> </section>20<section class="flexible-auction-item auction-collection-item col-2 col-md-1"> <a href="https://auctions.leonardjoel.com.au/asp/fullCatalogue.asp?salelot=LJ8818+++202+&amp;refno=40936778&saletype= "><div class="flexible-auction-item__image"></div></a> <div class="flexible-auction-item__heading"> <h6>Lot 202</h6> <h4>ROLEX DATEJUST WRISTWATCH REF 16233</h4> </div> <div class="flexible-auction-item__lot"> <p>Estimate:<br/> $8,000&nbsp;-&nbsp;12,000</p> </div> </section>21<div class="pagination"><ul><li><a href='/custom_asp/searchresults.asp?type=result&st=D&pg=2&ps=100&sale_no=LJ8818'>2</a><a href='/custom_asp/searchresults.asp?type=result&st=D&ps=100&pg=2&sale_no=LJ8818'>&rarr;</a></li></ul></div>`;2223describe('leonard-joel', () => {24  runFixtureSuite(connector, it, expect);2526  it('fixtures: AUD "Sold for" results', async () => {27    let sales = 0;28    for (const name of listFixtures('leonard-joel')) {29      for (const r of await connector.normalize(loadFixture('leonard-joel', name).raw)) {30        if (!('attributes' in r)) continue;31        expect(r.attributes.identifiers.leonard_joel_lot).toMatch(/^[A-Z]{1,3}\d+\/\S+$/);32        expect(r.sourceUrl).toMatch(/^https:\/\/auctions\.leonardjoel\.com\.au\//);33        if (r.kind === 'sale') {34          sales++;35          expect(r.currency).toBe('AUD');36          expect(r.buyerPremiumIncluded).toBeNull();37          expect(r.auctionHouse).toBe('Leonard Joel');38        }39      }40    }41    expect(sales).toBeGreaterThan(10);42  });4344  it('parses the results index and a results page (AUD, estimates, pagination)', async () => {45    const sales = parseResultsIndex(INDEX);46    expect(sales.map((s) => s.id)).toEqual(['IT127', 'LJ8818']);47    expect(sales[0]).toMatchObject({ title: 'Modern Design', date: '2026-09-07T00:00:00.000Z', location: 'Melbourne' });48    expect(parseAuDate('17 August 2026, 6:30pm')).toBe('2026-08-17T00:00:00.000Z');49    const p = parseResultsPage(PAGE, sales[1]!, 1)!;50    expect(p.hasMore).toBe(false); // only 2 lots (< page size) even though a page-2 link exists51    expect(p.sale).toMatchObject({ title: 'Fine Jewels Sydney', date: '2026-08-17T00:00:00.000Z', location: '36-40 Queen Street, Woollahra' });52    expect(p.lots[0]).toMatchObject({ lotNo: '201', price: 8500, currency: 'AUD', premiumIncluded: null, estimateLow: 4600, estimateHigh: 5500, sold: true, image: 'https://auctions.leonardjoel.com.au/Thumb//777/40936777tn.jpg' });53    expect(p.lots[0]!.url).toBe('https://auctions.leonardjoel.com.au/asp/fullCatalogue.asp?salelot=LJ8818+++201+&refno=40936777&saletype=');54    expect(p.lots[1]).toMatchObject({ lotNo: '202', price: null, sold: false, estimateLow: 8000, estimateHigh: 12000 });55    const out = await connector.normalize({ url: sales[1]!.url, kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: { kind: 'sale_results', url: sales[1]!.url, sale: { ...sales[1]!, ...p.sale, extra: sales[1]!.extra }, page: 1, totalLots: null, lots: p.lots } });56    expect(out.map((r) => r.kind)).toEqual(['sale', 'auction_lot']);57    expect(attrsOf(out[0]!).categorySlug).toBe('jewelry');58    expect(attrsOf(out[1]!).categorySlug).toBe('rolex');59    expect(parseResultsPage('<html>x</html>', sales[1]!, 1)).toBeNull();60  });61});62