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%
6.8 KB · 94 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 { runFixtureSuite } from '@rareindex/connectors/testing';6import { localMeta } from '../_lib/local-meta.js';7import { decodeEntities } from '../_g7-auctions-na-lib/index.js';8import createConnector, { parseInfoPage, parseSessionPage, ragoCategory, sessionUrlFromSitemap, WRIGHT } from './index.js';9import { asInertiaHtml, INFO_JSON, SESSION_JSON } from './test-data.js';1011const dir = path.dirname(fileURLToPath(import.meta.url));12const meta = localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8')));13const connector = createConnector(meta);1415describe('wright', () => {16  runFixtureSuite(connector, it, expect);1718  it('derives session URLs from the sitemap index names', () => {19    expect(sessionUrlFromSitemap(WRIGHT.site, 'https://www.wright20.com/sitemaps/sessions/sitemap-auctions_2000_12_the-american-scene-art-of-the-1930s-and-1940s.xml')).toBe('https://www.wright20.com/auctions/2000/12/the-american-scene-art-of-the-1930s-and-1940s');20    expect(sessionUrlFromSitemap(WRIGHT.site, 'https://www.wright20.com/sitemaps/sitemap-artists.xml')).toBeNull();21  });2223  it('parses the Inertia data-page (entities decoded) into session + items', () => {24    const html = asInertiaHtml(SESSION_JSON);25    expect(decodeEntities('&quot;a&amp;b&quot;')).toBe('"a&b"');26    const p = parseSessionPage(html, WRIGHT, 'https://www.wright20.com/auctions/2026/08/design')!;27    expect(p.session).toMatchObject({ id: '2884', title: 'Design', date: '2026-08-13T16:00:00.000000Z', startDate: 1786636800, showResults: true, archive: true, preliminary: false, resultsIncludePremium: null });28    expect(p.items.length).toBe(3);29    const calder = p.items.find((i) => i.id === '413032')!;30    expect(calder).toMatchObject({ id: '413032', lotNumber: '100', artist: 'After Alexander Calder', name: 'Turquoise tapestry', estimateLow: 15000, estimateHigh: 20000, result: 57600, bidCount: 14, location: 'Los Angeles' });31    const miro = p.items.find((i) => i.id === '412274')!;32    expect(miro.result).toBeNull(); // `result: false` = unsold / not shown33    expect(miro.artist).toBe('After Joan Miró');34    expect(parseInfoPage(asInertiaHtml(INFO_JSON))).toEqual({ endedAt: '2026-08-13T18:58:44.000000Z', resultsIncludePremium: true });35    expect(parseSessionPage('<html><body>no app</body></html>', WRIGHT, 'https://www.wright20.com/x')).toBeNull();36  });3738  it('normalises sold lots only, dated by the close time, premium flag from the info page', async () => {39    const p = parseSessionPage(asInertiaHtml(SESSION_JSON), WRIGHT, 'https://www.wright20.com/auctions/2026/08/design')!;40    const info = parseInfoPage(asInertiaHtml(INFO_JSON));41    p.session.endedAt = info.endedAt;42    p.session.resultsIncludePremium = info.resultsIncludePremium;43    const out = await connector.normalize({ url: 'https://www.wright20.com/auctions/2026/08/design', externalId: 'session:2884', kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload: p });44    expect(out.length).toBe(2);45    const s = out.find((r) => 'externalId' in r && r.externalId === '413032')!;46    if (s.kind !== 'sale') throw new Error('expected sale');47    expect(s).toMatchObject({ price: 57600, currency: 'USD', buyerPremiumIncluded: true, auctionHouse: 'Wright', lotNumber: '100', rawTitle: 'After Alexander Calder, Turquoise tapestry', location: 'Los Angeles' });48    expect(s.saleDate.toISOString()).toBe('2026-08-13T18:58:44.000Z');49    expect(s.sourceUrl).toBe('https://www.wright20.com/auctions/2026/08/design/100');50    expect(s.attributes).toMatchObject({ categorySlug: 'design_furniture', name: 'Turquoise tapestry', brand: null });51    expect(s.attributes.identifiers).toEqual({ wright_item_id: '413032' });52    expect(s.attributes.metadata).toMatchObject({ artist: 'After Alexander Calder', estimate_low: 15000, estimate_high: 20000, bid_count: 14 });53    // without the info page the premium basis is unknown and the auction date is used54    p.session.endedAt = null;55    p.session.resultsIncludePremium = null;56    const out2 = await connector.normalize({ url: 'x', externalId: 'e', kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload: p });57    const s2 = out2.find((r) => 'externalId' in r && r.externalId === '413032')!;58    if (s2.kind !== 'sale') throw new Error('expected sale');59    expect(s2.buyerPremiumIncluded).toBeNull();60    expect(s2.saleDate.toISOString()).toBe('2026-08-13T16:00:00.000Z');61  });6263  it('emits auction lots for future sessions and lowers confidence on preliminary results', async () => {64    const future = JSON.parse(JSON.stringify(SESSION_JSON)) as typeof SESSION_JSON;65    const nextYear = Math.floor(Date.now() / 1000) + 30 * 86_400;66    future.props.sessions['2884']!.start_date = nextYear;67    future.props.sessions['2884']!.archive_auction = 0;68    future.props.sessions['2884']!.sale_status = 'PRESALE';69    for (const it of Object.values(future.props.items)) (it as { result: number | boolean }).result = false;70    const p = parseSessionPage(asInertiaHtml(future), WRIGHT, 'https://www.wright20.com/auctions/2026/08/design')!;71    const out = await connector.normalize({ url: 'x', externalId: 'e', kind: 'auction_lot', engine: 'api', fetchedAt: new Date(), payload: p });72    expect(out.length).toBe(3);73    expect(out.every((r) => r.kind === 'auction_lot')).toBe(true);74    const lot = out.find((r) => 'externalId' in r && r.externalId === '413032')!;75    if (lot.kind !== 'auction_lot') throw new Error('expected lot');76    expect(lot).toMatchObject({ auctionHouse: 'Wright', auctionName: 'Design', estimateLow: 15000, estimateHigh: 20000, status: 'upcoming', currency: 'USD' });7778    const prelim = parseSessionPage(asInertiaHtml(SESSION_JSON), WRIGHT, 'https://www.wright20.com/auctions/2026/08/design')!;79    prelim.session.preliminary = true;80    const out2 = await connector.normalize({ url: 'x', externalId: 'e', kind: 'sale', engine: 'api', fetchedAt: new Date(), payload: prelim });81    expect((out2[0] as { confidence: number }).confidence).toBe(0.75);82    expect((out2[0] as { attributes: { metadata: Record<string, unknown> } }).attributes.metadata.preliminary).toBe(true);83  });8485  it('maps sale titles to taxonomy slugs', () => {86    expect(ragoCategory('Design', 'Sam Maloof, Coffee table')).toBe('design_furniture');87    expect(ragoCategory('Art + Design', 'Takashi Murakami, Flowers screenprint')).toBe('contemporary_art');88    expect(ragoCategory('Photographs', 'Irving Penn, gelatin silver print')).toBe('photography');89    expect(ragoCategory('Jewelry', 'Rolex, Submariner wristwatch')).toBe('rolex');90    expect(ragoCategory('Art of Africa, Oceania and the Americas', 'Yoruba, mask')).toBe('antiques');91    expect(ragoCategory('Scandinavian Design', 'Hans Wegner, Papa Bear chair')).toBe('design_furniture');92  });93});94