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.3 KB · 76 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import { getConnectorMeta } from '@rareindex/connectors';3import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';4import createConnector, { categoryPageAuctionIds, classifyLot, parseAuctionPage, parseLotPage, type AuctionLotsPayload, type LotPayload } from './index.js';56const connector = createConnector(getConnectorMeta('catawiki'));78describe('catawiki connector', () => {9  runFixtureSuite(connector, it, expect);1011  it('turns a closed, sold lot into a hammer-price sale in EUR with the source end time', async () => {12    const fx = loadFixture('catawiki', 'seeded-1');13    const lot = fx.raw.payload as LotPayload;14    const out = await connector.normalize(fx.raw);15    expect(out).toHaveLength(1);16    const r = out[0]!;17    if (r.kind !== 'sale') throw new Error('expected sale');18    expect(r.price).toBe(lot.bidding.finalBidEur);19    expect(r.currency).toBe('EUR');20    expect(r.buyerPremiumIncluded).toBe(false);21    expect(r.saleDate.getTime()).toBe(lot.bidding.biddingEndTime);22    expect(r.auctionHouse).toBe('Catawiki');23    expect(r.location).toBe(lot.sellerCountry);24    expect(r.attributes.identifiers.catawiki_lot_id).toBe(String(lot.id));25    expect(r.attributes.metadata.estimate_min_eur).toBe(lot.estimateMinEur);26    expect(r.attributes.material).toBe('Wood');27    expect(r.attributes.categorySlug).toBe('antiques');28  });2930  it('drops closed-unsold lots and emits live lots as auction_lot', async () => {31    const fx = loadFixture('catawiki', 'seeded-1');32    const lot = structuredClone(fx.raw.payload) as LotPayload;33    const unsold = { ...lot, bidding: { ...lot.bidding, sold: false } };34    expect(await connector.normalize({ ...fx.raw, payload: unsold })).toHaveLength(0);35    const live = { ...lot, bidding: { ...lot.bidding, closed: false, sold: null, biddingEndTime: Date.now() + 3 * 86_400_000 } };36    const out = await connector.normalize({ ...fx.raw, payload: live });37    expect(out).toHaveLength(1);38    expect(out[0]!.kind).toBe('auction_lot');39    if (out[0]!.kind === 'auction_lot') {40      expect(out[0]!.status).toBe('live');41      expect(out[0]!.currentBid).toBe(lot.bidding.finalBidEur);42      expect(out[0]!.estimateLow).toBe(lot.estimateMinEur);43    }44  });4546  it('emits auction_lot records for a live themed auction and none for a stale one', async () => {47    const fx = loadFixture('catawiki', 'seeded-2');48    const payload = structuredClone(fx.raw.payload) as AuctionLotsPayload;49    const future = new Date(Date.now() + 2 * 86_400_000).toISOString();50    payload.auction = { ...payload.auction, closeAt: future, startAt: new Date(Date.now() - 86_400_000).toISOString() };51    const out = await connector.normalize({ ...fx.raw, payload });52    expect(out.length).toBeGreaterThan(payload.lots.length * 0.8);53    for (const r of out) {54      expect(r.kind).toBe('auction_lot');55      if (r.kind !== 'auction_lot') continue;56      expect(r.endsAt?.toISOString()).toBe(new Date(future).toISOString());57      expect(r.currency).toBe('EUR');58      expect(['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches', 'pens', 'lighters', 'clocks', 'jewelry']).toContain(r.attributes.categorySlug);59    }60    const stale = { ...payload, auction: { ...payload.auction, closeAt: '2020-01-01T00:00:00Z' } };61    expect(await connector.normalize({ ...fx.raw, payload: stale })).toHaveLength(0);62  });6364  it('classifies lots from category path, specs and titles', () => {65    const base: LotPayload = { kind: 'lot', seedHint: 'toys', id: 1, url: 'https://www.catawiki.com/en/l/1', title: 'LEGO - Star Wars - 10179 - Millennium Falcon UCS', subtitle: 'Sealed', description: null, images: [], categoryId: null, categoryUrl: null, auction: { id: 1, title: 'LEGO Auction', url: 'https://www.catawiki.com/en/a/1', status: 'closed', startAt: null, closeAt: null, closedAt: null, categories: ['Toys & Models', 'LEGO'], lotCount: null }, specs: [{ name: 'Set number', value: '10179' }], estimateMinEur: null, estimateMaxEur: null, sellerCountry: 'NL', sellerName: null, sellerIsPro: null, bidding: { closed: true, sold: true, finalBidEur: 2500, biddingStartTime: null, biddingEndTime: 1, bidCount: null, reservePriceMet: null } };66    expect(classifyLot(base).slug).toBe('lego_sets');67    expect(classifyLot({ ...base, seedHint: 'cards', title: 'Pokémon - Charizard Base Set 4/102 - PSA 9', auction: { ...base.auction!, categories: ['Trading Cards', 'Pokémon'] } }).slug).toBe('pokemon');68    expect(classifyLot({ ...base, seedHint: 'watches', title: 'Rolex - Submariner 16610 - Men - 2005', auction: { ...base.auction!, categories: ['Watches, Pens & Lighters', 'Watches'] } }).slug).toBe('rolex');69    expect(classifyLot({ ...base, seedHint: 'wine', title: 'Macallan 18 Sherry Oak 2020 release', auction: { ...base.auction!, categories: ['Wine, Whisky & Spirits', 'Whisky'] } }).slug).toBe('whisky');70    expect(classifyLot({ ...base, seedHint: 'coins', title: 'Netherlands 10 Gulden 1875 gold', auction: { ...base.auction!, categories: ['Coins & Stamps', 'Coins'] } }).slug).toBe('coins');71    expect(categoryPageAuctionIds('<a href="/en/a/1263062-vintage"></a><a href="https://www.catawiki.com/en/a/1263062-vintage"></a><a href="/en/a/99-x">')).toEqual([1263062, 99]);72    expect(parseAuctionPage('<html></html>')).toBeNull();73    expect(parseLotPage('<html></html>', 'https://www.catawiki.com/en/l/1', 'unknown')).toBeNull();74  });75});76