TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { describe, expect, it } from 'vitest';2import { assessLot } from './auction.js';3import { feeBasisLabel } from './fees.js';45const riv = { rivUsd: 10_000, confidence: 0.8, sampleSize: 30, basis: 'transactions' as const };67describe('assessLot (§33–§35)', () => {8 it('uses the low estimate when there is no bid, on an all-in basis', () => {9 const a = assessLot({ house: "Sotheby's", currentBidUsd: null, bidCount: 0, estimateLowUsd: 6_000, estimateHighUsd: 9_000, riv });10 expect(a.basedOn).toBe('estimate');11 expect(a.allInBidUsd).toBeNull();12 expect(a.allInEstimateLowUsd).toBe(7_620); // 6,000 × 1.2713 expect(a.allInEstimateHighUsd).toBe(11_430);14 expect(a.estimateVsRiv).toBeCloseTo(-0.238, 3);15 expect(a.verdict).toBe('deal');16 expect(a.feeBasis).toBe('added_published');17 expect(a.buyerPremiumRate).toBe(0.27);18 });19 it('uses the all-in current bid when bids exist', () => {20 const a = assessLot({ house: 'Goldin', currentBidUsd: 7_000, bidCount: 3, estimateLowUsd: 5_000, estimateHighUsd: 8_000, riv });21 expect(a.basedOn).toBe('bid');22 expect(a.allInBidUsd).toBe(8_400); // 20 % premium23 expect(a.bidVsRiv).toBeCloseTo(-0.16, 3);24 expect(a.verdict).toBe('deal');25 });26 it('an opening bid with no bidders is ignored (it is not a price)', () => {27 const a = assessLot({ house: 'Goldin', currentBidUsd: 1, bidCount: 0, estimateLowUsd: null, estimateHighUsd: null, riv });28 expect(a.basedOn).toBe('none');29 expect(a.verdict).toBe('ungated');30 expect(a.bidVsRiv).toBeNull();31 });32 it('unknown house → default premium, labelled as such', () => {33 const a = assessLot({ house: 'Enchères du Coin', currentBidUsd: 8_000, bidCount: 2, estimateLowUsd: null, estimateHighUsd: null, riv });34 expect(a.feeBasis).toBe('added_default');35 expect(a.allInBidUsd).toBe(9_760); // 22 %36 expect(feeBasisLabel(a.feeBasis)).toContain('default');37 });38 it('variant mismatch → ungated, no discount written', () => {39 const a = assessLot({ house: 'Goldin', currentBidUsd: 5_000, bidCount: 4, estimateLowUsd: null, estimateHighUsd: null, riv, sameVariant: false });40 expect(a.verdict).toBe('ungated');41 expect(a.reasons).toContain('variant_mismatch');42 expect(a.bidVsRiv).toBeNull();43 expect(a.allInBidUsd).toBe(6_000); // the all-in cost is still informative44 });45 it('review and anomaly verdicts never produce a usable discount', () => {46 expect(assessLot({ house: 'Goldin', currentBidUsd: 2_000, bidCount: 5, estimateLowUsd: null, estimateHighUsd: null, riv }).verdict).toBe('review'); // 2,400 all-in vs 10,00047 const anomaly = assessLot({ house: 'Goldin', currentBidUsd: 200, bidCount: 5, estimateLowUsd: null, estimateHighUsd: null, riv });48 expect(anomaly.verdict).toBe('anomaly');49 expect(anomaly.bidVsRiv).toBeNull();50 });51 it('comps-only or thin valuations never qualify a lot', () => {52 expect(assessLot({ house: 'Goldin', currentBidUsd: 7_000, bidCount: 3, estimateLowUsd: null, estimateHighUsd: null, riv: { ...riv, basis: 'comps' } }).verdict).toBe('ungated');53 expect(assessLot({ house: 'Goldin', currentBidUsd: 7_000, bidCount: 3, estimateLowUsd: null, estimateHighUsd: null, riv: { ...riv, sampleSize: 3 } }).verdict).toBe('ungated');54 expect(assessLot({ house: 'Goldin', currentBidUsd: 7_000, bidCount: 3, estimateLowUsd: null, estimateHighUsd: null, riv: null }).reasons).toContain('no_riv');55 });56 it('fee basis labels are human-readable', () => {57 expect(feeBasisLabel('included')).toBe('premium included');58 expect(feeBasisLabel('none')).toBe('no buyer premium');59 expect(feeBasisLabel('unknown')).toBe('fees unknown');60 expect(feeBasisLabel('added_approximate')).toContain('estimated');61 });62});63