// Generated, do not edit. sha256:38c4b07d1566cda74ef6cac4d031f49fd52004b6938fdee8f13e3e7678fc12c7 import { describe, it, beforeEach, mock } from 'node:test'; import assert from 'node:assert/strict'; import { createDbHarness } from '../helpers/db-node.mjs'; import { createNwcApiFake } from '../helpers/nwc-api.mjs'; const harness = createDbHarness({ seedPreferences: true }); mock.module('../../server/db.js', { namedExports: harness.exports }); createNwcApiFake().registreer(); let stand = { level: 'free', enforced: true, why: 'none' }; const echt = await import('../../server/license.mjs'); mock.module('../../server/license.mjs', { namedExports: { ...echt, licenseState: () => stand, capacityReached: (soort, huidig) => echt.capacityReached(soort, huidig, stand), hasFeature: (naam) => echt.hasFeature(naam, stand), allowedAssets: () => echt.allowedAssets(stand), }, }); const { createAsset, updateAsset, deleteAsset, listAssets } = await import('../../server/data/assets.js'); const { createAccount, listAccounts } = await import('../../server/data/accounts.js'); const { createValuation, listValuations } = await import('../../server/data/valuations.js'); const { saveConnection, listConnections } = await import('../../server/data/connections.js'); const { setPriceSourceRank } = await import('../../server/data/price-source.js'); const { createWalletSource, updateWalletSource, listWalletSources } = await import('../../server/data/wallet-sources.js'); const EEN = { symbol: 'BTC', name: 'Bitcoin', kind: 'crypto', unit: 'BTC', subunit: 'sat', decimals: 8, displayUnit: 'unit', taxCategory: null, }; const TWEE = { ...EEN, symbol: 'XAU', name: 'Goud', kind: 'metal', unit: 'g', subunit: 'mg', decimals: 3 }; beforeEach(() => { harness.recreate(); stand = { level: 'free', enforced: true, why: 'none' }; }); describe('de gratis stand op fiatrekeningen', () => { const bank = (name) => ({ name, kind: 'bank', isOwnCustody: false, scanEnabled: false, taxCategory: null }); it('laat de EERSTE bankrekening toe en weigert de tweede', async () => { await createAccount(bank('ING')); await assert.rejects(() => createAccount(bank('Rabo')), (fout) => { assert.equal(fout.key, 'accounts.maxFreeBank'); assert.equal(fout.params.max, 1); return true; }); assert.equal(listAccounts().length, 1); }); it('TELT ALLEEN kind bank, dus een exchange of wallet valt erbuiten', async () => { await createAccount(bank('ING')); await createAccount({ ...bank('Kraken'), kind: 'exchange' }); await createAccount({ ...bank('Ledger'), kind: 'wallet' }); assert.equal(listAccounts().length, 3); }); it('laat de tweede bankrekening WEL toe in de betaalde stand', async () => { await createAccount(bank('ING')); stand = { level: 'full', enforced: true, why: 'licensed' }; await createAccount(bank('Rabo')); assert.equal(listAccounts().length, 2); }); }); describe('de gratis stand op assets', () => { it('TELT DE BASISVALUTA NIET MEE, anders is de gratis stand onbruikbaar', async () => { await createAsset({ ...EEN, symbol: 'EUR', name: 'Euro', kind: 'fiat', unit: 'EUR', subunit: 'cent', decimals: 2 }); const id = await createAsset(EEN); assert.ok(id > 0); assert.equal(listAssets().length, 2); }); it('telt een munt die er alleen voor de KOERS is niet mee, en een munt in gebruik wel', async () => { const DOLLAR = { ...EEN, symbol: 'USD', name: 'Dollar', kind: 'fiat', unit: 'USD', subunit: 'cent', decimals: 2 }; await createAsset(DOLLAR); await createAsset(EEN); assert.equal(listAssets().length, 2, 'bitcoin mag naast een ongebruikte dollar'); harness.recreate(); const usd = await createAsset(DOLLAR); stand = { level: 'full', enforced: true, why: 'licensed' }; await createValuation({ assetId: usd, valuedOn: '2026-01-01', accountId: null, balance: 100, fiatRate: 0.9, rateAt: '2026-01-01T00:00:00Z', source: 'manual' }); stand = { level: 'free', enforced: true, why: 'none' }; await assert.rejects(() => createAsset(EEN), (f) => f.key === 'assets.maxFree', 'met een balans in dollars is de dollar het ene asset van de gratis stand'); }); it('laat de EERSTE asset gewoon toe', async () => { const id = await createAsset(EEN); assert.ok(id > 0); assert.equal(listAssets().length, 1); }); it('weigert de TWEEDE, met een vertaalbare sleutel en niet met een SQL-fout', async () => { await createAsset(EEN); const POND = { ...EEN, symbol: 'GBP', name: 'Pond', kind: 'fiat', unit: 'GBP', subunit: 'pence', decimals: 2 }; await assert.rejects(() => createAsset(POND), (fout) => { assert.equal(fout.key, 'assets.maxFree'); assert.equal(fout.params.max, 1); assert.match(fout.message, /free version/i); return true; }); assert.equal(listAssets().length, 1, 'er mag niets half zijn aangemaakt'); }); it('ALLEEN BITCOIN: een ander asset wordt geweigerd, ook als het het eerste is', async () => { await assert.rejects(() => createAsset(TWEE), (fout) => { assert.equal(fout.key, 'assets.freeOnly'); assert.equal(fout.params.list, 'BTC'); return true; }); assert.equal(listAssets().length, 0, 'er mag niets half zijn aangemaakt'); }); it('laat een munt toe, want die valt onder de telling en niet onder de lijst', async () => { const id = await createAsset({ ...EEN, symbol: 'GBP', name: 'Pond', kind: 'fiat', unit: 'GBP', subunit: 'pence', decimals: 2 }); assert.ok(id > 0); }); it('laat de tweede WEL toe in de betaalde stand', async () => { await createAsset(EEN); stand = { level: 'full', enforced: true, why: 'licensed' }; await createAsset(TWEE); assert.equal(listAssets().length, 2); }); it('NEEMT NIETS AF: wijzigen en verwijderen blijven werken boven de grens', async () => { stand = { level: 'full', enforced: true, why: 'licensed' }; const a = await createAsset(EEN); const b = await createAsset(TWEE); stand = { level: 'free', enforced: true, why: 'none' }; await updateAsset(a, { ...EEN, name: 'Bitcoin hernoemd' }); assert.equal(listAssets().find((x) => x.id === a).name, 'Bitcoin hernoemd'); await deleteAsset(b); assert.equal(listAssets().length, 1); }); }); describe('de gratis stand op balansen', () => { const balans = (assetId, dag) => ({ assetId, valuedOn: dag, accountId: null, balance: 100, fiatRate: 50000, rateAt: `${dag}T00:00:00Z`, source: 'manual', }); it('laat ÉÉN balans toe en weigert de tweede', async () => { const asset = await createAsset(EEN); await createValuation(balans(asset, '2026-01-01')); await assert.rejects(() => createValuation(balans(asset, '2026-02-01')), (fout) => { assert.equal(fout.key, 'valuations.maxFree'); assert.equal(fout.params.max, 1); return true; }); assert.equal(listValuations().length, 1); }); it('laat de tweede WEL toe in de betaalde stand', async () => { const asset = await createAsset(EEN); await createValuation(balans(asset, '2026-01-01')); stand = { level: 'full', enforced: true, why: 'licensed' }; await createValuation(balans(asset, '2026-02-01')); assert.equal(listValuations().length, 2); }); }); describe('de features van de gratis stand', () => { it('weigert een lightning-verbinding en een eigen explorer', async () => { await assert.rejects(() => saveConnection({ kind: 'lnd', name: 'Node', url: 'https://x' }), (f) => f.key === 'connections.lightningPaid'); await assert.rejects(() => saveConnection({ kind: 'nwc', name: 'Wallet', url: 'nostr+walletconnect://x' }), (f) => f.key === 'connections.lightningPaid'); await assert.rejects(() => saveConnection({ kind: 'btc_explorer', name: 'Eigen node', url: 'https://x' }), (f) => f.key === 'connections.ownExplorerPaid'); }); it('LEEST verbindingen gewoon, want de grens zit op opslaan en niet op kijken', async () => { stand = { level: 'full', enforced: true, why: 'licensed' }; await saveConnection({ kind: 'btc_explorer', name: 'Eigen node', url: 'https://x' }); stand = { level: 'free', enforced: true, why: 'none' }; assert.equal(listConnections('btc_explorer').length, 1); }); it('laat die verbindingen WEL toe in de betaalde stand', async () => { stand = { level: 'full', enforced: true, why: 'licensed' }; const id = await saveConnection({ kind: 'lnd', name: 'Node', url: 'https://x' }); assert.ok(id); }); it('weigert een NWC- of LND-bron bij een account, ook via wijzigen, maar laat een bestaande staan', async () => { const accountId = await createAccount({ name: 'Wallet', kind: 'wallet', isOwnCustody: true, scanEnabled: false, taxCategory: null }); await assert.rejects(() => createWalletSource({ accountId, kind: 'nwc', value: 'ab'.repeat(32), name: 'W', secret: 'nostr+walletconnect://x' }), (f) => f.key === 'connections.lightningPaid'); await assert.rejects(() => createWalletSource({ accountId, kind: 'lnd', value: '', name: 'N', connectionId: 1 }), (f) => f.key === 'connections.lightningPaid'); const adres = await createWalletSource({ accountId, kind: 'address', value: 'bc1qtest', name: 'A' }); await assert.rejects(() => updateWalletSource(adres, { kind: 'nwc', value: 'ab'.repeat(32), name: 'A', secret: 'nostr+walletconnect://x' }), (f) => f.key === 'connections.lightningPaid'); stand = { level: 'full', enforced: true, why: 'licensed' }; const bron = await createWalletSource({ accountId, kind: 'nwc', value: 'cd'.repeat(32), name: 'W', secret: 'nostr+walletconnect://y' }); stand = { level: 'free', enforced: true, why: 'none' }; await updateWalletSource(bron, { kind: 'nwc', value: 'cd'.repeat(32), name: 'Nieuwe naam' }); assert.equal(listWalletSources(accountId).find(s => s.id === bron).name, 'Nieuwe naam'); }); it('weigert het wijzigen van de bronkeuze-matrix', async () => { const asset = await createAsset(EEN); await assert.rejects(() => setPriceSourceRank(asset, 'spot', 1), (f) => f.key === 'integrations.matrixPaid'); }); });