🚨 adding trailing commas everywhere (#148)

Two changes in this PR:

1. fail CI jobs if there are lint warnings
2. add trailing comas everywhere (this aligns `actual-server` with
`actual`)
This commit is contained in:
Matiss Janis Aboltins
2023-03-07 19:45:51 +00:00
committed by GitHub
parent 95a0769eaa
commit bd7992a45a
28 changed files with 341 additions and 334 deletions

View File

@@ -12,12 +12,10 @@ module.exports = {
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-unused-vars': [
'warn',
'error',
{
argsIgnorePattern: '^_'
}
],
'@typescript-eslint/no-var-requires': 'off'
]
}
};

View File

@@ -1,4 +1,4 @@
{
"singleQuote": true,
"trailingComma": "none"
"singleQuote": true,
"trailingComma": "all"
}

View File

@@ -34,12 +34,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
let budget = db.runQuery(
`SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!budget-%'`,
[],
true
true,
);
db.transaction(() => {
budget.map((monthBudget) => {
let match = monthBudget.name.match(
/^(budget-report|budget)(\d+)!budget-(.+)$/
/^(budget-report|budget)(\d+)!budget-(.+)$/,
);
if (match == null) {
console.log('Warning: invalid budget month name', monthBudget.name);
@@ -60,7 +60,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
let carryover = db.runQuery(
'SELECT * FROM spreadsheet_cells WHERE name = ?',
[`${sheetName}!carryover-${cat}`],
true
true,
);
let table = type === 'budget-report' ? 'reflect_budgets' : 'zero_budgets';
@@ -71,8 +71,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
dbmonth,
cat,
amount,
carryover.length > 0 && getValue(carryover[0]) === 'true' ? 1 : 0
]
carryover.length > 0 && getValue(carryover[0]) === 'true' ? 1 : 0,
],
);
});
});
@@ -81,7 +81,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
let buffers = db.runQuery(
`SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!buffered'`,
[],
true
true,
);
db.transaction(() => {
buffers.map((buffer) => {
@@ -95,7 +95,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
db.runQuery(
`INSERT INTO zero_budget_months (id, buffered) VALUES (?, ?)`,
[month, amount]
[month, amount],
);
}
});
@@ -105,7 +105,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
let notes = db.runQuery(
`SELECT * FROM spreadsheet_cells WHERE name LIKE 'notes!%'`,
[],
true
true,
);
let parseNote = (str) => {

View File

@@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"start": "node app",
"lint": "eslint .",
"lint": "eslint . --max-warnings 0",
"build": "tsc",
"test": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --trace-warnings' jest --coverage",
"types": "tsc --noEmit --incremental",

View File

@@ -30,7 +30,7 @@ app.get('/needs-bootstrap', (req, res) => {
res.send({
status: 'ok',
data: { bootstrapped: rows.length > 0 }
data: { bootstrapped: rows.length > 0 },
});
});
@@ -42,7 +42,7 @@ app.post('/bootstrap', (req, res) => {
if (rows.length !== 0) {
res.status(400).send({
status: 'error',
reason: 'already-bootstrapped'
reason: 'already-bootstrapped',
});
return;
}

View File

@@ -4,7 +4,7 @@ import { nordigenService } from './services/nordigen-service.js';
import {
RequisitionNotLinked,
AccountNotLinedToRequisition,
GenericNordigenError
GenericNordigenError,
} from './errors.js';
import { handleError } from './util/handle-error.js';
import validateUser from '../util/validate-user.js';
@@ -29,17 +29,17 @@ app.post(
const { link, requisitionId } = await nordigenService.createRequisition({
accessValidForDays,
institutionId,
host: origin
host: origin,
});
res.send({
status: 'ok',
data: {
link,
requisitionId
}
requisitionId,
},
});
})
}),
);
app.post(
@@ -55,20 +55,20 @@ app.post(
status: 'ok',
data: {
...requisition,
accounts
}
accounts,
},
});
} catch (error) {
if (error instanceof RequisitionNotLinked) {
res.send({
status: 'ok',
requisitionStatus: error.details.requisitionStatus
requisitionStatus: error.details.requisitionStatus,
});
} else {
throw error;
}
}
})
}),
);
app.post(
@@ -81,9 +81,9 @@ app.post(
res.send({
status: 'ok',
data
data,
});
})
}),
);
app.post(
@@ -95,18 +95,18 @@ app.post(
if (data.summary === 'Requisition deleted') {
res.send({
status: 'ok',
data
data,
});
} else {
res.send({
status: 'error',
data: {
data,
reason: 'Can not delete requisition'
}
reason: 'Can not delete requisition',
},
});
}
})
}),
);
app.post(
@@ -119,12 +119,12 @@ app.post(
balances,
institutionId,
startingBalance,
transactions: { booked, pending }
transactions: { booked, pending },
} = await nordigenService.getTransactionsWithBalance(
requisitionId,
accountId,
startDate,
endDate
endDate,
);
res.send({
@@ -135,9 +135,9 @@ app.post(
startingBalance,
transactions: {
booked,
pending
}
}
pending,
},
},
});
} catch (error) {
const sendErrorResponse = (data) =>
@@ -149,7 +149,8 @@ app.post(
error_type: 'ITEM_ERROR',
error_code: 'ITEM_LOGIN_REQUIRED',
status: 'expired',
reason: 'Access to account has expired as set in End User Agreement'
reason:
'Access to account has expired as set in End User Agreement',
});
break;
case error instanceof AccountNotLinedToRequisition:
@@ -157,14 +158,14 @@ app.post(
error_type: 'INVALID_INPUT',
error_code: 'INVALID_ACCESS_TOKEN',
status: 'rejected',
reason: 'Account not linked with this requisition'
reason: 'Account not linked with this requisition',
});
break;
case error instanceof GenericNordigenError:
console.log({ message: 'Something went wrong', error });
sendErrorResponse({
error_type: 'SYNC_ERROR',
error_code: 'NORDIGEN_ERROR'
error_code: 'NORDIGEN_ERROR',
});
break;
default:
@@ -172,10 +173,10 @@ app.post(
sendErrorResponse({
error_type: 'UNKNOWN',
error_code: 'UNKNOWN',
reason: 'Something went wrong'
reason: 'Something went wrong',
});
break;
}
}
})
}),
);

View File

@@ -1,6 +1,6 @@
import {
DetailedAccountWithInstitution,
NormalizedAccountDetails
NormalizedAccountDetails,
} from '../nordigen.types.js';
import { Transaction, Balance } from '../nordigen-node.types.js';
@@ -10,7 +10,7 @@ export interface IBank {
* Returns normalized object with required data for the frontend
*/
normalizeAccount: (
account: DetailedAccountWithInstitution
account: DetailedAccountWithInstitution,
) => NormalizedAccountDetails;
/**
@@ -23,6 +23,6 @@ export interface IBank {
*/
calculateStartingBalance: (
sortedTransactions: Transaction[],
balances: Balance[]
balances: Balance[],
) => number;
}

View File

