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%
11.3 KB · 194 lines typescript
Raw Blame History
1import { describe, expect, it } from 'vitest';2import { ConnectorMetaSchema } from '@rareindex/connectors';3import { listFixtures, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';4import metaJson from './meta.json' with { type: 'json' };5import createConnector, { categoryFor, leafCategoryIds, normalizeItem, parseItemsPage, trimItem } from './index.js';6import { isBundleMultilingual, parenCount, parseEuDate, parseEuMoney, yearFromTitle } from '../_g8-auctions-eu-apac-lib/index.js';78const meta = ConnectorMetaSchema.parse(metaJson);9const connector = createConnector(meta);1011const API_ITEM = {12  id: 5224154,13  catalog_number: null,14  auction_id: 9524392,15  currency: 'EUR',16  reserve_met: true,17  reserve_amount: 200,18  estimate: 450,19  upper_estimate: null,20  starting_bid_amount: 25,21  hammered: false,22  state: 'sold',23  title: 'CORTÉBERT, WALTHAM, IMMERFORT ETC., Armbanduhren Konvolut, 20. Jahrhundert. (4).',24  description: '<p>Konvolut bestehend aus vier Armbanduhren: </p>\n\n<p>Cortébert, Handaufzug, 1950er Jahre.</p>',25  condition: '<p>Altersgemäße Gebrauchsspuren.</p>',26  company_id: 237,27  category_id: 15,28  ends_at: 1788854835,29  published_at: 1788164174,30  type: 'online',31  location: 'Cologne',32  house: 'Stockholms Auktionsverk Köln',33  placement: 'auf Anfrage',34  url: 'https://auctionet.com/en/5224154-cortebert-waltham-immerfort-etc-wristwatch-collection-20th-century-4',35  images: [{ thumb: 't.jpg', mini: 'm.jpg', w640: 'https://images.auctionet.com/thumbs/w640_item_5224154_x.jpg', hd: 'hd.jpg' }],36  bids: [37    { id: 42504089, bidder: 7, amount: 220, your_bid: false, reserve_met: true, auto: false, timestamp: 1788854655 },38    { id: 42502618, bidder: 4, amount: 200, your_bid: false, reserve_met: true, auto: false, timestamp: 1788846567 },39  ],40};4142describe('auctionet', () => {43  runFixtureSuite(connector, it, expect);4445  it('fixtures: sold lots become hammer-basis sales in native currency, unsold lots become ended auction_lots', async () => {46    let sales = 0;47    let lots = 0;48    for (const name of listFixtures('auctionet')) {49      const fx = loadFixture('auctionet', name);50      const out = await connector.normalize(fx.raw);51      for (const r of out) {52        if (!('attributes' in r)) continue;53        expect(r.attributes.identifiers.auctionet_item_id).toMatch(/^\d+$/);54        expect(r.sourceUrl).toMatch(/^https:\/\/auctionet\.com\/en\/(events\/[^/]+\/)?\d+-/);55        if (r.kind === 'sale') {56          sales++;57          expect(['SEK', 'EUR', 'DKK', 'GBP']).toContain(r.currency);58          expect(r.buyerPremiumIncluded).toBe(false);59          expect(r.attributes.metadata.price_basis).toBe('winning_bid_excl_buyer_fee');60          expect(r.auctionHouse).toBeTruthy();61          expect(r.saleDate.getUTCFullYear()).toBeGreaterThanOrEqual(2011);62        } else if (r.kind === 'auction_lot') {63          lots++;64          expect(r.status).toBe('ended');65        }66      }67    }68    expect(sales).toBeGreaterThan(20);69    expect(lots).toBeGreaterThan(0);70  });7172  it('trims the API item and normalises it (winning bid = hammer, EUR, bundle of 4)', () => {73    const item = trimItem(API_ITEM);74    expect(item).toMatchObject({ id: 5224154, currency: 'EUR', state: 'sold', winningBid: 220, winningBidAt: 1788854655, bidCount: 2, house: 'Stockholms Auktionsverk Köln', location: 'Cologne', categoryId: 15 });75    expect(item.images).toEqual(['https://images.auctionet.com/thumbs/w640_item_5224154_x.jpg']);76    expect(item.description).toBe('Konvolut bestehend aus vier Armbanduhren: Cortébert, Handaufzug, 1950er Jahre.');77    const rec = normalizeItem(meta, item, new Date('2026-09-08T10:00:00Z'));78    expect(rec?.kind).toBe('sale');79    if (rec?.kind !== 'sale') return;80    expect(rec.price).toBe(220);81    expect(rec.currency).toBe('EUR');82    expect(rec.saleDate.toISOString()).toBe('2026-09-08T08:07:15.000Z');83    expect(rec.isBundle).toBe(true);84    expect(rec.attributes.categorySlug).toBe('other_watches');85    expect(rec.attributes.year).toBeNull(); // "20. Jahrhundert", "(4)" — no year86    expect(rec.buyerPremiumIncluded).toBe(false);87    expect(rec.lotNumber).toBeNull();88    expect(rec.condition.conditionRaw).toBe('Altersgemäße Gebrauchsspuren.');89  });9091  it('unsold and out-of-taxonomy items', () => {92    const unsold = trimItem({ ...API_ITEM, id: 1, state: 'unsold', bids: [], category_id: 128, title: 'MYNT, 5 kronor, Sverige 1955.' });93    const rec = normalizeItem(meta, unsold, new Date());94    expect(rec?.kind).toBe('auction_lot');95    if (rec?.kind === 'auction_lot') {96      expect(rec.status).toBe('ended');97      expect(rec.currentBid).toBeNull();98      expect(rec.estimateLow).toBe(450);99      expect(rec.attributes.categorySlug).toBe('coins');100      expect(rec.attributes.year).toBe(1955);101    }102    const weapon = trimItem({ ...API_ITEM, id: 2, category_id: 61, title: 'GEVÄR, Husqvarna.' });103    expect(normalizeItem(meta, weapon, new Date())).toBeNull();104    const unknownCurrency = trimItem({ ...API_ITEM, id: 3, currency: 'XXX' });105    expect(normalizeItem(meta, unknownCurrency, new Date())).toBeNull();106  });107108  it('parses a page and pagination metadata', () => {109    const p = parseItemsPage({ items: [API_ITEM], pagination: { current_page: 1, total_pages: 50, total_entries: 3917226 } }, 'https://auctionet.com/api/v2/items.json?is=ended', 1, { categoryId: null, countryCode: null });110    expect(p?.items).toHaveLength(1);111    expect(p?.totalEntries).toBe(3917226);112    expect(parseItemsPage({ error: 'x' }, 'u', 1, { categoryId: null, countryCode: null })).toBeNull();113  });114115  it('maps Auctionet categories + multilingual titles to taxonomy slugs', () => {116    expect(categoryFor(15, 'ARMBANDSUR, Rolex, Datejust, ref 16233, stål och guld.').slug).toBe('rolex');117    expect(categoryFor(15, 'ARMBANDSUR, Omega, Seamaster, stål, dam, manuell.').slug).toBe('omega');118    expect(categoryFor(110, 'FICKUR, silver, 1800-talets slut.').slug).toBe('other_watches');119    expect(categoryFor(128, 'ÄLDRE SVENSKA SEDLAR, 49 st, 1960-80-tal.').slug).toBe('banknotes');120    expect(categoryFor(128, 'MYNT, 1 riksdaler 1776.').slug).toBe('coins');121    expect(categoryFor(135, 'ORDEN, Vasaorden, riddartecken, guld.').slug).toBe('medals');122    expect(categoryFor(136, 'FRIMÄRKEN, samling i album.').slug).toBe('stamps');123    expect(categoryFor(19, 'SOFFBORD, Bruno Mathsson, Karl Mathsson, 1960-tal.').slug).toBe('antiques');124    expect(categoryFor(18, 'HANS J. WEGNER, armchair "The Chair", Johannes Hansen, Denmark.').slug).toBe('design_furniture');125    expect(categoryFor(28, 'OLJEMÅLNING, signerad, landskap.').slug).toBe('art');126    expect(categoryFor(26, 'FOTOGRAFI, gelatin silver print.').slug).toBe('photography');127    expect(categoryFor(170, 'MACALLAN 18 Years Old Sherry Oak, 70 cl.').slug).toBe('whisky');128    expect(categoryFor(170, 'CHÂTEAU MARGAUX 1990, 1 flaska.').slug).toBe('wine');129    expect(categoryFor(49, 'HERMÈS, handväska "Birkin 35", Togo.').slug).toBe('luxury_handbags');130    expect(categoryFor(268, 'POKÉMON, Charizard, Base Set, holo.').slug).toBe('pokemon');131    expect(categoryFor(211, 'SERIETIDNINGAR, Kalle Anka & Co, 1950-tal, 12 st.').slug).toBe('independent_comics');132    expect(categoryFor(275, 'MODELLBILAR, Dinky Toys, 5 st.').slug).toBe('model_cars');133    expect(categoryFor(215, 'VOLVO P1800 S, 1966.').slug).toBe('automobiles');134    expect(categoryFor(61, 'GEVÄR').slug).toBeNull();135    expect(categoryFor(253, 'MOTOR').slug).toBeNull();136    expect(categoryFor(999, 'Random unknown thing').slug).toBeNull();137    expect(categoryFor(999, 'LEICA M3 camera body').slug).toBe('cameras');138    expect(leafCategoryIds()).not.toContain(16); // parent "Furniture"139    expect(leafCategoryIds()).toContain(19);140    expect(leafCategoryIds()).toContain(42); // Mirrors (childless root)141    expect(leafCategoryIds()).not.toContain(61); // licence weapons142  });143144  it('shared multilingual helpers', () => {145    expect(parseEuDate('12 juin 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');146    expect(parseEuDate('jeudi 09 juillet 2026 14:00')?.toISOString()).toBe('2026-07-09T00:00:00.000Z');147    expect(parseEuDate('12. Juni 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');148    expect(parseEuDate('1. März 2025')?.toISOString()).toBe('2025-03-01T00:00:00.000Z');149    expect(parseEuDate('12 giugno 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');150    expect(parseEuDate('12 de junio de 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');151    expect(parseEuDate('den 12 juni 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');152    expect(parseEuDate('22–23 juin 2026')?.toISOString()).toBe('2026-06-22T00:00:00.000Z');153    expect(parseEuDate('June 12, 2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');154    expect(parseEuDate('12.06.2026')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');155    expect(parseEuDate('2026-06-12T14:00:00Z')?.toISOString()).toBe('2026-06-12T00:00:00.000Z');156    expect(parseEuDate('12 joulukuuta 2025')?.toISOString()).toBe('2025-12-12T00:00:00.000Z');157    expect(parseEuDate('nonsense')).toBeNull();158159    expect(parseEuMoney('1.250,00 €', 'EUR')).toMatchObject({ amount: 1250, currency: 'EUR' });160    expect(parseEuMoney('1 250 €', 'EUR')).toMatchObject({ amount: 1250, currency: 'EUR' });161    expect(parseEuMoney('1 081 EUR', 'EUR')).toMatchObject({ amount: 1081, currency: 'EUR' });162    expect(parseEuMoney('593EUR', 'EUR')).toMatchObject({ amount: 593, currency: 'EUR' });163    expect(parseEuMoney('€ 12.500', 'EUR')).toMatchObject({ amount: 12500, currency: 'EUR' });164    expect(parseEuMoney("CHF 1'250", 'CHF', 'ch')).toMatchObject({ amount: 1250, currency: 'CHF' });165    expect(parseEuMoney('12 000 SEK', 'SEK')).toMatchObject({ amount: 12000, currency: 'SEK' });166    expect(parseEuMoney('4 000 kr', 'SEK')).toMatchObject({ amount: 4000, currency: 'SEK' });167    expect(parseEuMoney('£1,250', 'GBP', 'en')).toMatchObject({ amount: 1250, currency: 'GBP' });168    expect(parseEuMoney('HK$1,250,000', 'HKD', 'en')).toMatchObject({ amount: 1_250_000, currency: 'HKD' });169    expect(parseEuMoney('¥1,250,000', 'JPY', 'en')).toMatchObject({ amount: 1_250_000, currency: 'JPY' });170    expect(parseEuMoney('AU$2,400', 'AUD', 'en')).toMatchObject({ amount: 2400, currency: 'AUD' });171    expect(parseEuMoney('1.250', 'EUR')).toMatchObject({ amount: 1250 });172    expect(parseEuMoney('1.25', 'EUR')).toMatchObject({ amount: 1.25 });173    expect(parseEuMoney('n/a', 'EUR')).toBeNull();174    expect(parseEuMoney('1 250', null)).toBeNull();175176    expect(isBundleMultilingual('Armbanduhren Konvolut (4)')).toBe(true);177    expect(isBundleMultilingual('SEDLAR, 49 st')).toBe(true);178    expect(isBundleMultilingual('Lot de trois montres')).toBe(true);179    expect(isBundleMultilingual('Lotto di sei tazze')).toBe(true);180    expect(isBundleMultilingual('SÄNGBORD, ett par')).toBe(false);181    expect(isBundleMultilingual('ARMBANDSUR, Rolex, Datejust')).toBe(false);182    expect(parenCount('LJUSSTAKAR, ett par, silver. (2).')).toBe(2);183    expect(parenCount('12 st glas')).toBe(12);184185    expect(yearFromTitle('SÄNGBORD, ett par, 1900/2000-tal')).toBeNull();186    expect(yearFromTitle('SOFFBORD, 1960-tal')).toBeNull();187    expect(yearFromTitle('Cortébert, 1950er Jahre')).toBeNull();188    expect(yearFromTitle('Rolex Datejust, 1980s')).toBeNull();189    expect(yearFromTitle('VOLVO P1800 S, 1966.')).toBe(1966);190    expect(yearFromTitle('MYNT, 1 riksdaler 1776.')).toBe(1776);191    expect(yearFromTitle('CHÂTEAU MARGAUX 1990')).toBe(1990);192  });193});194