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.8 KB · 66 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 from './index.js';7import { goauctionPageUrl, parseGoauctionCalendar, parseGoauctionLots, parseUkDate } from '../_g8-auctions-eu-apac-lib/goauction-platform.js';89const meta = ConnectorMetaSchema.parse(metaJson);10const connector = createConnector(meta);11const attrsOf = (r: NormalizedRecord) => {12  if (!('attributes' in r)) throw new Error(`record kind ${r.kind} has no attributes`);13  return r.attributes;14};15const HOUSE = { base: 'https://www.sworder.co.uk', currency: 'GBP' as const, listStyle: 'details' as const };1617const CAL = `<div class="auction-calendar-item calendar-quarter nv"> <a href='/auction/details/a1320-open-house?au=1367'> <img src="x" alt="Open House" /> </a> <div class="auction-calendar-text "> <a href='/auction/details/a1320-open-house?au=1367'> <H4>Open House</H4> </a> <div> <a href='/auction/details/a1320-open-house?au=1367'> <h5>Tuesday 1 September - Monday 7 September 2026</h5> <p><em>Timed Online | Bidding closes on Monday from 7pm</em></p> <strong>Sale number: A1320</strong> </a> </div> </div> </div>18<div class="auction-calendar-item calendar-quarter nv"> <a href='/auction/details/a1277-design?au=1306'> <div class="auction-calendar-image"> <img src="y" alt="Design" /> </div> </a> <div class="auction-calendar-text "> <a href='/auction/details/a1277-design?au=1306'> <H4>Design</H4> </a> <div> <a href='/auction/details/a1277-design?au=1306'> <h5>Tuesday 21 April 2026</h5> <strong>Sale number: A1277</strong> </a> </div> </div> </div>`;1920const GRID = `<link rel="next" href="/auction/details/a1277-design/?au=1306&amp;pn=2&amp;g=1"/><div class='auction-grid agh'><div class='auction-grid-lot col-sm-6'> <div class="auction-lot"> <span class="corner-flash auction-lot-sold">SOLD</span> <div class="auction-lot-image"> <a href="/auction/lot/lot-2---brge-mogensen/?lot=565336&amp;au=1306&amp;sd=1&amp;pp=96&amp;pn=1&amp;g=1"> <img src="https://sworders.goauction.co.uk/stock/682769-2-small.jpg?v=1" alt="Lot 2 - B&#248;rge Mogensen (Danish, 1914-1972) for P Lauritsen &amp; S&#248;n" /> </a> </div> <div class="auction-lot-text "> <p class="auction-lot-title"> <a href="/auction/lot/lot-2---brge-mogensen/?lot=565336&amp;au=1306&amp;sd=1"> <span class='lot-title cat-9'>Lot 2<br /><span class="req-tag"></span>Børge Mogensen (Danish, 1914-1972) for P Lauritsen & Søn <span class='sub-title cat-9'>a teak desk,</span></span> </a> </p> <p></p> <p> <strong>Sold for £1,800</strong> </p> </div> </div> </div>21<div class='auction-grid-lot col-sm-6'> <div class="auction-lot"> <div class="auction-lot-text "> <p class="auction-lot-title"> <a href="/auction/lot/lot-3---rolex/?lot=565337&amp;au=1306&amp;sd=1"> <span class='lot-title cat-9'>Lot 3<br /><span class="req-tag"></span>Rolex, an Oyster Perpetual Datejust wristwatch ref. 16233 <span class='sub-title cat-9'>steel and gold,</span></span> </a> </p> <p></p> </div> </div> </div></div><nav class="pagination"></nav>`;2223describe('sworders', () => {24  runFixtureSuite(connector, it, expect);2526  it('fixtures: GBP "Sold for" results, premium basis unknown', async () => {27    let sales = 0;28    for (const name of listFixtures('sworders')) {29      for (const r of await connector.normalize(loadFixture('sworders', name).raw)) {30        if (!('attributes' in r)) continue;31        expect(r.attributes.identifiers.sworders_lot).toMatch(/^\d+\/\S+$/);32        expect(r.sourceUrl).toMatch(/^https:\/\/www\.sworder\.co\.uk\//);33        if (r.kind === 'sale') {34          sales++;35          expect(r.currency).toBe('GBP');36          expect(r.buyerPremiumIncluded).toBeNull();37          expect(r.auctionHouse).toBe('Sworders');38        }39      }40    }41    expect(sales).toBeGreaterThan(10);42  });4344  it('parses the results calendar (single dates and ranges) and the lot grid', async () => {45    const sales = parseGoauctionCalendar(CAL, HOUSE);46    expect(sales.map((s) => s.id)).toEqual(['1367', '1306']);47    expect(sales[0]).toMatchObject({ title: 'Open House', date: '2026-09-01T00:00:00.000Z', url: 'https://www.sworder.co.uk/auction/details/a1320-open-house?au=1367' });48    expect(sales[0]!.extra).toMatchObject({ sale_number: 'A1320', timed: true });49    expect(sales[1]!.date).toBe('2026-04-21T00:00:00.000Z');50    expect(parseUkDate('20th August 2026')).toBe('2026-08-20T00:00:00.000Z');51    expect(parseUkDate('nonsense')).toBeNull();52    expect(goauctionPageUrl(sales[1]!, 2, HOUSE)).toBe('https://www.sworder.co.uk/auction/details/a1277-design?au=1306&g=1&pn=2');53    const p = parseGoauctionLots(GRID, sales[1]!, HOUSE)!;54    expect(p.hasMore).toBe(true);55    expect(p.lots).toHaveLength(2);56    expect(p.lots[0]).toMatchObject({ lotNo: '2', title: 'Børge Mogensen (Danish, 1914-1972) for P Lauritsen & Søn', subtitle: 'a teak desk,', price: 1800, currency: 'GBP', premiumIncluded: null, sold: true, image: 'https://sworders.goauction.co.uk/stock/682769-2-small.jpg?v=1', url: 'https://www.sworder.co.uk/auction/lot/lot-2---brge-mogensen/?lot=565336&au=1306&sd=1&pp=96&pn=1&g=1' });57    expect(p.lots[1]).toMatchObject({ lotNo: '3', price: null, sold: false });58    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]!, page: 1, totalLots: null, lots: p.lots } });59    expect(out.map((r) => r.kind)).toEqual(['sale', 'auction_lot']);60    expect(attrsOf(out[0]!).categorySlug).toBe('design_furniture');61    expect(attrsOf(out[1]!).categorySlug).toBe('rolex');62    expect(attrsOf(out[1]!).reference).toBe('16233');63    expect(parseGoauctionLots('<html><body>none</body></html>', sales[1]!, HOUSE)).toBeNull();64  });65});66