@@ -11,7 +11,7 @@ export default {
mask: account.iban.slice(-4),
name: [account.product, printIban(account)].join(' ').trim(),
official_name: account.product,
type: 'checking'
type: 'checking',
};
},
@@ -28,18 +28,18 @@ export default {
const oldestTransaction =
sortedTransactions[sortedTransactions.length - 1];
const oldestKnownBalance = amountToInteger(
oldestTransaction.balanceAfterTransaction.balanceAmount.amount
oldestTransaction.balanceAfterTransaction.balanceAmount.amount,
);
const oldestTransactionAmount = amountToInteger(
oldestTransaction.transactionAmount.amount
oldestTransaction.transactionAmount.amount,
);
return oldestKnownBalance - oldestTransactionAmount;
} else {
return amountToInteger(
balances.find((balance) => 'interimBooked' === balance.balanceType)
.balanceAmount.amount
.balanceAmount.amount,
);
}
}
},
};

View File

@@ -7,7 +7,7 @@ const SORTED_BALANCE_TYPE_LIST = [
'interimAvailable',
'interimBooked',
'nonInvoiced',
'openingBooked'
'openingBooked',
];
/** @type {import('./bank.interface.js').IBank} */
@@ -16,7 +16,7 @@ export default {
normalizeAccount(account) {
console.log(
'Available account properties for new institution integration',
{ account: JSON.stringify(account) }
{ account: JSON.stringify(account) },
);
return {
@@ -25,13 +25,13 @@ export default {
mask: (account?.iban || '0000').slice(-4),
name: [account.name, printIban(account)].filter(Boolean).join(' '),
official_name: `integration-${account.institution_id}`,
type: 'checking'
type: 'checking',
};
},
sortTransactions(transactions = []) {
console.log(
'Available (first 10) transactions properties for new integration of institution in sortTransactions function',
{ top10Transactions: JSON.stringify(transactions.slice(0, 10)) }
{ top10Transactions: JSON.stringify(transactions.slice(0, 10)) },
);
return sortByBookingDate(transactions);
},
@@ -40,8 +40,10 @@ export default {
'Available (first 10) transactions properties for new integration of institution in calculateStartingBalance function',
{
balances: JSON.stringify(balances),
top10SortedTransactions: JSON.stringify(sortedTransactions.slice(0, 10))
}
top10SortedTransactions: JSON.stringify(
sortedTransactions.slice(0, 10),
),
},
);
const currentBalance = balances
@@ -49,10 +51,10 @@ export default {
.sort(
(a, b) =>
SORTED_BALANCE_TYPE_LIST.indexOf(a.balanceType) -
SORTED_BALANCE_TYPE_LIST.indexOf(b.balanceType)
SORTED_BALANCE_TYPE_LIST.indexOf(b.balanceType),
)[0];
return sortedTransactions.reduce((total, trans) => {
return total - amountToInteger(trans.transactionAmount.amount);
}, amountToInteger(currentBalance?.balanceAmount?.amount || 0));
}
},
};

View File

@@ -11,13 +11,13 @@ export default {
mask: account.iban.slice(-4),
name: [account.displayName, printIban(account)].join(' '),
official_name: account.product,
type: 'checking'
type: 'checking',
};
},
sortTransactions(transactions = []) {
return transactions.sort(
(a, b) => Number(b.transactionId) - Number(a.transactionId)
(a, b) => Number(b.transactionId) - Number(a.transactionId),
);
},
@@ -31,11 +31,11 @@ export default {
*/
calculateStartingBalance(sortedTransactions = [], balances = []) {
const currentBalance = balances.find(
(balance) => 'interimBooked' === balance.balanceType
(balance) => 'interimBooked' === balance.balanceType,
);
return sortedTransactions.reduce((total, trans) => {
return total - amountToInteger(trans.transactionAmount.amount);
}, amountToInteger(currentBalance.balanceAmount.amount));
}
},
};

View File

@@ -11,7 +11,7 @@ export default {
mask: account.iban.slice(-4),
name: [account.name, printIban(account)].join(' '),
official_name: account.product,
type: 'checking'
type: 'checking',
};
},
@@ -34,11 +34,11 @@ export default {
*/
calculateStartingBalance(sortedTransactions = [], balances = []) {
const currentBalance = balances.find(
(balance) => 'interimAvailable' === balance.balanceType
(balance) => 'interimAvailable' === balance.balanceType,
);
return sortedTransactions.reduce((total, trans) => {
return total - amountToInteger(trans.transactionAmount.amount);
}, amountToInteger(currentBalance.balanceAmount.amount));
}
},
};

View File

@@ -13,7 +13,7 @@ describe('IngPlIngbplpw', () => {
bic: 'INGBPLPW',
ownerAddressUnstructured: [
'UL. EXAMPLE STREET 10 M.1',
'00-000 WARSZAWA'
'00-000 WARSZAWA',
],
id: 'd3eccc94-9536-48d3-98be-813f79199ee3',
created: '2022-07-24T20:45:47.929582Z',
@@ -35,9 +35,9 @@ describe('IngPlIngbplpw', () => {
'card_accounts',
'corporate_accounts',
'pending_transactions',
'private_accounts'
]
}
'private_accounts',
],
},
};
it('returns normalized account data returned to Frontend', () => {
@@ -78,47 +78,47 @@ describe('IngPlIngbplpw', () => {
const transactions = [
{
transactionId: 'D202301180000003',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301180000004',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301230000001',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301180000002',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301200000001',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
];
const sortedTransactions = IngPlIngbplpw.sortTransactions(transactions);
expect(sortedTransactions).toEqual([
{
transactionId: 'D202301230000001',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301200000001',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301180000004',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301180000003',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: 'D202301180000002',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
]);
});
@@ -142,40 +142,40 @@ describe('IngPlIngbplpw', () => {
transactionAmount: { amount: '-100.00', currency: 'USD' },
balanceAfterTransaction: {
balanceAmount: { amount: '400.00', currency: 'USD' },
balanceType: 'interimBooked'
}
balanceType: 'interimBooked',
},
},
{
transactionAmount: { amount: '50.00', currency: 'USD' },
balanceAfterTransaction: {
balanceAmount: { amount: '450.00', currency: 'USD' },
balanceType: 'interimBooked'
}
balanceType: 'interimBooked',
},
},
{
transactionAmount: { amount: '-25.00', currency: 'USD' },
balanceAfterTransaction: {
balanceAmount: { amount: '475.00', currency: 'USD' },
balanceType: 'interimBooked'
}
}
balanceType: 'interimBooked',
},
},
];
/** @type {import('../../nordigen-node.types.js').Balance[]} */
const balances = [
{
balanceType: 'interimBooked',
balanceAmount: { amount: '500.00', currency: 'USD' }
balanceAmount: { amount: '500.00', currency: 'USD' },
},
{
balanceType: 'closingBooked',
balanceAmount: { amount: '600.00', currency: 'USD' }
}
balanceAmount: { amount: '600.00', currency: 'USD' },
},
];
const startingBalance = IngPlIngbplpw.calculateStartingBalance(
sortedTransactions,
balances
balances,
);
expect(startingBalance).toEqual(50000);
@@ -188,11 +188,11 @@ describe('IngPlIngbplpw', () => {
const balances = [
{
balanceType: 'interimBooked',
balanceAmount: { amount: '500.00', currency: 'USD' }
}
balanceAmount: { amount: '500.00', currency: 'USD' },
},
];
expect(
IngPlIngbplpw.calculateStartingBalance(transactions, balances)
IngPlIngbplpw.calculateStartingBalance(transactions, balances),
).toEqual(50000);
});
});

