import 'package:flutter_test/flutter_test.dart'; import 'package:myapp/models/bank.dart'; import 'package:myapp/services/ing_csv_import.dart'; void main() { test('parses ING Dutch semicolon CSV with Af/Bij and YYYYMMDD', () { const raw = ''' "Datum";"Naam / Omschrijving";"Rekening";"Tegenrekening";"Code";"Af Bij";"Bedrag (EUR)";"Mutatiesoort";"Mededelingen" "20260901";"AH CAMPUS DIEMEN";"NL00INGB0000000000";"";"GT";"Af";"12,50";"Betaalautomaat";"Pasvolgnr: 001" "20260902";"SALARIS";"NL00INGB0000000000";"NL00ABCD";"OV";"Bij";"2000,00";"Overboeking";"Salaris september" '''; final txs = parseIngCsv(raw); expect(txs, hasLength(2)); expect(txs[0].date, '2026-09-01'); expect(txs[0].amount, -12.5); expect(txs[0].description, contains('AH CAMPUS')); expect(txs[1].date, '2026-09-02'); expect(txs[1].amount, 2000); }); test('skips duplicates against existing API-like rows', () { final existing = [ const BankTransaction( date: '2026-09-01', description: 'BCK*AH CAMPUS DIEMEN ZUID NLD Pasvolgnr: 001 Transactie: C00338', amount: -12.5, currency: 'EUR', pending: false, ), ]; const raw = ''' Datum,Naam / Omschrijving,Rekening,Tegenrekening,Code,Af Bij,Bedrag (EUR),Mutatiesoort,Mededelingen 20260901,AH CAMPUS DIEMEN,,,,Af,"12,50",Betaalautomaat,Pasvolgnr: 001 20260903,JUMBO,,,,Af,"8,00",Betaalautomaat, '''; final result = importIngCsvAgainst(raw: raw, existing: existing); expect(result.parsed, 2); expect(result.skippedDuplicates, 1); expect(result.added, hasLength(1)); expect(result.added.single.description, contains('JUMBO')); }); test('isSameTransaction matches merchant fingerprints', () { const api = BankTransaction( date: '2026-09-01', description: 'BCK*AH CAMPUS DIEMEN ZUID NLD Pasvolgnr: 001 Transactie: X', amount: -3.5, currency: 'EUR', pending: false, ); const csv = BankTransaction( date: '2026-09-01', description: 'AH CAMPUS DIEMEN ยท Pasvolgnr: 001', amount: -3.5, currency: 'EUR', pending: false, ); expect(isSameTransaction(api, csv), isTrue); }); test('API merge drops stale pending not returned by the bank', () { const stalePending = BankTransaction( date: '2026-09-01', description: 'AH CAMPUS DIEMEN', amount: -12.5, currency: 'EUR', pending: true, ); const settled = BankTransaction( date: '2026-09-03', description: 'BCK*AH CAMPUS DIEMEN ZUID NLD', amount: -12.5, currency: 'EUR', pending: false, ); const olderBooked = BankTransaction( date: '2026-08-01', description: 'SALARIS', amount: 2000, currency: 'EUR', pending: false, ); final merged = mergeApiTransactionsWithCache( [settled], [stalePending, olderBooked], ); expect(merged, hasLength(2)); expect(merged.any((tx) => tx.pending), isFalse); expect(merged.any((tx) => tx.description.contains('SALARIS')), isTrue); expect(merged.any((tx) => tx.description.contains('AH CAMPUS')), isTrue); }); test('API merge keeps live pending from the feed', () { const livePending = BankTransaction( date: '2026-09-10', description: 'PENDING COFFEE', amount: -4.0, currency: 'EUR', pending: true, ); final merged = mergeApiTransactionsWithCache([livePending], const []); expect(merged, hasLength(1)); expect(merged.single.pending, isTrue); }); test('dropSettledPendingDuplicates removes pending twin of booked', () { const pending = BankTransaction( date: '2026-09-01', description: 'AH CAMPUS DIEMEN', amount: -12.5, currency: 'EUR', pending: true, ); const booked = BankTransaction( date: '2026-09-02', description: 'BCK*AH CAMPUS DIEMEN ZUID', amount: -12.5, currency: 'EUR', pending: false, ); final cleaned = dropSettledPendingDuplicates([pending, booked]); expect(cleaned, hasLength(1)); expect(cleaned.single.pending, isFalse); }); }