// Generated, do not edit. sha256:60e26a3323cff9f6656d123b1222be3bdc643c67ea3cef033160914cd9a62cad import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { dailyProvenance, provenanceCounts, provenanceRuns, provenanceOn, provenanceOfRow, originFrom, liveOrigin, PROVENANCE_KINDS, } from '../../shared/price-provenance.js'; const MANUAL = 99; let seq = 0; const dag = (d, fiatPrice, extra = {}) => ({ id: ++seq, observedAt: `${d}T00:00:00Z`, resolution: 'day', fiatPrice, providerId: 1, createdAt: `${d}T00:00:00Z`.replace(d, volgendeDag(d)), updatedAt: null, ...extra, }); const spot = (d, tijd, fiatPrice, extra = {}) => ({ id: ++seq, observedAt: `${d}T${tijd}:00.000Z`, resolution: 'timestamp', fiatPrice, providerId: 1, createdAt: `${d}T${tijd}:00.000Z`, updatedAt: null, ...extra, }); function volgendeDag(d) { return new Date(Date.parse(`${d}T00:00:00Z`) + 86400000).toISOString().slice(0, 10); } const opts = extra => ({ manualProviderId: MANUAL, today: '2026-09-25', ...extra }); const op = (uit, d) => uit.find(x => x.day === d); describe('dailyProvenance: de soort per dag', () => { it('een dagrij van een bron is een slotkoers, een rij op manual is met de hand', () => { const uit = dailyProvenance([dag('2026-09-01', 100), dag('2026-09-02', 101, { providerId: MANUAL })], opts({ until: '2026-09-02' })); assert.deepEqual(uit.map(d => d.kind), ['close', 'manual']); }); it('een spot van een voorbije dag is afgeleid, met de afwijking naar de slotkoersen eromheen', () => { const uit = dailyProvenance([dag('2026-09-01', 100), spot('2026-09-02', '09:00', 110), dag('2026-09-03', 120)], opts({ until: '2026-09-03' })); const d = op(uit, '2026-09-02'); assert.equal(d.kind, 'spot'); assert.equal(d.fiatPrice, 110); assert.deepEqual(d.deviation, { before: 10, after: -8.33 }); }); it('een afwijking zonder slotkoers aan een kant is null aan die kant, en een spot meet niet tegen een spot', () => { const uit = dailyProvenance([spot('2026-09-01', '09:00', 100), spot('2026-09-02', '09:00', 110), dag('2026-09-03', 100)], opts({ until: '2026-09-03' })); assert.deepEqual(op(uit, '2026-09-02').deviation, { before: null, after: 10 }); }); it('vandaag is live, ook als er een dagrij staat', () => { const uit = dailyProvenance([dag('2026-09-24', 100), dag('2026-09-25', 101)], opts()); assert.equal(op(uit, '2026-09-25').kind, 'live'); }); it('een dagrij die op zijn eigen dag geschreven is, is een voorlopige koers en dus afgeleid', () => { const voorlopig = dag('2026-09-02', 105, { createdAt: '2026-09-02T14:00:00.000Z' }); const uit = dailyProvenance([dag('2026-09-01', 100), voorlopig], opts({ until: '2026-09-02' })); assert.equal(op(uit, '2026-09-02').kind, 'spot'); }); it('een dagrij van vóór migratie 86 (geen tijdstempels) telt als slotkoers', () => { const oud = dag('2026-09-01', 100, { createdAt: null, updatedAt: null }); assert.equal(dailyProvenance([oud], opts({ until: '2026-09-01' }))[0].kind, 'close'); }); }); describe('dailyProvenance: dezelfde keuzes als de leeskant', () => { it('een dagrij wint van een spot op dezelfde dag, in welke volgorde ze ook binnenkomen', () => { const rijen = [spot('2026-09-01', '15:00', 200), dag('2026-09-01', 100)]; for (const volgorde of [rijen, [...rijen].reverse()]) { const d = dailyProvenance(volgorde, opts({ until: '2026-09-01' }))[0]; assert.equal(d.kind, 'close'); assert.equal(d.fiatPrice, 100); } }); it('van twee dagrijen wint de nieuwste (hoogste id), zoals getPricePoint', () => { const oud = dag('2026-09-01', 100); const nieuw = dag('2026-09-01', 102); assert.equal(dailyProvenance([nieuw, oud], opts({ until: '2026-09-01' }))[0].fiatPrice, 102); assert.equal(dailyProvenance([oud, nieuw], opts({ until: '2026-09-01' }))[0].fiatPrice, 102); }); it('van twee spots op één dag wint de laatste', () => { const d = dailyProvenance([spot('2026-09-01', '18:00', 120), spot('2026-09-01', '09:00', 100)], opts({ until: '2026-09-01' }))[0]; assert.equal(d.fiatPrice, 120); }); it('een koers van nul of lager telt niet, zoals in toDailyGrid', () => { const uit = dailyProvenance([dag('2026-09-01', 100), dag('2026-09-02', 0), dag('2026-09-03', -5)], opts({ until: '2026-09-03' })); assert.deepEqual(uit.map(d => d.kind), ['close', 'carried', 'carried']); assert.equal(op(uit, '2026-09-03').fiatPrice, 100); }); }); describe('dailyProvenance: vandaag volgt de laatst geziene koers', () => { const VANDAAG = '2026-09-25'; const voorlopig = (fiatPrice, tijd) => dag(VANDAAG, fiatPrice, { createdAt: `${VANDAAG}T06:00:00.000Z`, updatedAt: `${VANDAAG}T${tijd}:00.000Z` }); it('een spot van later vandaag wint van een eerder geschreven dagrij, in welke volgorde ook', () => { const rijen = [voorlopig(100, '08:00'), spot(VANDAAG, '14:00', 110, { providerId: 2 })]; for (const volgorde of [rijen, [...rijen].reverse()]) { const d = op(dailyProvenance(volgorde, opts()), VANDAAG); assert.equal(d.fiatPrice, 110); assert.equal(d.kind, 'live'); } }); it('een dagrij die later vandaag is bijgewerkt, wint van een eerdere spot', () => { const rijen = [spot(VANDAAG, '07:00', 110, { providerId: 2 }), voorlopig(100, '09:00')]; for (const volgorde of [rijen, [...rijen].reverse()]) { assert.equal(op(dailyProvenance(volgorde, opts()), VANDAAG).fiatPrice, 100); } }); it('een voorbije dag houdt de regel van de leeskant: de dagrij wint, ook van een latere spot', () => { const gisteren = '2026-09-24'; const rijen = [dag(gisteren, 100, { createdAt: `${gisteren}T08:00:00.000Z` }), spot(gisteren, '14:00', 120, { providerId: 2 })]; for (const volgorde of [rijen, [...rijen].reverse()]) { assert.equal(op(dailyProvenance(volgorde, opts()), gisteren).fiatPrice, 100); } }); }); describe('dailyProvenance: doortrekken en de grens', () => { it('crypto trekt zeven dagen door en heeft daarna geen koers', () => { const uit = dailyProvenance([dag('2026-09-01', 100)], opts({ until: '2026-09-09' })); assert.equal(op(uit, '2026-09-08').kind, 'carried'); assert.equal(op(uit, '2026-09-08').ageDays, 7); assert.equal(op(uit, '2026-09-09').kind, 'none'); assert.equal(op(uit, '2026-09-09').fiatPrice, null); }); it('metaal trekt veertien dagen door, fiat zonder grens', () => { const metaal = dailyProvenance([dag('2026-08-01', 50)], opts({ assetKind: 'metal', until: '2026-08-16' })); assert.equal(op(metaal, '2026-08-15').kind, 'carried'); assert.equal(op(metaal, '2026-08-16').kind, 'none'); const fiat = dailyProvenance([dag('2025-01-01', 0.9)], opts({ assetKind: 'fiat', until: '2026-09-01' })); assert.equal(fiat.at(-1).kind, 'carried'); }); it('een bereik dat vóór de eerste koers begint, heeft daar geen koers', () => { const uit = dailyProvenance([dag('2026-09-03', 100)], opts({ from: '2026-09-01', until: '2026-09-03' })); assert.deepEqual(uit.map(d => d.kind), ['none', 'none', 'close']); }); it('een bereik dat ná de eerste koers begint, trekt de koers van daarvoor door', () => { const uit = dailyProvenance([dag('2026-09-01', 100)], opts({ from: '2026-09-03', until: '2026-09-03' })); assert.equal(uit[0].kind, 'carried'); assert.equal(uit[0].ageDays, 2); }); it('lege invoer geeft een lege lijst en geen fout', () => { assert.deepEqual(dailyProvenance([], opts()), []); assert.deepEqual(dailyProvenance(null, opts()), []); }); }); describe('provenanceOn: de herkomst van één dag, voor één bedrag', () => { it('geeft hetzelfde als het dagoverzicht voor die dag', () => { const rijen = [dag('2026-09-01', 100), dag('2026-09-03', 102)]; assert.deepEqual(provenanceOn(rijen, '2026-09-02', opts()), dailyProvenance(rijen, opts({ until: '2026-09-03' })).find(d => d.day === '2026-09-02')); }); it('meet de afwijking van een afgeleide koers tegen slotkoersen BUITEN die ene dag', () => { const rijen = [dag('2026-09-01', 100), spot('2026-09-02', '09:00', 110), dag('2026-09-03', 100)]; assert.deepEqual(provenanceOn(rijen, '2026-09-02', opts()).deviation, { before: 10, after: 10 }); }); it('beschrijft de rij met de gebruikte koers als twee bronnen dezelfde dag hebben', () => { const eerste = dag('2026-09-01', 100, { providerId: 1 }); const tweede = dag('2026-09-01', 105, { providerId: 2 }); const d = provenanceOn([eerste, tweede], '2026-09-01', opts({ usedPrice: 100 })); assert.equal(d.fiatPrice, 100); assert.equal(d.row.providerId, 1); assert.equal(d.kind, 'close'); }); it('doet dat ook bij een doorgetrokken koers, op de dag waar hij vandaan komt', () => { const rijen = [dag('2026-09-01', 100, { providerId: 1 }), dag('2026-09-01', 105, { providerId: 2 })]; const d = provenanceOn(rijen, '2026-09-03', opts({ usedPrice: 100 })); assert.equal(d.kind, 'carried'); assert.equal(d.ageDays, 2); assert.equal(d.row.providerId, 1); }); it('noemt een gebruikte koers voorbij de ouderdomsgrens doorgetrokken, met zijn echte leeftijd', () => { const d = provenanceOn([dag('2026-08-01', 100)], '2026-09-01', opts({ usedPrice: 100 })); assert.equal(d.kind, 'carried'); assert.equal(d.ageDays, 31); assert.equal(provenanceOn([dag('2026-08-01', 100)], '2026-09-01', opts()).kind, 'none', 'zonder gebruikte koers blijft het geen koers'); }); it('houdt zijn eigen keuze als geen rij de gebruikte koers heeft, en geeft null zonder koers', () => { const rijen = [dag('2026-09-01', 100)]; assert.equal(provenanceOn(rijen, '2026-09-01', opts({ usedPrice: 999 })).fiatPrice, 100); assert.equal(provenanceOn([], '2026-09-01', opts()), null); }); }); describe('provenanceOfRow: de laatste opgeslagen koers als koers van vandaag', () => { it('een rij van een eerdere dag is doorgetrokken, met zijn leeftijd, ook voorbij de grens', () => { const d = provenanceOfRow(dag('2026-08-01', 100), opts()); assert.equal(d.kind, 'carried'); assert.equal(d.ageDays, 55); assert.equal(d.day, '2026-09-25'); }); it('een rij van vandaag is live, een met de hand blijft met de hand', () => { assert.equal(provenanceOfRow(spot('2026-09-25', '09:00', 100), opts()).kind, 'live'); assert.equal(provenanceOfRow(dag('2026-09-25', 100, { providerId: MANUAL }), opts()).kind, 'manual'); }); it('beschrijft een rij als koers van een dag in het verleden, voor een verplaatsing op die dag', () => { assert.equal(provenanceOfRow(dag('2026-03-03', 100), opts({ day: '2026-03-03' })).kind, 'close'); const afgeleid = provenanceOfRow({ ...spot('2026-03-03', '09:00', 100), derivedFrom: 'spot' }, opts({ day: '2026-03-03' })); assert.equal(afgeleid.kind, 'spot', 'de laatste spot van die dag is afgeleid en niet live'); assert.equal(provenanceOfRow(dag('2026-03-01', 100), opts({ day: '2026-03-03' })).ageDays, 2); }); it('geeft null zonder rij of zonder koers', () => { assert.equal(provenanceOfRow(null, opts()), null); assert.equal(provenanceOfRow(dag('2026-09-25', 0), opts()), null); }); }); describe('originFrom en liveOrigin: de platte vorm voor de hover', () => { it('noemt de bron bij naam, de brondag en bij een afgeleide koers het moment', () => { const rij = spot('2026-09-02', '09:12', 110, { providerId: 7 }); const d = provenanceOn([dag('2026-09-01', 100), rij], '2026-09-02', opts()); const o = originFrom(d, new Map([[7, 'Bitvavo']])); assert.equal(o.kind, 'spot'); assert.equal(o.source, 'Bitvavo'); assert.equal(o.sourceDay, '2026-09-02'); assert.equal(o.moment, rij.observedAt); }); it('geeft bij een slotkoers geen moment, want die is van de hele dag', () => { const o = originFrom(provenanceOn([dag('2026-09-01', 100)], '2026-09-01', opts()), new Map()); assert.equal(o.moment, null); assert.equal(o.source, null, 'een onbekende bron is null en geen verzonnen naam'); }); it('geeft null zonder koers, en een live spot zegt alleen dat hij live is', () => { assert.equal(originFrom(null), null); assert.equal(originFrom({ day: '2026-09-01', fiatPrice:null, kind: 'none', row: null }), null); assert.deepEqual(liveOrigin(100, null, new Date('2026-09-25T10:00:00Z')), { day: '2026-09-25', kind: 'live', fiatPrice:100, ageDays: 0, deviation: null, source: null, sourceDay: null, moment: '2026-09-25T10:00:00.000Z' }); assert.equal(liveOrigin(null), null); }); }); describe('provenanceRuns', () => { it('voegt opeenvolgende dagen van dezelfde soort samen en breekt bij elke wissel', () => { const uit = dailyProvenance([dag('2026-09-01', 100), dag('2026-09-02', 100), spot('2026-09-03', '09:00', 101)], opts({ until: '2026-09-05' })); assert.deepEqual(provenanceRuns(uit), [ { kind: 'close', from: '2026-09-01', until: '2026-09-02', days: 2 }, { kind: 'spot', from: '2026-09-03', until: '2026-09-03', days: 1 }, { kind: 'carried', from: '2026-09-04', until: '2026-09-05', days: 2 }, ]); }); it('geeft een lege lijst bij lege invoer', () => { assert.deepEqual(provenanceRuns([]), []); }); }); describe('provenanceCounts', () => { it('telt per soort en noemt elke soort, ook met nul', () => { const uit = dailyProvenance([dag('2026-09-01', 100), spot('2026-09-02', '09:00', 101)], opts({ until: '2026-09-03' })); const n = provenanceCounts(uit); assert.deepEqual(Object.keys(n), [...PROVENANCE_KINDS]); assert.equal(n.close, 1); assert.equal(n.spot, 1); assert.equal(n.carried, 1); assert.equal(n.none, 0); }); });