import { describe, expect, it } from 'vitest';
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing';
import { localMeta } from '../_lib/local-meta.js';
import createConnector, { millerCategory, parseAmCatalog } from './index.js';
const dir = path.dirname(fileURLToPath(import.meta.url));
const meta = localMeta(JSON.parse(readFileSync(path.join(dir, 'meta.json'), 'utf8')));
const connector = createConnector(meta);
// Real slices of the server-rendered JSON of https://live.millerandmillerauctions.com/auctions/4-10LJNY (captured 2026-09-08).
const AUCTION = `{"row_id":"4-10LJNY","type":"auction","self_url":"https:\\/\\/production4-server.auctionmobility.com\\/v1\\/auction\\/4-10LJNY\\/","auction_type":"timed_then_live","title":"Watches, Jewellery & Decorative Arts","time_start":"2020-11-02T09:00:00Z","effective_end_time":"2020-11-21T22:00:00Z","extended_end_time":null,"lot_count":298,"sold_lot_count":0,"default_buyers_premium":null,"currency_code":"CAD","publication_status":"full","_detail_url":"\\/auctions\\/4-10LJNY\\/watches-jewellery-decorative-arts","_slug":"watches-jewellery-decorative-arts"}`;
const LOT_SOLD = `{"row_id":"4-178VA3","type":"auction-lot-summary","self_url":"https:\\/\\/production4-server.auctionmobility.com\\/v1\\/auction-lot\\/4-178VA3\\/summary","lot_number":1,"status":"sold","title":"Movado 14K Gold Diamond Cocktail Wristwatch","last_updated":"2020-11-21T14:01:23Z","lot_number_extension":"","starting_price":"25.00","hide_estimate":false,"estimate_low":"200.00","estimate_high":"300.00","truncated_description":"Swiss. Gross weight 14g. CODE-WAT","buyers_premium_amount":"0.00","cover_thumbnail":"https:\\/\\/images4-cdn.auctionmobility.com\\/is3\\/x.jpg","currency_code":"CAD","timed_auction_bid":{"row_id":"f6fbd6ba","absentee_bid_id":"4-1BD47B","amount":"175.00","amount_percentage":null,"created_at":"2020-11-21T13:59:00.000Z","updated_at":"2020-11-21T14:01:23.402Z","registration":{"paddle":"1","row_id":"4-x","customer":{"paddle":null,"row_id":"4-y"}}},"_detail_url":"\\/lots\\/view\\/4-178VA3\\/movado-14k-gold-diamond-cocktail-wristwatch"}`;
const LOT_PASSED = `{"row_id":"4-178VZZ","type":"auction-lot-summary","lot_number":9,"status":"expired","title":"Group of Assorted Costume Jewellery (12 pieces)","estimate_low":"100.00","estimate_high":"150.00","currency_code":"CAD","timed_auction_bid":null,"_detail_url":"\\/lots\\/view\\/4-178VZZ\\/costume"}`;
const HTML = `
Past Lots`;
describe('miller-miller', () => {
runFixtureSuite(connector, it, expect);
it('parses the embedded Auction Mobility JSON (auction header + lot summaries)', () => {
const p = parseAmCatalog(HTML, '4-10LJNY', 1)!;
expect(p.auction).toMatchObject({ id: '4-10LJNY', title: 'Watches, Jewellery & Decorative Arts', currency: 'CAD', endTime: '2020-11-21T22:00:00Z', lotCount: 298, url: 'https://live.millerandmillerauctions.com/auctions/4-10LJNY/watches-jewellery-decorative-arts' });
expect(p.lots).toHaveLength(2);
expect(p.lots[0]).toMatchObject({ id: '4-178VA3', lotNumber: '1', status: 'sold', hammer: 175, estimateLow: 200, estimateHigh: 300, currency: 'CAD', bidAt: '2020-11-21T14:01:23.402Z', url: 'https://live.millerandmillerauctions.com/lots/view/4-178VA3/movado-14k-gold-diamond-cocktail-wristwatch' });
expect(p.lots[1]).toMatchObject({ status: 'expired', hammer: null });
});
it('normalises sold lots to CAD hammer-price sales dated by the auction end; passed lots of closed auctions yield nothing', async () => {
const p = parseAmCatalog(HTML, '4-10LJNY', 1)!;
const out = await connector.normalize({ url: 'x', externalId: 'e', kind: 'sale', engine: 'api', fetchedAt: new Date('2026-09-08T00:00:00Z'), payload: p });
expect(out).toHaveLength(1);
const s = out[0]!;
if (s.kind !== 'sale') throw new Error('expected sale');
expect(s).toMatchObject({ price: 175, currency: 'CAD', buyerPremiumIncluded: false, auctionHouse: 'Miller & Miller Auctions', lotNumber: '1', location: 'CA', isBundle: false });
expect(s.saleDate.toISOString()).toBe('2020-11-21T22:00:00.000Z');
expect(s.attributes.categorySlug).toBe('other_watches');
expect(s.attributes.identifiers).toEqual({ miller_lot_id: '4-178VA3' });
expect(s.attributes.metadata).toMatchObject({ hammer_price: 175, estimate_low: 200 });
});
it('yields auction lots (not sales) for upcoming catalogs and reads PSA grades from titles', async () => {
const fx = loadFixture('miller-miller', 'sports-upcoming-1');
const out = await connector.normalize(fx.raw);
expect(out.length).toBeGreaterThan(0);
expect(out.every((r) => r.kind === 'auction_lot')).toBe(true);
const lot = out.find((r) => r.kind === 'auction_lot' && /PSA 6/.test(r.rawTitle));
expect(lot).toBeTruthy();
if (lot?.kind === 'auction_lot') {
expect(lot.grade).toMatchObject({ grader: 'psa', grade: '6' });
expect(lot.attributes.categorySlug).toBe('baseball_cards');
expect(lot.currency).toBe('CAD');
expect(['upcoming', 'live']).toContain(lot.status); // the catalog was already open for bidding when captured
}
});
it('maps Miller & Miller sale departments to taxonomy slugs', () => {
expect(millerCategory('Pre-1980 Sports Cards & Memorabilia', '1979 O-Pee-Chee #18 Wayne Gretzky Rookie PSA 7')).toBe('hockey_cards');
expect(millerCategory('Petroliana & Advertising', 'Red Indian Motor Oil Porcelain Sign')).toBe('advertising');
expect(millerCategory('Watches, Jewellery & Decorative Arts', 'Omega, Ladies 18K Diamond Cocktail Watch')).toBe('omega');
expect(millerCategory('Watches, Jewellery & Decorative Arts', '18K Gold & Sapphire Ring')).toBe('jewelry');
expect(millerCategory('Coins & Banknotes', '1937 Bank of Canada $2 Note')).toBe('banknotes');
expect(millerCategory('Post-War Canadian Folk Art', 'Maud Lewis (Canadian 1901-1970) Oil on Board')).toBe('art');
expect(millerCategory('Canadiana & Decoys', 'Pair of Redhead Decoys, Ontario c. 1920')).toBe('antiques');
expect(millerCategory('Firearms', 'Rifle')).toBeNull();
});
it('fixture sales are CAD and predate the capture', async () => {
const fx = loadFixture('miller-miller', 'watches-sold-1');
const out = await connector.normalize(fx.raw);
expect(out.length).toBeGreaterThanOrEqual(10); // fixture trimmed to 10 lots
for (const r of out) {
expect(r.kind).toBe('sale');
if (r.kind === 'sale') {
expect(r.currency).toBe('CAD');
expect(r.buyerPremiumIncluded).toBe(false);
expect(r.saleDate.getTime()).toBeLessThan(fx.raw.fetchedAt.getTime());
}
}
});
});