// Generated, do not edit. sha256:d235c44eb19e911ab77974e75ddb595cbc8249ee72a4b4a543123c373e4e6b5f import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { periodChoices, startPeriod, returnLine, idsForSelection, contributorsPerDay, flatLine } from '../../client/wealth/return-view.js'; import { dagreeks, seriesFor, meetVenster } from '../../client/wealth/series.js'; import { windowTwr } from '../../client/wealth/performance.js'; const rond = x => (x == null ? x : Math.round(x * 1e6) / 1e6); const grid = (vanafDag, koersen) => { const start = Date.parse(`${vanafDag}T00:00:00Z`); return koersen.map((k, i) => [start + i * 86400000, k]); }; const ev = o => ({ type: 'buy', amount: 0, fiatPrice: null, fiatFee: null, unitFee: null, fromAccountId: null, toAccountId: 1, ...o }); const A = { id: 1, decimals: 8, kind: 'crypto' }; const B = { id: 3, decimals: 8, kind: 'metal' }; const reeks = () => dagreeks({ assets: [A, B], prijzen: new Map([ [A.id, grid('2026-01-01', [100, 110, 99, 120, 130, 125])], [B.id, grid('2026-01-01', [50, 50, 55, 60, 54, 57])], ]), vanDag: '2026-01-01', totDag: '2026-01-06', events: [ ev({ assetId: A.id, amount: 1e8, fiatPrice: 100, occurredAt: '2026-01-01T10:00:00Z' }), ev({ assetId: B.id, amount: 2e8, fiatPrice: 55, occurredAt: '2026-01-03T10:00:00Z' }), ], valuations: [], }); describe('periodChoices', () => { it('zet de periode van de pagina vooraan, gemeten zoals de jaarkeuze meet', () => { const p = periodChoices(400, { label: '2025', venster: { van: 10, tot: 50 } }); assert.deepEqual(p[0], { key: 'page', days: null, label: '2025', venster: meetVenster({ van: 10, tot: 50 }, 400) }); assert.deepEqual(p.slice(1).map(x => x.key), ['d1', 'd7', 'd30', 'd365', 'start']); }); it('laat de pagina weg als die de hele reeks beslaat: dat is "sinds begin"', () => { assert.deepEqual(periodChoices(400, { label: 'x', venster: { van: 0, tot: 399 } }).map(x => x.key), ['d1', 'd7', 'd30', 'd365', 'start']); }); it('geeft zonder reeks niets', () => { assert.deepEqual(periodChoices(0, { label: '2025', venster: { van: 0, tot: 0 } }), []); }); }); describe('startPeriod', () => { it('opent op de bewaarde periode als die bestaat en te meten is', () => { assert.equal(startPeriod(periodChoices(400), 'd30'), 'd30'); }); it('valt terug op "sinds begin" als de reeks te kort is voor de bewaarde periode', () => { const kort = periodChoices(10); assert.equal(kort.find(p => p.key === 'd365')?.venster ?? null, null, 'voorwaarde: een jaar is niet te meten'); assert.equal(startPeriod(kort, 'd365'), 'start'); }); it('valt terug op de periode van de pagina bij een onbekende of lege keuze', () => { const metPagina = periodChoices(400, { label: '2025', venster: { van: 10, tot: 50 } }); assert.equal(startPeriod(metPagina, 'weg'), 'page'); assert.equal(startPeriod(metPagina, null), 'page'); assert.equal(startPeriod(periodChoices(400), null), 'start'); }); }); describe('returnLine', () => { const invoer = () => seriesFor(reeks()); it('eindigt op het bedrag erboven, in elk venster', () => { for (const venster of [{ van: 0, tot: 5 }, { van: 2, tot: 5 }, { van: 4, tot: 5 }]) { const lijn = returnLine(invoer(), venster); assert.equal(rond(lijn.points.at(-1).cumulative), rond(lijn.amount), `venster ${venster.van} t/m ${venster.tot}`); } }); it('begint op nul na het begin van de reeks, en op de aankoopdag vanaf dag nul', () => { const later = returnLine(invoer(), { van: 2, tot: 5 }); assert.deepEqual(later.points[0], { i: 2, cumulative: 0, day: null, pct: null }); const vanaf = returnLine(invoer(), { van: 0, tot: 5 }); assert.equal(vanaf.points[0].i, 0); assert.equal(rond(vanaf.points[0].day), 0, 'gekocht tegen de slotkoers van die dag'); }); it('geeft per dag het rendement van die dag', () => { const lijn = returnLine(invoer(), { van: 3, tot: 5 }); assert.equal(rond(lijn.points[1].pct), rond(238 / 240 - 1)); assert.equal(rond(lijn.points[1].day), -2); }); it('heeft zonder venster geen lijn en geen getallen', () => { assert.deepEqual(returnLine(invoer(), null), { amount: null, pct: null, points: [] }); }); }); describe('flatLine', () => { it('geeft nul over de periode, eindigend op vandaag, oudste eerst', () => { const f = flatLine(7, '2026-10-29'); assert.equal(f.amount, 0); assert.equal(f.pct, 0); assert.equal(f.labels.length, 7); assert.equal(f.labels[0], '2026-10-23'); assert.equal(f.labels.at(-1), '2026-10-29'); assert.ok(f.points.every(p => p.cumulative === 0)); }); it('heeft minstens twee punten, ook voor één dag', () => { assert.deepEqual(flatLine(1, '2026-10-29').labels, ['2026-10-28', '2026-10-29']); }); }); describe('seriesFor met een groep', () => { it('is met alle assets erin hetzelfde als het totaal', () => { const r = reeks(); const groep = seriesFor(r, [A.id, B.id]); assert.deepEqual(groep.waarden.map(rond), r.waarde.map(rond)); assert.equal(rond(windowTwr(groep, { van: 0, tot: 5 })), rond(windowTwr(seriesFor(r), { van: 0, tot: 5 }))); }); it('telt alleen de assets van de groep, vanaf de eerste dag van een van hen', () => { const r = reeks(); const groep = seriesFor(r, [B.id]); assert.deepEqual(groep.waarden.map(rond), r.perAsset.get(B.id).map(rond)); assert.equal(groep.eersteDag, r.eersteDagPerAsset.get(B.id)); assert.equal(groep.eenheden, undefined, 'eenheden van verschillende assets tellen niet op'); }); }); describe('contributorsPerDay', () => { it('telt per dag op tot het resultaat van de lijn, grootste bedrag eerst', () => { const r = reeks(); const per = contributorsPerDay(r, [A.id, B.id], { van: 0, tot: 5 }); assert.deepEqual(per.get(4).map(c => [c.id, rond(c.day), rond(c.pct)]), [[B.id, -12, rond(54 / 60 - 1)], [A.id, 10, rond(130 / 120 - 1)]]); const lijn = returnLine(seriesFor(r), { van: 0, tot: 5 }); for (const p of lijn.points.filter(x => per.has(x.i))) { assert.equal(rond(per.get(p.i).reduce((s, c) => s + c.day, 0)), rond(p.day), `dag ${p.i}`); } }); it('houdt het bij n per dag, en laat een asset zonder beweging weg', () => { const per = contributorsPerDay(reeks(), [A.id, B.id], { van: 0, tot: 5 }, 1); assert.deepEqual(per.get(4).map(c => c.id), [B.id]); assert.deepEqual(contributorsPerDay(reeks(), [A.id, B.id], { van: 0, tot: 5 }).get(1).map(c => c.id), [A.id]); }); it('is leeg voor één asset: dat is de lijn zelf', () => { assert.equal(contributorsPerDay(reeks(), [A.id], { van: 0, tot: 5 }).size, 0); }); }); describe('idsForSelection', () => { const assets = [A, B, { id: 4, kind: 'crypto' }]; it('volgt de selectie van de pagina', () => { assert.deepEqual(idsForSelection({ assetIds: [3] }, assets), [3]); assert.deepEqual(idsForSelection({ kind: 'crypto' }, assets), [1, 4]); }); it('valt terug op het hele vermogen', () => { assert.equal(idsForSelection(null, assets), null); assert.equal(idsForSelection({ kind: 'fiat' }, assets), null, 'een soort zonder assets'); }); });