View File

@@ -2,7 +2,7 @@ import { jest } from '@jest/globals';
import IntegrationBank from '../integration-bank.js';
import {
mockExtendAccountsAboutInstitutions,
mockInstitution
mockInstitution,
} from '../../services/tests/fixtures.js';
describe('IntegrationBank', () => {
@@ -23,14 +23,14 @@ describe('IntegrationBank', () => {
mask: '4321',
name: 'account-example-one (XXX 4321)',
official_name: 'integration-SANDBOXFINANCE_SFIN0000',
type: 'checking'
type: 'checking',
});
});
it('should return a normalized account object with masked value "0000" when no iban property is provided', () => {
const normalizedAccount = IntegrationBank.normalizeAccount({
...account,
iban: undefined
iban: undefined,
});
expect(normalizedAccount).toEqual({
account_id: account.id,
@@ -38,7 +38,7 @@ describe('IntegrationBank', () => {
mask: '0000',
name: 'account-example-one',
official_name: 'integration-SANDBOXFINANCE_SFIN0000',
type: 'checking'
type: 'checking',
});
});
@@ -47,8 +47,8 @@ describe('IntegrationBank', () => {
expect(consoleSpy).toHaveBeenCalledWith(
'Available account properties for new institution integration',
{
account: JSON.stringify(account)
}
account: JSON.stringify(account),
},
);
});
});
@@ -58,35 +58,35 @@ describe('IntegrationBank', () => {
{
date: '2022-01-01',
bookingDate: '2022-01-01',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
date: '2022-01-03',
bookingDate: '2022-01-03',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
date: '2022-01-02',
bookingDate: '2022-01-02',
transactionAmount: { amount: '100', currency: 'EUR' }
}
transactionAmount: { amount: '100', currency: 'EUR' },
},
];
const sortedTransactions = [
{
date: '2022-01-03',
bookingDate: '2022-01-03',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
date: '2022-01-02',
bookingDate: '2022-01-02',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
date: '2022-01-01',
bookingDate: '2022-01-01',
transactionAmount: { amount: '100', currency: 'EUR' }
}
transactionAmount: { amount: '100', currency: 'EUR' },
},
];
it('should return transactions sorted by bookingDate', () => {
@@ -98,7 +98,7 @@ describe('IntegrationBank', () => {
IntegrationBank.sortTransactions(transactions);
expect(consoleSpy).toHaveBeenCalledWith(
'Available (first 10) transactions properties for new integration of institution in sortTransactions function',
{ top10Transactions: JSON.stringify(sortedTransactions.slice(0, 10)) }
{ top10Transactions: JSON.stringify(sortedTransactions.slice(0, 10)) },
);
});
});
@@ -108,24 +108,24 @@ describe('IntegrationBank', () => {
const transactions = [
{
bookingDate: '2022-01-01',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
bookingDate: '2022-02-01',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
bookingDate: '2022-03-01',
transactionAmount: { amount: '100', currency: 'EUR' }
}
transactionAmount: { amount: '100', currency: 'EUR' },
},
];
/** @type {import('../../nordigen-node.types.js').Balance[]} */
const balances = [
{
balanceAmount: { amount: '1000.00', currency: 'EUR' },
balanceType: 'interimBooked'
}
balanceType: 'interimBooked',
},
];
it('should return 0 when no transactions or balances are provided', () => {
@@ -136,7 +136,7 @@ describe('IntegrationBank', () => {
it('should return 70000 when transactions and balances are provided', () => {
const startingBalance = IntegrationBank.calculateStartingBalance(
transactions,
balances
balances,
);
expect(startingBalance).toEqual(70000);
});
@@ -147,8 +147,8 @@ describe('IntegrationBank', () => {
'Available (first 10) transactions properties for new integration of institution in calculateStartingBalance function',
{
balances: JSON.stringify(balances),
top10SortedTransactions: JSON.stringify(transactions.slice(0, 10))
}
top10SortedTransactions: JSON.stringify(transactions.slice(0, 10)),
},
);
});
});

View File

@@ -13,7 +13,7 @@ describe('MbankRetailBrexplpw', () => {
ownerAddressUnstructured: [
'POL',
'UL. EXAMPLE STREET 10 M.1',
'00-000 WARSZAWA'
'00-000 WARSZAWA',
],
id: 'd3eccc94-9536-48d3-98be-813f79199ee3',
created: '2023-01-18T13:24:55.879512Z',
@@ -35,9 +35,9 @@ describe('MbankRetailBrexplpw', () => {
'card_accounts',
'corporate_accounts',
'pending_transactions',
'private_accounts'
]
}
'private_accounts',
],
},
};
it('returns normalized account data returned to Frontend', () => {
expect(MbankRetailBrexplpw.normalizeAccount(accountRaw))
@@ -77,47 +77,47 @@ describe('MbankRetailBrexplpw', () => {
const sortedTransactions = MbankRetailBrexplpw.sortTransactions([
{
transactionId: '202212300001',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300003',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300002',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300000',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202112300001',
transactionAmount: { amount: '100', currency: 'EUR' }
}
transactionAmount: { amount: '100', currency: 'EUR' },
},
]);
expect(sortedTransactions).toEqual([
{
transactionId: '202212300003',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300002',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300001',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202212300000',
transactionAmount: { amount: '100', currency: 'EUR' }
transactionAmount: { amount: '100', currency: 'EUR' },
},
{
transactionId: '202112300001',
transactionAmount: { amount: '100', currency: 'EUR' }
}
transactionAmount: { amount: '100', currency: 'EUR' },
},
]);
});
@@ -138,30 +138,30 @@ describe('MbankRetailBrexplpw', () => {
const balances = [
{
balanceAmount: { amount: '1000.00', currency: 'PLN' },
balanceType: 'interimBooked'
}
balanceType: 'interimBooked',
},
];
it('returns the same balance amount when no transactions', () => {
const transactions = [];
expect(
MbankRetailBrexplpw.calculateStartingBalance(transactions, balances)
MbankRetailBrexplpw.calculateStartingBalance(transactions, balances),
).toEqual(100000);
});
it('returns the balance minus the available transactions', () => {
const transactions = [
{
transactionAmount: { amount: '200.00', currency: 'PLN' }
transactionAmount: { amount: '200.00', currency: 'PLN' },
},
{
transactionAmount: { amount: '300.50', currency: 'PLN' }
}
transactionAmount: { amount: '300.50', currency: 'PLN' },
},
];
expect(
MbankRetailBrexplpw.calculateStartingBalance(transactions, balances)
MbankRetailBrexplpw.calculateStartingBalance(transactions, balances),
).toEqual(49950);
});
});

