import * as d from 'date-fns'; import { amountToInteger } from '../../shared/util'; import * as db from '../db'; import * as prefs from '../prefs'; import { parseFile } from './parse-file'; import { reconcileTransactions } from './sync'; beforeEach(global.emptyDatabase()); // libofx spits out errors that contain the entire // source code of the file in the stack which makes // it hard to test. let old = console.warn; beforeAll(() => { console.warn = () => {}; }); afterAll(() => { console.warn = old; }); async function getTransactions(accountId) { return db.runQuery( 'SELECT * FROM transactions WHERE acct = ?', [accountId], true, ); } async function importFileWithRealTime( accountId, filepath, dateFormat?: string, ) { // Emscripten requires a real Date.now! global.restoreDateNow(); let { errors, transactions } = await parseFile(filepath, { enableExperimentalOfxParser: true, }); global.restoreFakeDateNow(); if (transactions) { // eslint-disable-next-line @typescript-eslint/no-explicit-any transactions = (transactions as any[]).map(trans => ({ ...trans, amount: amountToInteger(trans.amount), date: dateFormat ? d.format(d.parse(trans.date, dateFormat, new Date()), 'yyyy-MM-dd') : trans.date, })); } if (errors.length > 0) { return { errors, added: [] }; } let { added } = await reconcileTransactions(accountId, transactions); return { errors, added }; } describe('File import', () => { test('qif import works', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let { errors } = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/data.qif', 'MM/dd/yy', ); expect(errors.length).toBe(0); expect(await getTransactions('one')).toMatchSnapshot(); }); test('ofx import works', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let { errors } = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/data.ofx', ); expect(errors.length).toBe(0); expect(await getTransactions('one')).toMatchSnapshot(); }, 45000); test('ofx import works (credit card)', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let { errors } = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/credit-card.ofx', ); expect(errors.length).toBe(0); expect(await getTransactions('one')).toMatchSnapshot(); }, 45000); test('qfx import works', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let { errors } = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/data.qfx', ); expect(errors.length).toBe(0); expect(await getTransactions('one')).toMatchSnapshot(); }, 45000); test('matches extensions correctly (case-insensitive, etc)', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let res = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/best.data-ever$.QFX', ); expect(res.errors.length).toBe(0); res = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/big.data.QiF', 'MM/dd/yy', ); expect(res.errors.length).toBe(0); res = await importFileWithRealTime('one', 'foo.txt'); expect(res.errors.length).toBe(1); expect(res.errors[0].message).toBe('Invalid file type'); }, 45000); test('handles non-ASCII characters', async () => { prefs.loadPrefs(); await db.insertAccount({ id: 'one', name: 'one' }); let { errors } = await importFileWithRealTime( 'one', __dirname + '/../../mocks/files/8859-1.qfx', 'yyyy-MM-dd', ); expect(errors.length).toBe(0); expect(await getTransactions('one')).toMatchSnapshot(); }); });