← back to AbramsOS
tests/csv-parser.test.js
86 lines
const test = require('node:test');
const assert = require('node:assert');
const { parseStatement, parseAmount, parseDate } = require('../lib/csv-parser');
test('parses standard amex-style export', () => {
const csv = `Date,Description,Amount
01/15/2026,"AMAZON.COM, INC",24.99
01/16/2026,WHOLE FOODS,87.42
01/17/2026,STARBUCKS,5.50`;
const r = parseStatement(csv);
assert.strictEqual(r.rows.length, 3);
assert.strictEqual(r.rows[0].merchant, 'AMAZON.COM, INC');
assert.strictEqual(r.rows[0].amount, 24.99);
assert.strictEqual(r.rows[1].merchant, 'WHOLE FOODS');
assert.strictEqual(r.skipped, 0);
});
test('parses chase-style with extra columns', () => {
const csv = `Transaction Date,Post Date,Description,Category,Type,Amount,Memo
12/01/2025,12/02/2025,APPLE.COM/BILL,Shopping,Sale,9.99,
12/05/2025,12/06/2025,SHELL OIL,Gas,Sale,42.00,`;
const r = parseStatement(csv);
assert.strictEqual(r.rows.length, 2);
assert.strictEqual(r.rows[0].merchant, 'APPLE.COM/BILL');
});
test('skips refund rows (negative amounts)', () => {
const csv = `Date,Description,Amount
01/01/2026,RETURN BEST BUY,-50.00
01/02/2026,COFFEE SHOP,4.50`;
const r = parseStatement(csv);
assert.strictEqual(r.rows.length, 1);
assert.strictEqual(r.rows[0].merchant, 'COFFEE SHOP');
assert.strictEqual(r.skipped, 1);
});
test('handles dollar signs and commas in amounts', () => {
const csv = `Date,Description,Amount
01/01/2026,FANCY HOTEL,"$1,234.56"`;
const r = parseStatement(csv);
assert.strictEqual(r.rows[0].amount, 1234.56);
});
test('handles parentheses for negatives (rejected as refund)', () => {
const csv = `Date,Description,Amount
01/01/2026,REFUND,(45.00)`;
const r = parseStatement(csv);
assert.strictEqual(r.rows.length, 0);
assert.strictEqual(r.skipped, 1);
});
test('rejects when required columns missing', () => {
const csv = `Foo,Bar
1,2`;
const r = parseStatement(csv);
assert.strictEqual(r.rows.length, 0);
assert.match(r.errors[0], /missing required columns/);
});
test('rejects empty input cleanly', () => {
const r = parseStatement('');
assert.strictEqual(r.rows.length, 0);
assert.ok(r.errors.length >= 1);
});
test('parseAmount edge cases', () => {
assert.strictEqual(parseAmount('$1,234.56'), 1234.56);
assert.strictEqual(parseAmount('(99.00)'), -99);
assert.strictEqual(parseAmount(''), null);
assert.strictEqual(parseAmount('not-a-number'), null);
});
test('parseDate handles common US + ISO formats', () => {
assert.ok(parseDate('2026-01-15') instanceof Date);
assert.ok(parseDate('01/15/2026') instanceof Date);
assert.ok(parseDate('1/15/26') instanceof Date);
assert.strictEqual(parseDate(''), null);
});
test('quoted fields with embedded commas', () => {
const csv = `Date,Description,Amount
01/01/2026,"Smith, John & Associates",100.00`;
const r = parseStatement(csv);
assert.strictEqual(r.rows[0].merchant, 'Smith, John & Associates');
});