// Generated, do not edit. sha256:dddfdfd366ef82253787978dcf8368fdcb9f0cf259774eee0d63e666ef6c597c import { describe, it, beforeEach, mock } from 'node:test'; import assert from 'node:assert/strict'; import { createDbHarness } from '../helpers/db-node.mjs'; import { CONFIG, ENUMS } from '../../shared/config.js'; const harness = createDbHarness(); mock.module('../../server/db.js', { namedExports: harness.exports }); const { counts, tableCounts } = await import('../../server/data/counts.js'); const { createScanLog, latestScanLog, listScanLogs } = await import('../../server/data/scan-logs.js'); let ctx; beforeEach(() => { harness.recreate(); harness.exports.run( `INSERT INTO Asset (symbol, name, searchName, kind, unit, subunit, decimals, displayUnit) VALUES ('BTC','Bitcoin','bitcoin','crypto','BTC','sat',8,'subunit')`); const btc = harness.exports.lastId(); harness.exports.run( `INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Kluis','kluis','wallet',1,1,1,NULL)`); ctx = { btc, account: harness.exports.lastId() }; }); function gebeurtenis() { harness.exports.run( `INSERT INTO Event (assetId, type, occurredAt, amount, fiatPrice, toAccountId, source, createdAt) VALUES (?, 'buy', '2024-01-01T00:00:00', 100000, 50000, ?, 'manual', '2024-01-01T00:00:00')`, [ctx.btc, ctx.account]); } describe('counts', () => { it('telt de vier hoofd-entiteiten', () => { gebeurtenis(); harness.exports.run( `INSERT INTO Valuation (assetId, valuedOn, accountId, balance, fiatRate, rateAt, source) VALUES (?, '2024-12-31', ?, 1, 1, '2024-12-31T23:00:00', 'manual')`, [ctx.btc, ctx.account]); assert.deepEqual(counts(), { assets: 1, accounts: 1, events: 1, valuations: 1 }); }); it('geeft nullen op een lege database in plaats van niets', () => { harness.exports.run(`DELETE FROM Asset`); harness.exports.run(`DELETE FROM Account`); assert.deepEqual(counts(), { assets: 0, accounts: 0, events: 0, valuations: 0 }); }); }); describe('tableCounts', () => { it('geeft een rij per tabel uit de whitelist, in dezelfde volgorde', () => { const rijen = tableCounts(); assert.deepEqual(rijen.map(r => r.name), [...CONFIG.DB_TABLES], 'de widget toont de lijst in configuratie-volgorde, dus die mag niet gesorteerd raken'); }); it('draait elke naam uit de whitelist echt af zonder te werpen', () => { const rijen = tableCounts(); assert.ok(rijen.length >= 10, `verwacht een flinke whitelist, kreeg ${rijen.length}`); for (const r of rijen) { assert.equal(typeof r.n, 'number', `${r.name} gaf geen getal terug`); assert.ok(r.n >= 0); } }); it('telt echt en geeft niet overal nul', () => { gebeurtenis(); const perTabel = Object.fromEntries(tableCounts().map(r => [r.name, r.n])); assert.equal(perTabel.Event, 1); assert.equal(perTabel.Asset, 1); assert.equal(perTabel.Valuation, 0); }); }); describe('createScanLog', () => { const scan = (extra = {}) => ({ accountId: ctx.account, status: 'success', ...extra }); const rij = (id) => harness.exports.one(`SELECT * FROM ScanLog WHERE id = ?`, [id]); it('bewaart de velden en geeft het id terug', async () => { const id = await createScanLog(scan({ scannedAt: '2024-05-01T12:00:00', addressesFound: 12, balanceFound: 750_000, proposalsCreated: 2, })); const s = rij(id); assert.equal(s.accountId, ctx.account); assert.equal(s.scannedAt, '2024-05-01T12:00:00'); assert.equal(s.status, 'success'); assert.equal(s.addressesFound, 12); assert.equal(s.balanceFound, 750_000); assert.equal(s.proposalsCreated, 2); }); it('zet het tijdstip zelf als de aanroeper er geen geeft', async () => { const id = await createScanLog(scan()); assert.ok(rij(id).scannedAt, 'een scan zonder tijdstip is niet te ordenen'); }); it('bewaart rawData als JSON-tekst', async () => { const id = await createScanLog(scan({ rawData: { adressen: ['bc1q…'], saldo: 750_000 } })); const ruw = rij(id).rawData; assert.equal(typeof ruw, 'string'); assert.deepEqual(JSON.parse(ruw), { adressen: ['bc1q…'], saldo: 750_000 }); }); it('laat rawData leeg als er niets is', async () => { const id = await createScanLog(scan()); assert.equal(rij(id).rawData, null, 'geen "null" als tekst, maar echt leeg'); }); it('accepteert elke status uit de registry en weigert de rest', async () => { for (const status of ENUMS.SCAN_STATUS) { const id = await createScanLog(scan({ status })); assert.equal(rij(id).status, status); } await assert.rejects(() => createScanLog(scan({ status: 'bijna-goed' })), /status/); }); it('persisteert', async () => { const voor = harness.calls.persist; await createScanLog(scan()); assert.equal(harness.calls.persist, voor + 1); }); }); describe('latestScanLog en listScanLogs', () => { const scan = (extra = {}) => createScanLog({ accountId: ctx.account, status: 'success', ...extra }); it('geeft de laatste scan van dat account', async () => { await scan({ scannedAt: '2024-01-01T00:00:00' }); const laatste = await scan({ scannedAt: '2024-06-01T00:00:00' }); assert.equal(latestScanLog(ctx.account).id, laatste); }); it('kiest bij een gelijk tijdstip de hoogste id', async () => { await scan({ scannedAt: '2024-06-01T00:00:00', addressesFound: 1 }); const tweede = await scan({ scannedAt: '2024-06-01T00:00:00', addressesFound: 2 }); assert.equal(latestScanLog(ctx.account).id, tweede); assert.equal(latestScanLog(ctx.account).addressesFound, 2); }); it('geeft null als er nog nooit gescand is', () => { assert.equal(latestScanLog(ctx.account), null); }); it('kijkt alleen naar het gevraagde account', async () => { harness.exports.run( `INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Ander','ander','wallet',1,1,1,NULL)`); const ander = harness.exports.lastId(); await scan({ scannedAt: '2024-06-01T00:00:00' }); assert.equal(latestScanLog(ander), null); assert.deepEqual(listScanLogs(ander), []); }); it('geeft de volledige historie, nieuwste eerst', async () => { await scan({ scannedAt: '2024-01-01T00:00:00' }); await scan({ scannedAt: '2024-06-01T00:00:00' }); await scan({ scannedAt: '2024-03-01T00:00:00' }); assert.deepEqual(listScanLogs(ctx.account).map(s => s.scannedAt), ['2024-06-01T00:00:00', '2024-03-01T00:00:00', '2024-01-01T00:00:00']); }); it('is append-only: een tweede scan overschrijft de eerste niet', async () => { await scan({ scannedAt: '2024-01-01T00:00:00', status: 'failed' }); await scan({ scannedAt: '2024-06-01T00:00:00', status: 'success' }); assert.equal(listScanLogs(ctx.account).length, 2); assert.deepEqual(listScanLogs(ctx.account).map(s => s.status), ['success', 'failed']); }); });