TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { readFileSync } from 'node:fs';2import path from 'node:path';3import { describe, expect, it } from 'vitest';4import { getConnectorMeta } from '@rareindex/connectors';5import { fixtureDir, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';6import createConnector, { ListResponseSchema, listUrl, toAuctions } from './index.js';7import { alnumReferenceFromText, watchFromTitle } from '../_g9-asia-watch-sneaker-lib/index.js';89const connector = createConnector(getConnectorMeta('loupe-this'));10const sample = ListResponseSchema.parse(JSON.parse(readFileSync(path.join(fixtureDir('loupe-this'), 'samples', 'api-closed.json'), 'utf8')));1112describe('loupe-this', () => {13 runFixtureSuite(connector, it, expect);1415 it('maps JSON:API resources and resolves brand names from `included`', () => {16 const auctions = toAuctions(sample.data, sample.included);17 expect(auctions).toHaveLength(3);18 const a = auctions[0]!;19 expect(a.title).toBe('MING 37.02 Minimalist');20 expect(a.brand).toBe('Ming');21 expect(a.isClosed).toBe(true);22 expect(a.soldPriceCents).toBe(352000);23 expect(a.currentBidCents).toBe(320000);24 expect(a.buyersPremiumPercent).toBe(10);25 expect(a.endsAt).toBe('2026-08-10T16:25:00.000Z');26 expect(sample.meta?.pagination?.total_pages).toBeGreaterThan(40);27 expect(listUrl('closed', 3)).toBe('https://api.loupethis.com/api/v1/auctions?status=closed&per_page=100&page=3&include=brand');28 });2930 it('closed lots with a sold price become sales (buyer premium included, hammer in metadata)', async () => {31 const auctions = toAuctions(sample.data, sample.included);32 const out = await connector.normalize({ url: 'https://api.loupethis.com/api/v1/auctions?status=closed', externalId: null, kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload: { kind: 'auction_page', status: 'closed', page: 2, totalPages: 43, totalCount: 4251, auctions } });33 const s = out[0];34 if (s?.kind !== 'sale') throw new Error('expected sale');35 expect(s.price).toBe(3520);36 expect(s.currency).toBe('USD');37 expect(s.buyerPremiumIncluded).toBe(true);38 expect(s.attributes.metadata.hammer_price).toBe(3200);39 expect(s.saleDate.toISOString()).toBe('2026-08-10T16:25:00.000Z');40 expect(s.saleType).toBe('auction');41 expect(s.auctionHouse).toBe('Loupe This');42 expect(s.attributes.brand).toBe('Ming');43 expect(s.attributes.categorySlug).toBe('other_watches');44 expect(s.sourceUrl).toBe('https://loupethis.com/auctions/ming-37-02-minimalist');45 expect(s.attributes.identifiers.loupe_this_id).toBe(auctions[0]!.id);46 });4748 it('closed lots without a sold price are skipped; open lots become auction_lot records', async () => {49 const auctions = toAuctions(sample.data, sample.included);50 const unsold = { ...auctions[0]!, soldPriceCents: null };51 const live = { ...auctions[1]!, isClosed: false, soldPriceCents: null, startsAt: '2026-09-01T16:00:00.000Z', endsAt: '2026-09-30T16:00:00.000Z', currentBidCents: 45000 };52 const upcoming = { ...auctions[2]!, isClosed: false, soldPriceCents: null, startsAt: '2026-10-01T16:00:00.000Z', endsAt: '2026-10-08T16:00:00.000Z', currentBidCents: 0 };53 const out = await connector.normalize({ url: 'x', externalId: null, kind: 'auction_lot', engine: 'api', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload: { kind: 'auction_page', status: 'live', page: 1, totalPages: 1, totalCount: 3, auctions: [unsold, live, upcoming] } });54 expect(out).toHaveLength(2);55 const [l, u] = out;56 if (l?.kind !== 'auction_lot' || u?.kind !== 'auction_lot') throw new Error('expected auction lots');57 expect(l.status).toBe('live');58 expect(l.currentBid).toBe(450);59 expect(l.currency).toBe('USD');60 expect(u.status).toBe('upcoming');61 expect(u.currentBid).toBeNull();62 });6364 it('live fixture yields auction lots with watch references (incl. Seiko-style codes)', async () => {65 const fx = loadFixture('loupe-this', 'live-p1');66 const out = await connector.normalize(fx.raw);67 expect(out.length).toBeGreaterThan(3);68 expect(out.every((r) => r.kind === 'auction_lot')).toBe(true);69 const gs = out.find((r) => r.kind === 'auction_lot' && /SBGA211/.test(r.rawTitle));70 expect(gs && gs.kind === 'auction_lot' ? gs.attributes.reference : null).toBe('SBGA211');71 });7273 it('watch title parsing', () => {74 expect(watchFromTitle('Patek Philippe Hour Glass 2456J 18K YG With Extract From The Archives')).toMatchObject({ brand: 'Patek Philippe', categorySlug: 'patek_philippe', reference: '2456J', material: 'gold' });75 expect(watchFromTitle('Rolex Submariner Date 126610LN Unworn 2023 41mm').reference).toBe('126610LN');76 expect(alnumReferenceFromText('IWC Pilot IW371446 18K')).toBe('IW371446');77 expect(alnumReferenceFromText('Steel GMT 40mm')).toBeNull();78 });79});80