View File

@@ -26,8 +26,8 @@ describe('SandboxfinanceSfin0000', () => {
countries: ['XX'],
logo: 'https://cdn.nordigen.com/ais/SANDBOXFINANCE_SFIN0000.png',
supported_payments: {},
supported_features: []
}
supported_features: [],
},
};
it('returns normalized account data returned to Frontend', () => {
@@ -61,48 +61,48 @@ describe('SandboxfinanceSfin0000', () => {
const transactions = [
{
transactionId: '2023012301927902-2',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927902-1',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-2',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-1',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-3',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
];
const sortedTransactions =
SandboxfinanceSfin0000.sortTransactions(transactions);
expect(sortedTransactions).toEqual([
{
transactionId: '2023012301927902-2',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927902-1',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-3',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-2',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
transactionId: '2023012301927900-1',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
]);
});
@@ -125,29 +125,29 @@ describe('SandboxfinanceSfin0000', () => {
const balances = [
{
balanceAmount: { amount: '1000.00', currency: 'PLN' },
balanceType: 'interimAvailable'
}
balanceType: 'interimAvailable',
},
];
it('should calculate the starting balance correctly', () => {
const sortedTransactions = [
{
transactionId: '2022-01-01-1',
transactionAmount: { amount: '-100.00', currency: 'USD' }
transactionAmount: { amount: '-100.00', currency: 'USD' },
},
{
transactionId: '2022-01-01-2',
transactionAmount: { amount: '50.00', currency: 'USD' }
transactionAmount: { amount: '50.00', currency: 'USD' },
},
{
transactionId: '2022-01-01-3',
transactionAmount: { amount: '-25.00', currency: 'USD' }
}
transactionAmount: { amount: '-25.00', currency: 'USD' },
},
];
const startingBalance = SandboxfinanceSfin0000.calculateStartingBalance(
sortedTransactions,
balances
balances,
);
expect(startingBalance).toEqual(107500);
@@ -157,7 +157,7 @@ describe('SandboxfinanceSfin0000', () => {
const transactions = [];
expect(
SandboxfinanceSfin0000.calculateStartingBalance(transactions, balances)
SandboxfinanceSfin0000.calculateStartingBalance(transactions, balances),
).toEqual(100000);
});
@@ -165,15 +165,15 @@ describe('SandboxfinanceSfin0000', () => {
/** @type {import('../../nordigen-node.types.js').Transaction[]} */
const transactions = [
{
transactionAmount: { amount: '200.00', currency: 'PLN' }
transactionAmount: { amount: '200.00', currency: 'PLN' },
},
{
transactionAmount: { amount: '300.50', currency: 'PLN' }
}
transactionAmount: { amount: '300.50', currency: 'PLN' },
},
];
expect(
SandboxfinanceSfin0000.calculateStartingBalance(transactions, balances)
SandboxfinanceSfin0000.calculateStartingBalance(transactions, balances),
).toEqual(49950);
});
});

View File

@@ -10,7 +10,7 @@ export class AccountNotLinedToRequisition extends Error {
super('Provided account id is not linked to given requisition');
this.details = {
accountId,
requisitionId
requisitionId,
};
}
}
@@ -57,7 +57,7 @@ export class ResourceSuspended extends NordigenClientError {
constructor(response) {
super(
'Resource was suspended due to numerous errors that occurred while accessing it',
response
response,
);
}
}
@@ -66,7 +66,7 @@ export class RateLimitError extends NordigenClientError {
constructor(response) {
super(
'Daily request limit set by the Institution has been exceeded',
response
response,
);
}
}

View File

@@ -3,7 +3,7 @@ import {
NordigenAccountDetails,
Institution,
Transactions,
Balance
Balance,
} from './nordigen-node.types.js';
export type DetailedAccount = Omit<NordigenAccountDetails, 'status'> &

View File

@@ -9,7 +9,7 @@ import {
ResourceSuspended,
RateLimitError,
UnknownError,
ServiceError
ServiceError,
} from '../errors.js';
import * as nordigenNode from 'nordigen-node';
import * as uuid from 'uuid';
@@ -18,7 +18,7 @@ import config from '../../load-config.js';
const NordigenClient = nordigenNode.default;
const nordigenClient = new NordigenClient({
secretId: config.nordigen_secret_id,
secretKey: config.nordigen_secret_key
secretKey: config.nordigen_secret_key,
});
export const handleNordigenError = (response) => {
@@ -102,7 +102,7 @@ export const nordigenService = {
*/
getRequisitionWithAccounts: async (requisitionId) => {
const requisition = await nordigenService.getLinkedRequisition(
requisitionId
requisitionId,
);
let institutionIdSet = new Set();
@@ -111,19 +111,19 @@ export const nordigenService = {
const account = await nordigenService.getDetailedAccount(accountId);
institutionIdSet.add(account.institution_id);
return account;
})
}),
);
const institutions = await Promise.all(
Array.from(institutionIdSet).map(async (institutionId) => {
return await nordigenService.getInstitution(institutionId);
})
}),
);
const extendedAccounts =
await nordigenService.extendAccountsAboutInstitutions({
accounts: detailedAccounts,
institutions
institutions,
});
const normalizedAccounts = extendedAccounts.map((account) => {
@@ -156,7 +156,7 @@ export const nordigenService = {
requisitionId,
accountId,
startDate,
endDate
endDate,
) => {
const { institution_id, accounts: accountIds } =
await nordigenService.getLinkedRequisition(requisitionId);
@@ -169,22 +169,22 @@ export const nordigenService = {
nordigenService.getTransactions({
accountId,
startDate,
endDate
endDate,
}),
nordigenService.getBalances(accountId)
nordigenService.getBalances(accountId),
]);
const bank = BankFactory(institution_id);
const sortedBookedTransactions = bank.sortTransactions(
transactions.transactions?.booked
transactions.transactions?.booked,
);
const sortedPendingTransactions = bank.sortTransactions(
transactions.transactions?.pending
transactions.transactions?.pending,
);
const startingBalance = bank.calculateStartingBalance(
sortedBookedTransactions,
accountBalance.balances
accountBalance.balances,
);
return {
@@ -193,8 +193,8 @@ export const nordigenService = {
startingBalance,
transactions: {
booked: sortedBookedTransactions,
pending: sortedPendingTransactions
}
pending: sortedPendingTransactions,
},
};
},
@@ -223,7 +223,7 @@ export const nordigenService = {
userLanguage: 'en',
ssn: null,
redirectImmediate: false,
accountSelection: false
accountSelection: false,
});
handleNordigenError(response);
@@ -232,7 +232,7 @@ export const nordigenService = {
return {
link,
requisitionId
requisitionId,
};
},
@@ -289,7 +289,7 @@ export const nordigenService = {
getDetailedAccount: async (accountId) => {
const [detailedAccount, metadataAccount] = await Promise.all([
client.getDetails(accountId),
client.getMetadata(accountId)
client.getMetadata(accountId),
]);
handleNordigenError(detailedAccount);
@@ -297,7 +297,7 @@ export const nordigenService = {
return {
...detailedAccount.account,
...metadataAccount
...metadataAccount,
};
},
@@ -358,7 +358,7 @@ export const nordigenService = {
const institution = institutionsById[account.institution_id] || null;
return {
...account,
institution
institution,
};
});
},
@@ -380,7 +380,7 @@ export const nordigenService = {
const response = await client.getTransactions({
accountId,
dateFrom: startDate,
dateTo: endDate
dateTo: endDate,
});
handleNordigenError(response);
@@ -407,7 +407,7 @@ export const nordigenService = {
handleNordigenError(response);
return response;
}
},
};
/**
@@ -422,7 +422,7 @@ export const client = {
await nordigenClient.account(accountId).getTransactions({
dateFrom,
dateTo,
country: undefined
country: undefined,
}),
getInstitutions: async (country) =>
await nordigenClient.institution.getInstitutions({ country }),
@@ -445,7 +445,7 @@ export const client = {
userLanguage,
ssn,
redirectImmediate,
accountSelection
accountSelection,
}) =>
await nordigenClient.initSession({
redirectUrl,
@@ -456,7 +456,7 @@ export const client = {
userLanguage,
ssn,
redirectImmediate,
accountSelection
accountSelection,
}),
generateToken: async () => await nordigenClient.generateToken()
generateToken: async () => await nordigenClient.generateToken(),
};

View File

@@ -4,20 +4,20 @@ export const mockedBalances = {
{
balanceAmount: {
amount: '657.49',
currency: 'string'
currency: 'string',
},
balanceType: 'interimAvailable',
referenceDate: '2021-11-22'
referenceDate: '2021-11-22',
},
{
balanceAmount: {
amount: '185.67',
currency: 'string'
currency: 'string',
},
balanceType: 'interimAvailable',
referenceDate: '2021-11-19'
}
]
referenceDate: '2021-11-19',
},
],
};
/** @type {{transactions: import('../../nordigen-node.types.js').Transactions}} */
@@ -28,44 +28,44 @@ export const mockTransactions = {
transactionId: 'string',
debtorName: 'string',
debtorAccount: {
iban: 'string'
iban: 'string',
},
transactionAmount: {
currency: 'EUR',
amount: '328.18'
amount: '328.18',
},
bankTransactionCode: 'string',
bookingDate: 'date',
valueDate: 'date'
valueDate: 'date',
},
{
transactionId: 'string',
transactionAmount: {
currency: 'EUR',
amount: '947.26'
amount: '947.26',
},
bankTransactionCode: 'string',
bookingDate: 'date',
valueDate: 'date'
}
valueDate: 'date',
},
],
pending: [
{
transactionAmount: {
currency: 'EUR',
amount: '947.26'
amount: '947.26',
},
valueDate: 'date'
}
]
}
valueDate: 'date',
},
],
},
};
export const mockUnknownError = {
summary: "Couldn't update account balances",
detail: 'Request to Institution returned an error',
type: 'UnknownRequestError',
status_code: 500
status_code: 500,
};
/** @type {{account: import('../../nordigen-node.types.js').NordigenAccountDetails}} */
@@ -77,8 +77,8 @@ export const mockAccountDetails = {
ownerName: 'JOHN EXAMPLE',
product: 'Savings Account for Individuals (Retail)',
bic: 'INGBPLPW',
ownerAddressUnstructured: ['EXAMPLE STREET 100/001', '00-000 EXAMPLE CITY']
}
ownerAddressUnstructured: ['EXAMPLE STREET 100/001', '00-000 EXAMPLE CITY'],
},
};
/** @type {import('../../nordigen-node.types.js').NordigenAccountMetadata} */
@@ -89,13 +89,13 @@ export const mockAccountMetaData = {
iban: 'PL00000000000000000987654321',
institution_id: 'SANDBOXFINANCE_SFIN0000',
status: 'READY',
owner_name: 'JOHN EXAMPLE'
owner_name: 'JOHN EXAMPLE',
};
/** @type {import('../../nordigen.types.js').DetailedAccount} */
export const mockDetailedAccount = {
...mockAccountDetails.account,
...mockAccountMetaData
...mockAccountMetaData,
};
/** @type {import('../../nordigen-node.types.js').Institution} */
@@ -105,7 +105,7 @@ export const mockInstitution = {
bic: 'NTSBDEB1',
transaction_total_days: '90',
countries: ['GB', 'NO', 'SE'],
logo: 'https://cdn.nordigen.com/ais/N26_SANDBOX_NTSBDEB1.png'
logo: 'https://cdn.nordigen.com/ais/N26_SANDBOX_NTSBDEB1.png',
};
/** @type {import('../../nordigen-node.types.js').Requisition} */
@@ -122,13 +122,13 @@ export const mockRequisition = {
link: 'https://ob.nordigen.com/psd2/start/3fa85f64-5717-4562-b3fc-2c963f66afa6/{$INSTITUTION_ID}',
ssn: 'string',
account_selection: false,
redirect_immediate: false
redirect_immediate: false,
};
export const mockDeleteRequisition = {
summary: 'Requisition deleted',
detail:
"Requisition '$REQUISITION_ID' deleted with all its End User Agreements"
"Requisition '$REQUISITION_ID' deleted with all its End User Agreements",
};
export const mockCreateRequisition = {
@@ -144,37 +144,37 @@ export const mockCreateRequisition = {
link: 'https://ob.nordigen.com/psd2/start/3fa85f64-5717-4562-b3fc-2c963f66afa6/{$INSTITUTION_ID}',
ssn: 'string',
account_selection: false,
redirect_immediate: false
redirect_immediate: false,
};
/** @type {import('../../nordigen.types.js').DetailedAccount} */
export const mockDetailedAccountExample1 = {
...mockDetailedAccount,
name: 'account-example-one'
name: 'account-example-one',
};
/** @type {import('../../nordigen.types.js').DetailedAccount} */
export const mockDetailedAccountExample2 = {
...mockDetailedAccount,
name: 'account-example-two'
name: 'account-example-two',
};
/** @type {import('../../nordigen.types.js').DetailedAccountWithInstitution[]} */
export const mockExtendAccountsAboutInstitutions = [
{
...mockDetailedAccountExample1,
institution: mockInstitution
institution: mockInstitution,
},
{
...mockDetailedAccountExample2,
institution: mockInstitution
}
institution: mockInstitution,
},
];
export const mockRequisitionWithExampleAccounts = {
...mockRequisition,
accounts: [mockDetailedAccountExample1.id, mockDetailedAccountExample2.id]
accounts: [mockDetailedAccountExample1.id, mockDetailedAccountExample2.id],
};
export const mockTransactionAmount = { amount: '100', currency: 'EUR' };

