Files
AtreidesAssetsFree/tests/repo/license-limits.test.mjs
T
2026-10-29 11:57:29 +01:00

216 lines
9.9 KiB
JavaScript

// 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');
});
});