diff --git a/test/test.statements.ts b/test/test.statements.ts index 77862ef..aeef430 100644 --- a/test/test.statements.ts +++ b/test/test.statements.ts @@ -107,49 +107,65 @@ tap.test('should default to last month when no date options provided', async () }); tap.test('should create and download PDF statement', async () => { - try { - const exportBuilder = primaryAccount.getAccountStatement({ - monthlyIndexedFrom1: 1, - includeTransactionAttachments: false - }); + 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}`); - // 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; + 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 () => { + // Wait to avoid rate limiting + await new Promise(resolve => setTimeout(resolve, 3500)); + 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); @@ -163,19 +179,31 @@ tap.test('should create CSV statement with custom date range', async () => { // Configure as CSV const csvExport = await exportBuilder.asCsv().create(); - await csvExport.waitForCompletion(30000); + 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 + // Verify file exists and has content const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); - console.log(`CSV statement downloaded to: ${testFilePath}`); + 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 () => { + // Wait to avoid rate limiting + await new Promise(resolve => setTimeout(resolve, 3500)); + console.log('Creating MT940 statement export...'); + const exportBuilder = primaryAccount.getAccountStatement({ monthlyIndexedFrom0: 1, // Last month includeTransactionAttachments: false @@ -183,16 +211,24 @@ tap.test('should create MT940 statement', async () => { // Configure as MT940 const mt940Export = await exportBuilder.asMt940().create(); - await mt940Export.waitForCompletion(30000); + 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 + // Verify file exists and has content const fileExists = await plugins.smartfile.fs.fileExists(testFilePath); expect(fileExists).toBeTrue(); - console.log(`MT940 statement downloaded to: ${testFilePath}`); + 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 () => { diff --git a/ts/bunq.classes.export.ts b/ts/bunq.classes.export.ts index 1f14bf9..88f5468 100644 --- a/ts/bunq.classes.export.ts +++ b/ts/bunq.classes.export.ts @@ -111,18 +111,27 @@ export class BunqExport { throw new Error('Export ID not set'); } + // Ensure the export is complete before downloading + const status = await this.get(); + if (status.status !== 'COMPLETED') { + throw new Error(`Export is not ready for download. Status: ${status.status}`); + } + // For PDF statements, use the /content endpoint directly const downloadUrl = `${this.bunqAccount.apiContext.getBaseUrl()}/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccount.id}/customer-statement/${this.id}/content`; const response = await fetch(downloadUrl, { method: 'GET', headers: { - 'X-Bunq-Client-Authentication': this.bunqAccount.apiContext.getSession().getContext().sessionToken + 'X-Bunq-Client-Authentication': this.bunqAccount.apiContext.getSession().getContext().sessionToken, + 'User-Agent': 'bunq-api-client/1.0.0', + 'Cache-Control': 'no-cache' } }); if (!response.ok) { - throw new Error(`Failed to download export: HTTP ${response.status}`); + const responseText = await response.text(); + throw new Error(`Failed to download export: HTTP ${response.status} - ${responseText}`); } const arrayBuffer = await response.arrayBuffer(); @@ -146,7 +155,7 @@ export class BunqExport { while (true) { const details = await this.get(); - if (details.status === 'COMPLETE') { + if (details.status === 'COMPLETED') { return; }