Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,429 @@
|
||||
// Generated, do not edit. sha256:43e27327deb8801c6e640676df136f116a9043c3e6d4e1f65b6469a9f90a6fa6
|
||||
import { describe, it, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
const INSTELLING = { asset_show_name: 1, asset_show_symbol: 1 };
|
||||
mock.module('../../client/app-settings.js', {
|
||||
namedExports: { appSetting: (k) => INSTELLING[k], baseCurrency: () => 'EUR', setAppSetting: async () => {} },
|
||||
});
|
||||
|
||||
const { fiatAtPrice, fiatValue, fiatHistorical } = await import('../../client/ui/fiat.js');
|
||||
const { assetLabel, assetLabelHtml } = await import('../../client/ui/asset-label.js');
|
||||
const { RANGE_DAYS, SPOT_RANGE_DAYS, rangeSeries, intradayStart, rangeCycleButton, wireRangeCycle, rangePointLabel, rangePointSources, namedDaySources } = await import('../../client/ui/range-cycle.js');
|
||||
const { serviceOrder, matrixCardHtml } = await import('../../client/ui/source-matrix.js');
|
||||
|
||||
describe('fiatAtPrice: van kleinste eenheid naar een bedrag', () => {
|
||||
it('rekent met de decimalen van het asset', () => {
|
||||
assert.match(fiatAtPrice(100000, 8, 50000), /50,00/);
|
||||
});
|
||||
|
||||
it('gebruikt acht decimalen als er geen meegegeven zijn', () => {
|
||||
assert.equal(fiatAtPrice(100000000, undefined, 7), fiatAtPrice(100000000, 8, 7));
|
||||
});
|
||||
|
||||
it('geeft een lege string als er geen prijs bekend is', () => {
|
||||
assert.equal(fiatAtPrice(100, 8, null), '');
|
||||
assert.equal(fiatAtPrice(100, 8, undefined), '');
|
||||
});
|
||||
|
||||
it('rekent nul gewoon uit in plaats van hem als onbekend te behandelen', () => {
|
||||
assert.match(fiatAtPrice(0, 8, 50000), /0,00/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fiatValue en fiatHistorical: de twee wegen naar leeg', () => {
|
||||
it('geeft niets voor het reken-asset', () => {
|
||||
assert.equal(fiatValue(12345, { id: 1, symbol: 'EUR', decimals: 2 }, 'eur'), '');
|
||||
});
|
||||
|
||||
it('geeft niets zonder koers in de cache, en zonder asset', () => {
|
||||
assert.equal(fiatValue(100, { id: 999, symbol: 'BTC', decimals: 8 }, 'eur'), '');
|
||||
assert.equal(fiatValue(100, null, 'eur'), '');
|
||||
assert.equal(fiatHistorical(100, null, '2026-03-01'), '');
|
||||
assert.equal(fiatHistorical(100, { id: 999, decimals: 8 }, '2026-03-01'), '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetLabel: de twee weergaveschuiven', () => {
|
||||
const btc = { name: 'Bitcoin', symbol: 'BTC' };
|
||||
|
||||
it('toont naam en symbool samen', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
assert.equal(assetLabel(btc), 'Bitcoin (BTC)');
|
||||
});
|
||||
|
||||
it('toont alleen de naam, of alleen het symbool', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 0 });
|
||||
assert.equal(assetLabel(btc), 'Bitcoin');
|
||||
Object.assign(INSTELLING, { asset_show_name: 0, asset_show_symbol: 1 });
|
||||
assert.equal(assetLabel(btc), 'BTC');
|
||||
});
|
||||
|
||||
it('valt terug op wat er wél is als de gekozen helft ontbreekt', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 0 });
|
||||
assert.equal(assetLabel({ symbol: 'XAU' }), 'XAU');
|
||||
Object.assign(INSTELLING, { asset_show_name: 0, asset_show_symbol: 1 });
|
||||
assert.equal(assetLabel({ name: 'Goud' }), 'Goud');
|
||||
});
|
||||
|
||||
it('leest de alias-velden van een JOIN-rij', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
assert.equal(assetLabel({ asset_name: 'Goud', asset_symbol: 'XAU' }), 'Goud (XAU)');
|
||||
});
|
||||
|
||||
it('geeft voorrang aan het eigen veld boven de alias, ook als dat leeg is', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 0 });
|
||||
assert.equal(assetLabel({ name: null, asset_name: 'Bitcoin', symbol: 'BTC' }), 'BTC');
|
||||
});
|
||||
|
||||
it('geeft een lege string voor niets', () => {
|
||||
assert.equal(assetLabel(null), '');
|
||||
assert.equal(assetLabelHtml(null), '');
|
||||
});
|
||||
|
||||
it('laat met `withoutSymbol` het symbool weg, want de hoeveelheid droeg het al', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
const met = assetLabelHtml({ asset_name: 'Proef zonder koers', asset_symbol: 'PRFN' });
|
||||
const zonder = assetLabelHtml({ asset_name: 'Proef zonder koers', asset_symbol: 'PRFN' }, { withoutSymbol: true });
|
||||
assert.match(met, /PRFN/, 'zonder de vlag blijft het gedrag ongewijzigd');
|
||||
assert.match(zonder, /Proef zonder koers/);
|
||||
assert.ok(!zonder.includes('PRFN'), zonder);
|
||||
});
|
||||
|
||||
it('toont een naam die gelijk is aan het symbool één keer, ook met beide schuiven aan', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
assert.equal(assetLabel({ name: 'XRP', symbol: 'XRP' }), 'XRP');
|
||||
assert.equal(assetLabel({ name: 'Xrp', symbol: 'XRP' }), 'Xrp');
|
||||
assert.equal(assetLabel({ name: 'XRP Ledger', symbol: 'XRP' }), 'XRP Ledger (XRP)');
|
||||
const h = assetLabelHtml({ name: 'XRP', symbol: 'XRP' });
|
||||
assert.equal(h.match(/XRP/g).length, 1, h);
|
||||
assert.ok(!h.includes('t-muted-cell'), h);
|
||||
});
|
||||
|
||||
it('valt met `withoutSymbol` terug op het symbool als er geen naam te tonen is', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
assert.match(assetLabelHtml({ asset_symbol: 'PRFN' }, { withoutSymbol: true }), /PRFN/);
|
||||
Object.assign(INSTELLING, { asset_show_name: 0, asset_show_symbol: 1 });
|
||||
assert.match(assetLabelHtml({ asset_name: 'Bitcoin', asset_symbol: 'BTC' }, { withoutSymbol: true }), /BTC/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetLabelHtml: bouwt HTML en escapet zelf', () => {
|
||||
it('zet naam en symbool in hun eigen span', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 1 });
|
||||
const h = assetLabelHtml({ name: 'Bitcoin', symbol: 'BTC' });
|
||||
assert.match(h, /<span class="asset-name">Bitcoin<\/span>/);
|
||||
assert.match(h, /<span class="t-muted-cell">BTC<\/span>/);
|
||||
});
|
||||
|
||||
it('escapet een naam uit de database', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 0 });
|
||||
const h = assetLabelHtml({ name: '<script>x</script> & co' });
|
||||
|
||||
assert.equal(h, '<span class="asset-name"><script>x</script> & co</span>');
|
||||
assert.equal(h.includes('<script>'), false, 'de tag mag niet als tag overleven');
|
||||
});
|
||||
|
||||
it('escapet GEEN aanhalingsteken, en dat is een grens en geen fout', () => {
|
||||
Object.assign(INSTELLING, { asset_show_name: 1, asset_show_symbol: 0 });
|
||||
assert.match(assetLabelHtml({ name: 'zeg "hallo"' }), /zeg "hallo"/,
|
||||
'als dit ooit verandert: controleer of de aanroepers nog steeds alleen elementinhoud zijn');
|
||||
});
|
||||
});
|
||||
|
||||
describe('range-cycle: de gedeelde tijdvakknop', () => {
|
||||
it('kent drie tijdvakken met hun dagen', () => {
|
||||
assert.deepEqual(RANGE_DAYS, { week: 7, month: 30, year: 365 });
|
||||
});
|
||||
|
||||
it('cyclet week naar maand naar jaar en weer terug', () => {
|
||||
const gezien = [];
|
||||
const wrap = {};
|
||||
let huidig = 'week';
|
||||
wireRangeCycle(wrap, () => huidig, (r) => { huidig = r; gezien.push(r); });
|
||||
|
||||
const klik = { target: { closest: (sel) => (sel === '.range-cycle-btn' ? {} : null) } };
|
||||
wrap.onclick(klik); wrap.onclick(klik); wrap.onclick(klik);
|
||||
|
||||
assert.deepEqual(gezien, ['month', 'year', 'week']);
|
||||
});
|
||||
|
||||
it('doet niets bij een klik naast de knop', () => {
|
||||
let geroepen = 0;
|
||||
const wrap = {};
|
||||
wireRangeCycle(wrap, () => 'week', () => { geroepen++; });
|
||||
wrap.onclick({ target: { closest: () => null } });
|
||||
assert.equal(geroepen, 0);
|
||||
});
|
||||
|
||||
it('levert een knop met het label van het huidige tijdvak', () => {
|
||||
const h = rangeCycleButton('month');
|
||||
assert.match(h, /range-cycle-btn/);
|
||||
assert.match(h, /aria-label="/, 'een icoonknop hoort een toegankelijke naam te hebben');
|
||||
});
|
||||
|
||||
it('de widgets met een live spot cyclen dag, week, maand, jaar', () => {
|
||||
const gezien = [];
|
||||
const wrap = {};
|
||||
let huidig = 'day';
|
||||
wireRangeCycle(wrap, () => huidig, (r) => { huidig = r; gezien.push(r); }, SPOT_RANGE_DAYS);
|
||||
const klik = { target: { closest: (sel) => (sel === '.range-cycle-btn' ? {} : null) } };
|
||||
for (let i = 0; i < 4; i++) wrap.onclick(klik);
|
||||
assert.deepEqual(gezien, ['week', 'month', 'year', 'day']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rangeSeries', () => {
|
||||
const DAG = 86400000;
|
||||
const nu = Date.parse('2026-10-09T13:00:00Z');
|
||||
const middernacht = Math.floor(nu / DAG) * DAG;
|
||||
const maand = Array.from({ length: 30 }, (_, i) => [middernacht - (30 - i) * DAG, 100 + i]);
|
||||
|
||||
it('dag: precies de slotkoers van gisteren en de spot', () => {
|
||||
assert.deepEqual(rangeSeries(maand, 'day', 200, nu), [[middernacht - DAG, 129], [middernacht, 200]]);
|
||||
});
|
||||
|
||||
it('dag zonder spot: de laatste twee slotkoersen', () => {
|
||||
assert.deepEqual(rangeSeries(maand, 'day', null, nu), maand.slice(-2));
|
||||
});
|
||||
|
||||
it('week: de dagen binnen zeven dagen, met de spot als vandaag', () => {
|
||||
const uit = rangeSeries(maand, 'week', 200, nu);
|
||||
assert.equal(uit.length, 7);
|
||||
assert.deepEqual(uit.at(-1), [middernacht, 200]);
|
||||
});
|
||||
|
||||
it('te weinig punten in het tijdvak: de hele reeks', () => {
|
||||
const kort = [[middernacht - 40 * DAG, 90], [middernacht - 35 * DAG, 95]];
|
||||
assert.equal(rangeSeries(kort, 'week', null, nu), kort);
|
||||
});
|
||||
|
||||
const binnen = [[middernacht + 3600_000, 130], [middernacht + 7200_000, 135]];
|
||||
|
||||
it('dag met reeks: slotkoers aan het eind van zijn dag, de reeks, de spot op nu', () => {
|
||||
assert.deepEqual(rangeSeries(maand, 'day', 200, nu, binnen),
|
||||
[[middernacht, 129], ...binnen, [nu, 200]]);
|
||||
});
|
||||
|
||||
it('dag met reeks: punten vóór het einde van de slotdag of na nu vallen weg', () => {
|
||||
const rommel = [[middernacht - 60_000, 1], ...binnen, [nu + 60_000, 2]];
|
||||
assert.deepEqual(rangeSeries(maand, 'day', 200, nu, rommel), [[middernacht, 129], ...binnen, [nu, 200]]);
|
||||
});
|
||||
|
||||
it('dag met een lege of onbruikbare reeks: de rechte lijn van nu', () => {
|
||||
const rechte = [[middernacht - DAG, 129], [middernacht, 200]];
|
||||
assert.deepEqual(rangeSeries(maand, 'day', 200, nu, []), rechte);
|
||||
assert.deepEqual(rangeSeries(maand, 'day', 200, nu, [[nu + 1, 5]]), rechte);
|
||||
});
|
||||
|
||||
it('dag met reeks maar zonder spot: geen reeks, want er is geen eindpunt', () => {
|
||||
assert.deepEqual(rangeSeries(maand, 'day', null, nu, binnen), maand.slice(-2));
|
||||
});
|
||||
|
||||
it('de reeks raakt de andere tijdvakken niet', () => {
|
||||
assert.deepEqual(rangeSeries(maand, 'week', 200, nu, binnen), rangeSeries(maand, 'week', 200, nu));
|
||||
});
|
||||
});
|
||||
|
||||
describe('rangePointLabel: de hint bij een punt', () => {
|
||||
const datum = { day: 'numeric', month: 'short', year: 'numeric' };
|
||||
|
||||
it('binnen de dag: de prijs met de lokale datum en tijd', () => {
|
||||
const ms = Date.UTC(2026, 9, 16, 13, 7);
|
||||
const lokaal = new Date(ms).toLocaleString('nl-NL', { ...datum, hour: '2-digit', minute: '2-digit' });
|
||||
assert.equal(rangePointLabel('day', '€ 72.386', ms), `€ 72.386\n${lokaal}`);
|
||||
assert.match(lokaal, /2026/);
|
||||
});
|
||||
|
||||
it('in een ander tijdvak: de kalenderdag van het punt, zonder tijd', () => {
|
||||
const middernacht = Date.UTC(2026, 9, 16);
|
||||
const dag = new Date(middernacht).toLocaleDateString('nl-NL', { ...datum, timeZone: 'UTC' });
|
||||
assert.match(dag, /^16 okt\.? 2026$/);
|
||||
for (const range of Object.keys(RANGE_DAYS)) assert.equal(rangePointLabel(range, '€ 72.386', middernacht), `€ 72.386\n${dag}`);
|
||||
});
|
||||
|
||||
it('ook ten westen van Greenwich, waar middernacht UTC nog de vorige dag is', () => {
|
||||
const oud = process.env.TZ;
|
||||
process.env.TZ = 'America/New_York';
|
||||
try {
|
||||
assert.match(rangePointLabel('week', '€ 1', Date.UTC(2026, 9, 16)), /16 okt\.? 2026$/);
|
||||
} finally {
|
||||
if (oud === undefined) delete process.env.TZ; else process.env.TZ = oud;
|
||||
}
|
||||
});
|
||||
|
||||
it('zonder moment: alleen de prijs', () => {
|
||||
assert.equal(rangePointLabel('day', '€ 72.386', undefined), '€ 72.386');
|
||||
assert.equal(rangePointLabel('week', '€ 72.386', NaN), '€ 72.386');
|
||||
});
|
||||
|
||||
it('met een bron: die komt als laatste, en zonder bron blijft de hint zoals hij was', () => {
|
||||
const middernacht = Date.UTC(2026, 9, 16);
|
||||
const dag = new Date(middernacht).toLocaleDateString('nl-NL', { ...datum, timeZone: 'UTC' });
|
||||
assert.equal(rangePointLabel('week', '€ 1', middernacht, 'CoinGecko'), `€ 1\n${dag}\nCoinGecko`);
|
||||
assert.equal(rangePointLabel('week', '€ 1', middernacht, null), `€ 1\n${dag}`);
|
||||
assert.equal(rangePointLabel('week', '€ 1', NaN, 'CoinGecko'), '€ 1\nCoinGecko');
|
||||
});
|
||||
|
||||
it('zet elk deel op een eigen regel, de prijs bovenaan', () => {
|
||||
const regels = rangePointLabel('week', '€ 1', Date.UTC(2026, 9, 16), 'CoinGecko').split('\n');
|
||||
assert.equal(regels.length, 3);
|
||||
assert.equal(regels[0], '€ 1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rangePointSources: de bron per punt', () => {
|
||||
const DAG = 86400000;
|
||||
const d0 = Date.UTC(2026, 9, 12);
|
||||
const nu = Date.UTC(2026, 9, 16, 14, 30);
|
||||
const vandaag = Date.UTC(2026, 9, 16);
|
||||
const grid = [[d0, 10], [d0 + DAG, 11], [d0 + 2 * DAG, 11], [d0 + 3 * DAG, 11]];
|
||||
const days = new Map([[d0, 'CoinGecko'], [d0 + DAG, 'Atreides Services']]);
|
||||
const dagTekst = ms => new Date(ms).toLocaleDateString('nl-NL', { day: 'numeric', month: 'short', year: 'numeric', timeZone: 'UTC' });
|
||||
|
||||
it('een week: eigen dagen bij naam, doorgetrokken dagen met de dag van de koers, de spot als laatste', () => {
|
||||
const use = rangeSeries(grid, 'week', 12, nu);
|
||||
const bron = rangePointSources(use, { range: 'week', spot: 12, nowMs: nu, live: 'Atreides Services (Bitvavo)', days });
|
||||
assert.equal(use[use.length - 1][0], vandaag);
|
||||
assert.equal(bron.get(d0), 'CoinGecko');
|
||||
assert.equal(bron.get(d0 + DAG), 'Atreides Services');
|
||||
assert.equal(bron.get(d0 + 2 * DAG), `Atreides Services, koers van ${dagTekst(d0 + DAG)}`);
|
||||
assert.equal(bron.get(vandaag), 'Atreides Services (Bitvavo)');
|
||||
});
|
||||
|
||||
it('zonder spot is het laatste punt geen actuele koers', () => {
|
||||
const use = rangeSeries(grid, 'week', null, nu);
|
||||
const bron = rangePointSources(use, { range: 'week', spot: null, nowMs: nu, live: 'Bitvavo', days });
|
||||
assert.equal(bron.get(d0 + 3 * DAG), `Atreides Services, koers van ${dagTekst(d0 + DAG)}`);
|
||||
assert.ok(![...bron.values()].includes('Bitvavo'));
|
||||
});
|
||||
|
||||
it('binnen de dag: een minuutpunt met een eigen bron draagt die, de rest de bron van de reeks', () => {
|
||||
const intraday = [[vandaag + 3600000, 11.5], [vandaag + 7200000, 11.8]];
|
||||
const use = rangeSeries(grid, 'day', 12, nu, intraday);
|
||||
const intradayAt = new Map([[vandaag + 3600000, 'Atreides Services (bitvavo)']]);
|
||||
const bron = rangePointSources(use, { range: 'day', spot: 12, nowMs: nu, live: 'Spot', intraday: 'Minuten', intradayAt, days });
|
||||
assert.equal(bron.get(vandaag + 3600000), 'Atreides Services (bitvavo)');
|
||||
assert.equal(bron.get(vandaag + 7200000), 'Minuten');
|
||||
assert.equal(bron.get(nu), 'Spot', 'de spot blijft de spot, ook met een kaart per punt');
|
||||
});
|
||||
|
||||
it('binnen de dag: de minuutreeks tussen de slotkoers en de spot', () => {
|
||||
const intraday = [[vandaag + 3600000, 11.5], [vandaag + 7200000, 11.8]];
|
||||
const use = rangeSeries(grid, 'day', 12, nu, intraday);
|
||||
const bron = rangePointSources(use, { range: 'day', spot: 12, nowMs: nu, live: 'Spot', intraday: 'Minuten', days });
|
||||
assert.equal(use.length, 4);
|
||||
assert.equal(bron.get(use[0][0]), `Atreides Services, koers van ${dagTekst(d0 + DAG)}`);
|
||||
assert.equal(bron.get(use[1][0]), 'Minuten');
|
||||
assert.equal(bron.get(use[2][0]), 'Minuten');
|
||||
assert.equal(bron.get(nu), 'Spot');
|
||||
});
|
||||
|
||||
it('binnen de dag zonder reeks: twee punten, en geen van beide heet minuutreeks', () => {
|
||||
const use = rangeSeries(grid, 'day', 12, nu, null);
|
||||
const bron = rangePointSources(use, { range: 'day', spot: 12, nowMs: nu, live: 'Spot', intraday: 'Minuten', days });
|
||||
assert.equal(use.length, 2);
|
||||
assert.equal(bron.get(vandaag), 'Spot');
|
||||
assert.notEqual(bron.get(use[0][0]), 'Minuten');
|
||||
});
|
||||
|
||||
it('zonder iets te zeggen: geen bron, ook niet voor een dag vóór de eerste eigen rij', () => {
|
||||
assert.equal(rangePointSources([], { range: 'week' }).size, 0);
|
||||
assert.equal(rangePointSources(null, { range: 'week' }).size, 0);
|
||||
const bron = rangePointSources([[d0 - DAG, 9], [d0, 10]], { range: 'week', nowMs: nu, days });
|
||||
assert.equal(bron.has(d0 - DAG), false);
|
||||
assert.equal(bron.get(d0), 'CoinGecko');
|
||||
});
|
||||
|
||||
it('namedDaySources: ids naar namen, en een onbekende provider valt weg in plaats van verkeerd te heten', () => {
|
||||
const dagBron = (providerId, sourceName = null) => ({ providerId, sourceName });
|
||||
const byDay = new Map([[d0, dagBron(1)], [d0 + DAG, dagBron(2)], [d0 + 2 * DAG, dagBron(99)]]);
|
||||
const named = namedDaySources(byDay, [{ id: 1, name: 'CoinGecko' }, { id: 2, name: 'Atreides Services' }]);
|
||||
assert.deepEqual([...named], [[d0, 'CoinGecko'], [d0 + DAG, 'Atreides Services']]);
|
||||
assert.equal(namedDaySources(byDay, null).size, 0);
|
||||
});
|
||||
|
||||
it('namedDaySources: de bron achter een dagkoers van de dienst staat erbij, zoals bij elke koers van de dienst', () => {
|
||||
const byDay = new Map([[d0, { providerId: 2, sourceName: 'Bitvavo' }]]);
|
||||
const named = namedDaySources(byDay, [{ id: 2, name: 'Atreides Services' }]);
|
||||
assert.equal(named.get(d0), 'Atreides Services (Bitvavo)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('intradayStart: waar de reeks binnen de dag begint', () => {
|
||||
const DAG = 86400000;
|
||||
const nu = Date.parse('2026-10-09T13:00:00Z');
|
||||
const middernacht = Math.floor(nu / DAG) * DAG;
|
||||
|
||||
it('het eind van de laatste slotdag vóór vandaag', () => {
|
||||
assert.equal(intradayStart([[middernacht - 2 * DAG, 1], [middernacht - DAG, 2]], nu), middernacht);
|
||||
});
|
||||
|
||||
it('een opgeslagen waarde van vandaag telt niet als slotkoers', () => {
|
||||
assert.equal(intradayStart([[middernacht - DAG, 2], [middernacht, 3]], nu), middernacht);
|
||||
});
|
||||
|
||||
it('na een weekend zonder slot: vanaf het eind van de laatste', () => {
|
||||
assert.equal(intradayStart([[middernacht - 3 * DAG, 1]], nu), middernacht - 2 * DAG);
|
||||
});
|
||||
|
||||
it('zonder reeks: vandaag middernacht', () => {
|
||||
assert.equal(intradayStart([], nu), middernacht);
|
||||
assert.equal(intradayStart(null, nu), middernacht);
|
||||
});
|
||||
});
|
||||
|
||||
describe('serviceOrder: de plek van de dienst in de keten', () => {
|
||||
const app = (providerId, rank) => ({ providerId, rank, own: false });
|
||||
const zelf = (providerId, rank) => ({ providerId, rank, own: true });
|
||||
|
||||
it('eerst: zelf gekozen, dan de dienst, dan de keuze van de app', () => {
|
||||
const { ranks, service } = serviceOrder([app(1, 1), zelf(2, 2), app(3, 3)], 'first');
|
||||
assert.deepEqual([...ranks], [[2, 1], [1, 3], [3, 4]]);
|
||||
assert.equal(service, 2);
|
||||
});
|
||||
|
||||
it('eerst zonder eigen keuze: de dienst bovenaan', () => {
|
||||
const { ranks, service } = serviceOrder([app(1, 1)], 'first');
|
||||
assert.equal(service, 1);
|
||||
assert.equal(ranks.get(1), 2);
|
||||
});
|
||||
|
||||
it('als terugval: alle gekozen bronnen, dan de dienst', () => {
|
||||
const { ranks, service } = serviceOrder([zelf(2, 2), app(1, 1)], 'fallback');
|
||||
assert.deepEqual([...ranks], [[1, 1], [2, 2]]);
|
||||
assert.equal(service, 3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('matrixCardHtml: de dienst als vaste kolom', () => {
|
||||
const bron = { id: 7, name: 'Bitvavo', isActive: 1, coverage: ['BTC'], endpoints: [{ capability: 'spot' }] };
|
||||
const btc = { id: 1, symbol: 'BTC', kind: 'crypto', name: 'Bitcoin' };
|
||||
const ctx = (mode, own, covered = [1]) => ({
|
||||
alle: [bron], providers: [bron], rateSource: new Map(),
|
||||
cell: new Map([['1|spot|7', { rank: 1, proposed: false, own }]]),
|
||||
service: { mode, covered: new Set(covered) },
|
||||
});
|
||||
const nummers = html => [...html.matchAll(/class="mx-rank[^"]*">(\d+)</g)].map(m => Number(m[1]));
|
||||
|
||||
it('stand eerst, Bitvavo door de app gekozen: de dienst op 1, Bitvavo op 2', () => {
|
||||
const html = matrixCardHtml(btc, ctx('first', false));
|
||||
assert.match(html, /Atreides Services/);
|
||||
assert.deepEqual(nummers(html), [2, 1]);
|
||||
assert.match(html, /mx-svc/);
|
||||
});
|
||||
|
||||
it('stand eerst, Bitvavo zelf gekozen: Bitvavo op 1, de dienst op 2', () => {
|
||||
assert.deepEqual(nummers(matrixCardHtml(btc, ctx('first', true))), [1, 2]);
|
||||
});
|
||||
|
||||
it('de dienstkolom is niet klikbaar', () => {
|
||||
const html = matrixCardHtml(btc, ctx('first', false));
|
||||
assert.doesNotMatch(html, /class="mx-cell"[^>]*>[^<]*<span class="mx-rank[^"]*is-service/);
|
||||
});
|
||||
|
||||
it('stand uit, of een asset dat de dienst niet dekt: geen kolom', () => {
|
||||
assert.doesNotMatch(matrixCardHtml(btc, ctx('off', false)), /Atreides Services/);
|
||||
assert.doesNotMatch(matrixCardHtml(btc, ctx('first', false, [])), /Atreides Services/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user