View File

@@ -9,7 +9,7 @@ import {
UnknownError,
ServiceError,
RequisitionNotLinked,
AccountNotLinedToRequisition
AccountNotLinedToRequisition,
} from '../../errors.js';
import {
@@ -26,13 +26,13 @@ import {
mockRequisitionWithExampleAccounts,
mockDetailedAccountExample1,
mockDetailedAccountExample2,
mockExtendAccountsAboutInstitutions
mockExtendAccountsAboutInstitutions,
} from './fixtures.js';
import {
nordigenService,
handleNordigenError,
client
client,
} from '../nordigen-service.js';
describe('nordigenService', () => {
@@ -76,7 +76,7 @@ describe('nordigenService', () => {
.mockResolvedValue(mockRequisition);
expect(await nordigenService.getLinkedRequisition(requisitionId)).toEqual(
mockRequisition
mockRequisition,
);
});
@@ -88,7 +88,7 @@ describe('nordigenService', () => {
.mockResolvedValue({ ...mockRequisition, status: 'ER' });
await expect(() =>
nordigenService.getLinkedRequisition(requisitionId)
nordigenService.getLinkedRequisition(requisitionId),
).rejects.toThrow(RequisitionNotLinked);
});
});
@@ -112,16 +112,16 @@ describe('nordigenService', () => {
.mockResolvedValue([
{
...mockExtendAccountsAboutInstitutions[0],
institution_id: 'NEWONE'
institution_id: 'NEWONE',
},
{
...mockExtendAccountsAboutInstitutions[1],
institution_id: 'NEWONE'
}
institution_id: 'NEWONE',
},
]);
const response = await nordigenService.getRequisitionWithAccounts(
mockRequisitionWithExampleAccounts.id
mockRequisitionWithExampleAccounts.id,
);
expect(response.accounts.length).toEqual(2);
@@ -130,14 +130,14 @@ describe('nordigenService', () => {
expect.objectContaining({
account_id: mockDetailedAccountExample1.id,
institution: mockInstitution,
official_name: expect.stringContaining('integration-') // It comes from IntegrationBank
official_name: expect.stringContaining('integration-'), // It comes from IntegrationBank
}),
expect.objectContaining({
account_id: mockDetailedAccountExample2.id,
institution: mockInstitution,
official_name: expect.stringContaining('integration-') // It comes from IntegrationBank
})
])
official_name: expect.stringContaining('integration-'), // It comes from IntegrationBank
}),
]),
);
expect(response.requisition).toEqual(mockRequisitionWithExampleAccounts);
});
@@ -161,8 +161,8 @@ describe('nordigenService', () => {
requisitionId,
accountId,
undefined,
undefined
)
undefined,
),
).toEqual(
expect.objectContaining({
balances: mockedBalances.balances,
@@ -174,23 +174,23 @@ describe('nordigenService', () => {
bookingDate: expect.any(String),
transactionAmount: {
amount: expect.any(String),
currency: 'EUR'
currency: 'EUR',
},
transactionId: expect.any(String),
valueDate: expect.any(String)
})
valueDate: expect.any(String),
}),
]),
pending: expect.arrayContaining([
expect.objectContaining({
transactionAmount: {
amount: expect.any(String),
currency: 'EUR'
currency: 'EUR',
},
valueDate: expect.any(String)
})
])
}
})
valueDate: expect.any(String),
}),
]),
},
}),
);
});
@@ -204,8 +204,8 @@ describe('nordigenService', () => {
requisitionId,
accountId: 'some-unknown-account-id',
startDate: undefined,
endDate: undefined
})
endDate: undefined,
}),
).rejects.toThrow(AccountNotLinedToRequisition);
});
});
@@ -215,7 +215,7 @@ describe('nordigenService', () => {
const params = {
host: 'https://exemple.com',
institutionId,
accessValidForDays: 90
accessValidForDays: 90,
};
it('calls nordigenClient and delete requisition', async () => {
@@ -225,7 +225,7 @@ describe('nordigenService', () => {
expect(await nordigenService.createRequisition(params)).toEqual({
link: expect.any(String),
requisitionId: expect.any(String)
requisitionId: expect.any(String),
});
expect(createRequisitionSpy).toBeCalledTimes(1);
@@ -237,7 +237,7 @@ describe('nordigenService', () => {
createRequisitionSpy.mockResolvedValue(mockUnknownError);
await expect(() =>
nordigenService.createRequisition(params)
nordigenService.createRequisition(params),
).rejects.toThrow(UnknownError);
});
});
@@ -252,7 +252,7 @@ describe('nordigenService', () => {
deleteRequisitionsSpy.mockResolvedValue(mockDeleteRequisition);
expect(await nordigenService.deleteRequisition(requisitionId)).toEqual(
mockDeleteRequisition
mockDeleteRequisition,
);
expect(getRequisitionsSpy).toBeCalledTimes(1);
@@ -266,7 +266,7 @@ describe('nordigenService', () => {
deleteRequisitionsSpy.mockReturnValue(mockUnknownError);
await expect(() =>
nordigenService.deleteRequisition(requisitionId)
nordigenService.deleteRequisition(requisitionId),
).rejects.toThrow(UnknownError);
});
});
@@ -279,7 +279,7 @@ describe('nordigenService', () => {
getRequisitionsSpy.mockResolvedValue(mockRequisition);
expect(await nordigenService.getRequisition(requisitionId)).toEqual(
mockRequisition
mockRequisition,
);
expect(setTokenSpy).toBeCalledTimes(1);
@@ -292,7 +292,7 @@ describe('nordigenService', () => {
getRequisitionsSpy.mockReturnValue(mockUnknownError);
await expect(() =>
nordigenService.getRequisition(requisitionId)
nordigenService.getRequisition(requisitionId),
).rejects.toThrow(UnknownError);
});
});
@@ -304,7 +304,7 @@ describe('nordigenService', () => {
expect(await nordigenService.getDetailedAccount(accountId)).toEqual({
...mockAccountMetaData,
...mockAccountDetails.account
...mockAccountDetails.account,
});
expect(getDetailsSpy).toBeCalledTimes(1);
expect(getMetadataSpy).toBeCalledTimes(1);
@@ -315,7 +315,7 @@ describe('nordigenService', () => {
getMetadataSpy.mockResolvedValue(mockAccountMetaData);
await expect(() =>
nordigenService.getDetailedAccount(accountId)
nordigenService.getDetailedAccount(accountId),
).rejects.toThrow(UnknownError);
expect(getDetailsSpy).toBeCalledTimes(1);
@@ -327,7 +327,7 @@ describe('nordigenService', () => {
getMetadataSpy.mockResolvedValue(mockUnknownError);
await expect(() =>
nordigenService.getDetailedAccount(accountId)
nordigenService.getDetailedAccount(accountId),
).rejects.toThrow(UnknownError);
expect(getDetailsSpy).toBeCalledTimes(1);
@@ -341,7 +341,7 @@ describe('nordigenService', () => {
getInstitutionsSpy.mockResolvedValue([mockInstitution]);
expect(await nordigenService.getInstitutions({ country })).toEqual([
mockInstitution
mockInstitution,
]);
expect(getInstitutionsSpy).toBeCalledTimes(1);
});
@@ -350,7 +350,7 @@ describe('nordigenService', () => {
getInstitutionsSpy.mockResolvedValue(mockUnknownError);
await expect(() =>
nordigenService.getInstitutions({ country })
nordigenService.getInstitutions({ country }),
).rejects.toThrow(UnknownError);
});
});
@@ -361,7 +361,7 @@ describe('nordigenService', () => {
getInstitutionSpy.mockResolvedValue(mockInstitution);
expect(await nordigenService.getInstitution(institutionId)).toEqual(
mockInstitution
mockInstitution,
);
expect(getInstitutionSpy).toBeCalledTimes(1);
});
@@ -370,7 +370,7 @@ describe('nordigenService', () => {
getInstitutionSpy.mockResolvedValue(mockUnknownError);
await expect(() =>
nordigenService.getInstitution(institutionId)
nordigenService.getInstitution(institutionId),
).rejects.toThrow(UnknownError);
});
});
@@ -382,12 +382,12 @@ describe('nordigenService', () => {
const accountAA = {
...mockDetailedAccount,
id: 'AA',
institution_id: 'INSTITUTION_A'
institution_id: 'INSTITUTION_A',
};
const accountBB = {
...mockDetailedAccount,
id: 'BB',
institution_id: 'INSTITUTION_B'
institution_id: 'INSTITUTION_B',
};
const accounts = [accountAA, accountBB];
@@ -396,17 +396,17 @@ describe('nordigenService', () => {
const expected = [
{
...accountAA,
institution: institutionA
institution: institutionA,
},
{
...accountBB,
institution: institutionB
}
institution: institutionB,
},
];
const result = await nordigenService.extendAccountsAboutInstitutions({
accounts,
institutions
institutions,
});
expect(result).toEqual(expected);
@@ -416,12 +416,12 @@ describe('nordigenService', () => {
const accountAA = {
...mockDetailedAccount,
id: 'AA',
institution_id: 'INSTITUTION_A'
institution_id: 'INSTITUTION_A',
};
const accountBB = {
...mockDetailedAccount,
id: 'BB',
institution_id: 'INSTITUTION_B'
institution_id: 'INSTITUTION_B',
};
const accounts = [accountAA, accountBB];
@@ -432,17 +432,17 @@ describe('nordigenService', () => {
const expected = [
{
...accountAA,
institution: institutionA
institution: institutionA,
},
{
...accountBB,
institution: null
}
institution: null,
},
];
const result = await nordigenService.extendAccountsAboutInstitutions({
accounts,
institutions
institutions,
});
expect(result).toEqual(expected);
@@ -457,8 +457,8 @@ describe('nordigenService', () => {
await nordigenService.getTransactions({
accountId,
startDate: '',
endDate: ''
})
endDate: '',
}),
).toMatchInlineSnapshot(`
{
"transactions": {
@@ -510,8 +510,8 @@ describe('nordigenService', () => {
nordigenService.getTransactions({
accountId,
startDate: '',
endDate: ''
})
endDate: '',
}),
).rejects.toThrow(UnknownError);
});
});
@@ -521,7 +521,7 @@ describe('nordigenService', () => {
getBalancesSpy.mockResolvedValue(mockedBalances);
expect(await nordigenService.getBalances(accountId)).toEqual(
mockedBalances
mockedBalances,
);
expect(getBalancesSpy).toBeCalledTimes(1);
});
@@ -530,7 +530,7 @@ describe('nordigenService', () => {
getBalancesSpy.mockResolvedValue(mockUnknownError);
await expect(() =>
nordigenService.getBalances(accountId)
nordigenService.getBalances(accountId),
).rejects.toThrow(UnknownError);
});
});
@@ -545,7 +545,7 @@ describe('#handleNordigenError', () => {
it('throws InvalidNordigenTokenError for status code 401', () => {
const response = { status_code: 401 };
expect(() => handleNordigenError(response)).toThrow(
InvalidNordigenTokenError
InvalidNordigenTokenError,
);
});

View File

@@ -7,30 +7,30 @@ describe('utils', () => {
const transactions = [
{
bookingDate: '2023-01-01',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
bookingDate: '2023-01-20',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
bookingDate: '2023-01-10',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
];
expect(sortByBookingDate(transactions)).toEqual([
{
bookingDate: '2023-01-20',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
bookingDate: '2023-01-10',
transactionAmount: mockTransactionAmount
transactionAmount: mockTransactionAmount,
},
{
bookingDate: '2023-01-01',
transactionAmount: mockTransactionAmount
}
transactionAmount: mockTransactionAmount,
},
]);
});
});

View File

@@ -8,7 +8,7 @@ export const printIban = (account) => {
export const sortByBookingDate = (transactions = []) =>
transactions.sort(
(a, b) => +new Date(b.bookingDate) - +new Date(a.bookingDate)
(a, b) => +new Date(b.bookingDate) - +new Date(a.bookingDate),
);
export const amountToInteger = (n) => Math.round(n * 100);

View File

@@ -53,7 +53,7 @@ app.post('/sync', async (req, res) => {
let currentFiles = accountDb.all(
'SELECT group_id, encrypt_keyid, encrypt_meta, sync_version FROM files WHERE id = ?',
[file_id]
[file_id],
);
if (currentFiles.length === 0) {
@@ -135,7 +135,7 @@ app.post('/user-get-key', (req, res) => {
let rows = accountDb.all(
'SELECT encrypt_salt, encrypt_keyid, encrypt_test FROM files WHERE id = ?',
[fileId]
[fileId],
);
if (rows.length === 0) {
res.status(400).send('file-not-found');
@@ -146,8 +146,8 @@ app.post('/user-get-key', (req, res) => {
res.send(
JSON.stringify({
status: 'ok',
data: { id: encrypt_keyid, salt: encrypt_salt, test: encrypt_test }
})
data: { id: encrypt_keyid, salt: encrypt_salt, test: encrypt_test },
}),
);
});
@@ -161,7 +161,7 @@ app.post('/user-create-key', (req, res) => {
accountDb.mutate(
'UPDATE files SET encrypt_salt = ?, encrypt_keyid = ?, encrypt_test = ? WHERE id = ?',
[keySalt, keyId, testContent, fileId]
[keySalt, keyId, testContent, fileId],
);
res.send(JSON.stringify({ status: 'ok' }));
@@ -176,7 +176,7 @@ app.post('/reset-user-file', async (req, res) => {
let { fileId } = req.body;
let files = accountDb.all('SELECT group_id FROM files WHERE id = ?', [
fileId
fileId,
]);
if (files.length === 0) {
res.status(400).send('User or file not found');
@@ -225,7 +225,7 @@ app.post('/upload-user-file', async (req, res) => {
let currentFiles = accountDb.all(
'SELECT group_id, encrypt_keyid, encrypt_meta FROM files WHERE id = ?',
[fileId]
[fileId],
);
if (currentFiles.length) {
let currentFile = currentFiles[0];
@@ -268,7 +268,7 @@ app.post('/upload-user-file', async (req, res) => {
groupId = uuid.v4();
accountDb.mutate(
'INSERT INTO files (id, group_id, sync_version, name, encrypt_meta) VALUES (?, ?, ?, ?, ?)',
[fileId, groupId, syncFormatVersion, name, encryptMeta]
[fileId, groupId, syncFormatVersion, name, encryptMeta],
);
res.send(JSON.stringify({ status: 'ok', groupId }));
} else {
@@ -277,14 +277,14 @@ app.post('/upload-user-file', async (req, res) => {
groupId = uuid.v4();
accountDb.mutate('UPDATE files SET group_id = ? WHERE id = ?', [
groupId,
fileId
fileId,
]);
}
// Regardless, update some properties
accountDb.mutate(
'UPDATE files SET sync_version = ?, encrypt_meta = ?, name = ? WHERE id = ?',
[syncFormatVersion, encryptMeta, name, fileId]
[syncFormatVersion, encryptMeta, name, fileId],
);
res.send(JSON.stringify({ status: 'ok', groupId }));
@@ -306,7 +306,7 @@ app.get('/download-user-file', async (req, res) => {
// Do some authentication
let rows = accountDb.all(
'SELECT id FROM files WHERE id = ? AND deleted = FALSE',
[fileId]
[fileId],
);
if (rows.length === 0) {
res.status(400).send('User or file not found');
@@ -337,7 +337,7 @@ app.post('/update-user-filename', (req, res) => {
// Do some authentication
let rows = accountDb.all(
'SELECT id FROM files WHERE id = ? AND deleted = FALSE',
[fileId]
[fileId],
);
if (rows.length === 0) {
res.status(500).send('User or file not found');
@@ -366,9 +366,9 @@ app.get('/list-user-files', (req, res) => {
fileId: row.id,
groupId: row.group_id,
name: row.name,
encryptKeyId: row.encrypt_keyid
}))
})
encryptKeyId: row.encrypt_keyid,
})),
}),
);
});
@@ -382,7 +382,7 @@ app.get('/get-user-file-info', (req, res) => {
let rows = accountDb.all(
'SELECT * FROM files WHERE id = ? AND deleted = FALSE',
[fileId]
[fileId],
);
if (rows.length === 0) {
res.send(JSON.stringify({ status: 'error' }));
@@ -398,9 +398,9 @@ app.get('/get-user-file-info', (req, res) => {
fileId: row.id,
groupId: row.group_id,
name: row.name,
encryptMeta: row.encrypt_meta ? JSON.parse(row.encrypt_meta) : null
}
})
encryptMeta: row.encrypt_meta ? JSON.parse(row.encrypt_meta) : null,
},
}),
);
});

View File

@@ -13,7 +13,7 @@ describe('/download-user-file', () => {
expect(res.body).toEqual({
details: 'token-not-found',
reason: 'unauthorized',
status: 'error'
status: 'error',
});
});
@@ -26,7 +26,7 @@ describe('/download-user-file', () => {
expect(res.body).toEqual({
details: 'token-not-found',
reason: 'unauthorized',
status: 'error'
status: 'error',
});
});
@@ -42,7 +42,7 @@ describe('/download-user-file', () => {
it('returns 500 error if the file does not exist on the filesystem', async () => {
getAccountDb().mutate(
'INSERT INTO files (id, deleted) VALUES (?, FALSE)',
['missing-fs-file']
['missing-fs-file'],
);
const res = await request(app)
@@ -57,7 +57,7 @@ describe('/download-user-file', () => {
fs.writeFileSync(getPathForUserFile('file-id'), 'content');
getAccountDb().mutate(
'INSERT INTO files (id, deleted) VALUES (?, FALSE)',
['file-id']
['file-id'],
);
const res = await request(app)
@@ -69,8 +69,8 @@ describe('/download-user-file', () => {
expect(res.headers).toEqual(
expect.objectContaining({
'content-disposition': 'attachment;filename=file-id',
'content-type': 'application/octet-stream'
})
'content-type': 'application/octet-stream',
}),
);
});
});

View File

@@ -64,7 +64,7 @@ export default async function run() {
const httpsOptions = {
...config.https,
key: parseHTTPSConfig(config.https.key),
cert: parseHTTPSConfig(config.https.cert)
cert: parseHTTPSConfig(config.https.cert),
};
https.createServer(httpsOptions, app).listen(config.port, config.hostname);
} else {

View File

@@ -25,7 +25,13 @@ if (process.env.ACTUAL_CONFIG_PATH) {
let defaultConfig = {
port: 5006,
hostname: '::',
webRoot: path.join(projectRoot, 'node_modules', '@actual-app', 'web', 'build')
webRoot: path.join(
projectRoot,
'node_modules',
'@actual-app',
'web',
'build',
),
};
/** @type {import('./config-types.js').Config} */
@@ -35,7 +41,7 @@ if (process.env.NODE_ENV === 'test') {
mode: 'test',
serverFiles: path.join(projectRoot, 'test-server-files'),
userFiles: path.join(projectRoot, 'test-user-files'),
...defaultConfig
...defaultConfig,
};
} else {
config = {
@@ -43,7 +49,7 @@ if (process.env.NODE_ENV === 'test') {
...defaultConfig,
serverFiles: path.join(defaultDataDir, 'server-files'),
userFiles: path.join(defaultDataDir, 'user-files'),
...(userConfig || {})
...(userConfig || {}),
};
}
@@ -59,7 +65,7 @@ export default {
? {
key: process.env.ACTUAL_HTTPS_KEY.replace(/\\n/g, '\n'),
cert: process.env.ACTUAL_HTTPS_CERT.replace(/\\n/g, '\n'),
...(config.https || {})
...(config.https || {}),
}
: config.https
: config.https,
};

View File

@@ -37,8 +37,8 @@ function addMessages(db, messages) {
[
msg.getTimestamp(),
msg.getIsencrypted() ? 1 : 0,
Buffer.from(msg.getContent())
]
Buffer.from(msg.getContent()),
],
);
if (info.changes > 0) {
@@ -51,7 +51,7 @@ function addMessages(db, messages) {
db.mutate(
'INSERT INTO messages_merkles (id, merkle) VALUES (1, ?) ON CONFLICT (id) DO UPDATE SET merkle = ?',
[JSON.stringify(trie), JSON.stringify(trie)]
[JSON.stringify(trie), JSON.stringify(trie)],
);
returnValue = trie;
@@ -78,7 +78,7 @@ export function sync(messages, since, groupId) {
`SELECT * FROM messages_binary
WHERE timestamp > ?
ORDER BY timestamp`,
[since]
[since],
);
let trie = addMessages(db, messages);
@@ -93,6 +93,6 @@ export function sync(messages, since, groupId) {
envelopePb.setIsencrypted(msg.is_encrypted);
envelopePb.setContent(msg.content);
return envelopePb;
})
}),
};
}

View File

@@ -19,7 +19,7 @@ export default function validateUser(req, res) {
res.send({
status: 'error',
reason: 'unauthorized',
details: 'token-not-found'
details: 'token-not-found',
});
return null;
}