TypeScript 61.9%
HTML 37.2%
SQL 0.7%
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&pn=2&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&au=1306&sd=1&pp=96&pn=1&g=1"> <img src="https://sworders.goauction.co.uk/stock/682769-2-small.jpg?v=1" alt="Lot 2 - Børge Mogensen (Danish, 1914-1972) for P Lauritsen & Søn" /> </a> </div> <div class="auction-lot-text "> <p class="auction-lot-title"> <a href="/auction/lot/lot-2---brge-mogensen/?lot=565336&au=1306&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&au=1306&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