import * as fs from 'fs/promises'; import * as path from 'path'; import * as api from './index'; const budgetName = 'test-budget'; beforeEach(async () => { // we need real datetime if we are going to mix new timestamps with our mock data global.restoreDateNow(); const budgetPath = path.join(__dirname, '/mocks/budgets/', budgetName); await fs.rm(budgetPath, { force: true, recursive: true }); await createTestBudget('default-budget-template', budgetName); await api.init({ dataDir: path.join(__dirname, '/mocks/budgets/'), }); }); afterEach(async () => { global.currentMonth = null; await api.shutdown(); }); async function createTestBudget(templateName: string, name: string) { const templatePath = path.join( __dirname, '/../loot-core/src/mocks/files', templateName, ); const budgetPath = path.join(__dirname, '/mocks/budgets/', name); await fs.mkdir(budgetPath); await fs.copyFile( path.join(templatePath, 'metadata.json'), path.join(budgetPath, 'metadata.json'), ); await fs.copyFile( path.join(templatePath, 'db.sqlite'), path.join(budgetPath, 'db.sqlite'), ); } describe('API setup and teardown', () => { // apis: loadBudget, getBudgetMonths test('successfully loads budget', async () => { await expect(api.loadBudget(budgetName)).resolves.toBeUndefined(); await expect(api.getBudgetMonths()).resolves.toMatchSnapshot(); }); }); describe('API CRUD operations', () => { beforeEach(async () => { // load test budget await api.loadBudget(budgetName); }); // apis: setBudgetAmount, setBudgetCarryover, getBudgetMonth test('Budgets: successfully update budgets', async () => { const month = '2023-10'; global.currentMonth = month; // create some new categories to test with const groupId = await api.createCategoryGroup({ name: 'tests', }); const categoryId = await api.createCategory({ name: 'test-budget', group_id: groupId, }); await api.setBudgetAmount(month, categoryId, 100); await api.setBudgetCarryover(month, categoryId, true); const budgetMonth = await api.getBudgetMonth(month); expect(budgetMonth.categoryGroups).toEqual( expect.arrayContaining([ expect.objectContaining({ id: groupId, categories: expect.arrayContaining([ expect.objectContaining({ id: categoryId, budgeted: 100, carryover: true, }), ]), }), ]), ); }); //apis: createAccount, getAccounts, updateAccount, closeAccount, deleteAccount, reopenAccount test('Accounts: successfully complete account operators', async () => { const accountId1 = await api.createAccount( { name: 'test-account1', offbudget: true }, 1000, ); const accountId2 = await api.createAccount({ name: 'test-account2' }, 0); let accounts = await api.getAccounts(); // accounts successfully created expect(accounts).toEqual( expect.arrayContaining([ expect.objectContaining({ id: accountId1, name: 'test-account1', offbudget: true, }), expect.objectContaining({ id: accountId2, name: 'test-account2' }), ]), ); await api.updateAccount(accountId1, { offbudget: false }); await api.closeAccount(accountId1, accountId2, null); await api.deleteAccount(accountId2); // accounts successfully updated, and one of them deleted accounts = await api.getAccounts(); expect(accounts).toEqual( expect.arrayContaining([ expect.objectContaining({ id: accountId1, name: 'test-account1', closed: true, offbudget: false, }), expect.not.objectContaining({ id: accountId2 }), ]), ); await api.reopenAccount(accountId1); // the non-deleted account is reopened accounts = await api.getAccounts(); expect(accounts).toEqual( expect.arrayContaining([ expect.objectContaining({ id: accountId1, name: 'test-account1', closed: false, }), ]), ); }); });