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 () => { try { 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(); // Wait for completion with longer timeout for PDF await bunqExport.waitForCompletion(120000); // Download to test directory const testFilePath = '.nogit/teststatements/test-statement.pdf'; await bunqExport.saveToFile(testFilePath); // Verify file exists const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); console.log(`Statement downloaded to: ${testFilePath}`); } catch (error) { if (error.message && error.message.includes('timed out')) { console.log('PDF export timed out - sandbox may not support PDF exports'); // Try CSV instead const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom1: 1, includeTransactionAttachments: false }); const csvExport = await exportBuilder.asCsv().create(); console.log('Created CSV export instead with ID:', csvExport.id); } else { throw error; } } }); tap.test('should create CSV statement with custom date range', async () => { // 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(); await csvExport.waitForCompletion(30000); const testFilePath = '.nogit/teststatements/test-statement.csv'; await csvExport.saveToFile(testFilePath); // Verify file exists const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); console.log(`CSV statement downloaded to: ${testFilePath}`); }); tap.test('should create MT940 statement', async () => { const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom0: 1, // Last month includeTransactionAttachments: false }); // Configure as MT940 const mt940Export = await exportBuilder.asMt940().create(); await mt940Export.waitForCompletion(30000); const testFilePath = '.nogit/teststatements/test-statement.txt'; await mt940Export.saveToFile(testFilePath); // Verify file exists const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); console.log(`MT940 statement downloaded to: ${testFilePath}`); }); 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();