TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { describe, expect, it } from 'vitest';2import { readFileSync } from 'node:fs';3import path from 'node:path';4import { fileURLToPath } from 'node:url';5import { ConnectorMetaSchema } from '@rareindex/connectors';6import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';7import createConnector, { parseCatalogPage, parsePastAuctions, swannCategory } from './index.js';89const dir = path.dirname(fileURLToPath(import.meta.url));10const meta = ConnectorMetaSchema.parse(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8')));11const connector = createConnector(meta);1213const LIST = `<div class="event__content"><div class="event__date">Thursday, November 6, 2025</div><h2 class="event__title">Autographs</h2>14<div class="event__department"><a href="https://www.swanngalleries.com/books-manuscripts/autographs/">Autographs</a> - Sale 2719</div>15<ul><li><a class="btn btn-primary btn-cta--view_lots" href="https://www.swanngalleries.com/auction-catalog/autographs_JCJOCA54V5">View Lots</a></li></ul></div>`;1617const CATALOG = `<div data-lot-ref="C337D422B9"><a href="https://www.swanngalleries.com/auction-lot/marlon-brando_c337d422b9"><img src="https://image.invaluable.com/h.jpg"/></a>18<p class="lot-card_card-title__EEZRj">2<!-- -->: <!-- -->Marlon Brando Slip of paper Signed and Inscribed. Np, nd.</p>19<div class="lot-card_estimate-bid__8g2bA"><span>Estimate<!-- -->: </span><span>$600 - $900</span></div>20<div><div class="lot-card_bid-amount__Xp4jF"><strong class="lot-card_amount__WX83V"><span>Sold<!-- -->:</span><span>$1,188</span></strong></div><span>Sold price includes buyer's premium</span></div></div>21<div data-lot-ref="C3359DB2B8"><a href="https://www.swanngalleries.com/auction-lot/tony-bennett_c3359db2b8"><img src="https://image.invaluable.com/t.jpg"/></a>22<p class="lot-card_card-title__EEZRj">1<!-- -->: <!-- -->Tony Bennett. Group of 5 photographs.</p>23<div class="lot-card_estimate-bid__8g2bA"><span>Estimate: </span><span>$600 - $900</span></div><div><span>Passed</span></div></div>`;2425describe('swann', () => {26 runFixtureSuite(connector, it, expect);2728 it('parses the past-auction list and catalog cards', () => {29 const auctions = parsePastAuctions(LIST);30 expect(auctions).toEqual([{ slug: 'autographs_JCJOCA54V5', url: 'https://www.swanngalleries.com/auction-catalog/autographs_JCJOCA54V5', title: 'Autographs', dateText: 'Thursday, November 6, 2025', department: 'Autographs', saleNumber: '2719' }]);31 const page = parseCatalogPage(CATALOG, auctions[0]!, 1);32 expect(page.lots.length).toBe(2);33 expect(page.lots[0]).toMatchObject({ ref: 'C337D422B9', lotNumber: '2', soldText: '$1,188', premiumNote: true, passed: false, estimateText: '$600 - $900' });34 expect(page.lots[1]).toMatchObject({ lotNumber: '1', soldText: null, passed: true });35 });3637 it('normalises sold lots only, premium included, dated by the sale', async () => {38 const auction = parsePastAuctions(LIST)[0]!;39 const out = await connector.normalize({ url: 'x', externalId: 's', kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-07T00:00:00Z'), payload: parseCatalogPage(CATALOG, auction, 1) });40 expect(out.length).toBe(1);41 const s = out[0]!;42 if (s.kind !== 'sale') throw new Error('sale');43 expect(s).toMatchObject({ price: 1188, currency: 'USD', buyerPremiumIncluded: true, lotNumber: '2', auctionHouse: 'Swann Auction Galleries' });44 expect(s.saleDate.toISOString()).toBe('2025-11-06T00:00:00.000Z');45 expect(s.attributes.categorySlug).toBe('autographs');46 expect(swannCategory('Photographs & Photobooks', 'Photographs', 'Ansel Adams')).toBe('photography');47 expect(swannCategory('Vintage Posters', 'Posters', 'Casablanca one sheet')).toBe('movie_posters');48 expect(swannCategory('Maps & Atlases', 'Maps', 'Blaeu, Americae')).toBe('maps');49 });5051 it('fixture sales are USD with lot refs', async () => {52 const out = await connector.normalize(loadFixture('swann', 'catalog-page').raw);53 expect(out.length).toBeGreaterThan(0);54 for (const r of out) if (r.kind === 'sale') expect(r.attributes.identifiers.swann_lot_ref).toBeTruthy();55 });56});57