import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as plugins from '../ts/bunq.plugins.js'; import * as bunq from '../ts/index.js'; let testBunqAccount: bunq.BunqAccount; let sandboxApiKey: string; let primaryAccount: bunq.BunqMonetaryAccount; tap.test('should setup statement test environment', async () => { // Create sandbox user const tempAccount = new bunq.BunqAccount({ apiKey: '', deviceName: 'bunq-statement-test', environment: 'SANDBOX', }); sandboxApiKey = await tempAccount.createSandboxUser(); // Initialize bunq account testBunqAccount = new bunq.BunqAccount({ apiKey: sandboxApiKey, deviceName: 'bunq-statement-test', environment: 'SANDBOX', }); await testBunqAccount.init(); // Get primary account const { accounts } = await testBunqAccount.getAccounts(); primaryAccount = accounts[0]; console.log('Statement test environment setup complete'); console.log(`Using account: ${primaryAccount.description}`); }); tap.test('should create export builder with specific date range', async () => { const fromDate = new Date('2024-01-01'); const toDate = new Date('2024-01-31'); const exportBuilder = primaryAccount.getAccountStatement({ from: fromDate, to: toDate, includeTransactionAttachments: true }); expect(exportBuilder).toBeInstanceOf(bunq.ExportBuilder); // The export builder should be properly configured const privateOptions = (exportBuilder as any).options; expect(privateOptions.dateStart).toEqual('01-01-2024'); expect(privateOptions.dateEnd).toEqual('31-01-2024'); expect(privateOptions.includeAttachment).toBeTrue(); }); tap.test('should create export builder with monthly index from 0', async () => { // Test with 0-indexed month (0 = current month, 1 = last month, etc.) const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom0: 2, // Two months ago includeTransactionAttachments: false }); expect(exportBuilder).toBeInstanceOf(bunq.ExportBuilder); // The export builder should have dates for two months ago const privateOptions = (exportBuilder as any).options; const now = new Date(); const twoMonthsAgo = new Date(now.getFullYear(), now.getMonth() - 2, 1); const expectedStart = `01-${String(twoMonthsAgo.getMonth() + 1).padStart(2, '0')}-${twoMonthsAgo.getFullYear()}`; expect(privateOptions.dateStart).toEqual(expectedStart); expect(privateOptions.includeAttachment).toBeFalse(); }); tap.test('should create export builder with monthly index from 1', async () => { // Test with 1-indexed month (1 = last month, 2 = two months ago, etc.) const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom1: 1, // Last month includeTransactionAttachments: true }); expect(exportBuilder).toBeInstanceOf(bunq.ExportBuilder); // The export builder should have dates for last month const privateOptions = (exportBuilder as any).options; const now = new Date(); const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1); const expectedStart = `01-${String(lastMonth.getMonth() + 1).padStart(2, '0')}-${lastMonth.getFullYear()}`; expect(privateOptions.dateStart).toEqual(expectedStart); expect(privateOptions.includeAttachment).toBeTrue(); }); tap.test('should default to last month when no date options provided', async () => { const exportBuilder = primaryAccount.getAccountStatement({ includeTransactionAttachments: false }); expect(exportBuilder).toBeInstanceOf(bunq.ExportBuilder); // Should default to last month const privateOptions = (exportBuilder as any).options; const now = new Date(); const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1); const expectedStart = `01-${String(lastMonth.getMonth() + 1).padStart(2, '0')}-${lastMonth.getFullYear()}`; expect(privateOptions.dateStart).toEqual(expectedStart); }); tap.test('should create and download PDF statement', async () => { console.log('Creating PDF statement export...'); const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom1: 1, includeTransactionAttachments: false }); // Configure as PDF exportBuilder.asPdf(); // Create the export const bunqExport = await exportBuilder.create(); expect(bunqExport).toBeInstanceOf(bunq.BunqExport); expect(bunqExport.id).toBeTypeofNumber(); console.log('Created PDF export with ID:', bunqExport.id); // Wait for completion with status updates console.log('Waiting for PDF export to complete...'); const maxWaitTime = 180000; // 3 minutes const startTime = Date.now(); while (true) { const status = await bunqExport.get(); console.log(`Export status: ${status.status}`); if (status.status === 'COMPLETED') { break; } if (status.status === 'FAILED') { throw new Error('Export failed: ' + JSON.stringify(status)); } if (Date.now() - startTime > maxWaitTime) { throw new Error(`Export timed out after ${maxWaitTime/1000} seconds. Last status: ${status.status}`); } await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds } // Download to test directory console.log('Downloading PDF statement...'); const testFilePath = '.nogit/teststatements/test-statement.pdf'; await bunqExport.saveToFile(testFilePath); // Verify file exists and has content const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); const fileStats = await plugins.smartfile.fs.stat(testFilePath); console.log(`PDF Statement downloaded to: ${testFilePath} (${fileStats.size} bytes)`); expect(fileStats.size).toBeGreaterThan(0); }); tap.test('should create CSV statement with custom date range', async () => { console.log('Creating CSV statement export...'); // Use last month's date range to ensure it's in the past const now = new Date(); const startOfMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1); const endOfMonth = new Date(now.getFullYear(), now.getMonth(), 0); const exportBuilder = primaryAccount.getAccountStatement({ from: startOfMonth, to: endOfMonth, includeTransactionAttachments: false }); // Configure as CSV const csvExport = await exportBuilder.asCsv().create(); console.log('Created CSV export with ID:', csvExport.id); // Wait for completion console.log('Waiting for CSV export to complete...'); await csvExport.waitForCompletion(60000); // Download to test directory console.log('Downloading CSV statement...'); const testFilePath = '.nogit/teststatements/test-statement.csv'; await csvExport.saveToFile(testFilePath); // Verify file exists and has content const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); const fileStats = await plugins.smartfile.fs.stat(testFilePath); console.log(`CSV statement downloaded to: ${testFilePath} (${fileStats.size} bytes)`); expect(fileStats.size).toBeGreaterThan(0); }); tap.test('should create MT940 statement', async () => { console.log('Creating MT940 statement export...'); const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom0: 1, // Last month includeTransactionAttachments: false }); // Configure as MT940 const mt940Export = await exportBuilder.asMt940().create(); console.log('Created MT940 export with ID:', mt940Export.id); // Wait for completion console.log('Waiting for MT940 export to complete...'); await mt940Export.waitForCompletion(60000); // Download to test directory console.log('Downloading MT940 statement...'); const testFilePath = '.nogit/teststatements/test-statement.txt'; await mt940Export.saveToFile(testFilePath); // Verify file exists and has content const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); const fileStats = await plugins.smartfile.fs.stat(testFilePath); console.log(`MT940 statement downloaded to: ${testFilePath} (${fileStats.size} bytes)`); expect(fileStats.size).toBeGreaterThan(0); }); tap.test('should handle edge cases for date calculations', async () => { // Mock the getAccountStatement method to test with a specific date const originalMethod = primaryAccount.getAccountStatement; // Override the method temporarily for this test primaryAccount.getAccountStatement = function(optionsArg) { const exportBuilder = new bunq.ExportBuilder(this.bunqAccountRef, this); // Simulate January 2024 as "now" const mockNow = new Date(2024, 0, 15); // January 15, 2024 const targetDate = new Date(mockNow.getFullYear(), mockNow.getMonth() - 1, 1); const startDate = new Date(targetDate.getFullYear(), targetDate.getMonth(), 1); const endDate = new Date(targetDate.getFullYear(), targetDate.getMonth() + 1, 0); const formatDate = (date: Date): string => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${day}-${month}-${year}`; }; exportBuilder.dateRange(formatDate(startDate), formatDate(endDate)); exportBuilder.includeAttachments(optionsArg.includeTransactionAttachments); return exportBuilder; }; try { const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom1: 1, // Last month (December 2023) includeTransactionAttachments: false }); const privateOptions = (exportBuilder as any).options; expect(privateOptions.dateStart).toEqual('01-12-2023'); expect(privateOptions.dateEnd).toEqual('31-12-2023'); } finally { // Restore original method primaryAccount.getAccountStatement = originalMethod; } }); tap.test('should cleanup test environment', async () => { await testBunqAccount.stop(); console.log('Test environment cleaned up'); }); export default tap.start();