import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as bunq from '../ts/index.js'; let testBunqAccount: bunq.BunqAccount; let sandboxApiKey: string; let primaryAccount: bunq.BunqMonetaryAccount; let secondaryAccount: bunq.BunqMonetaryAccount; tap.test('should create test setup with multiple accounts', async () => { // Create sandbox user const tempAccount = new bunq.BunqAccount({ apiKey: '', deviceName: 'bunq-payment-test', environment: 'SANDBOX', }); sandboxApiKey = await tempAccount.createSandboxUser(); console.log('Generated sandbox API key for payment tests'); // Initialize bunq account testBunqAccount = new bunq.BunqAccount({ apiKey: sandboxApiKey, deviceName: 'bunq-payment-test', environment: 'SANDBOX', }); await testBunqAccount.init(); // Get accounts const accounts = await testBunqAccount.getAccounts(); primaryAccount = accounts[0]; // Create a second account for testing transfers try { const newAccount = await bunq.BunqMonetaryAccount.create(testBunqAccount, { currency: 'EUR', description: 'Test Secondary Account', dailyLimit: '100.00', overdraftLimit: '0.00' }); // Refresh accounts list const updatedAccounts = await testBunqAccount.getAccounts(); secondaryAccount = updatedAccounts.find(acc => acc.id === newAccount.id) || primaryAccount; } catch (error) { console.log('Could not create secondary account, using primary for tests'); secondaryAccount = primaryAccount; } expect(primaryAccount).toBeInstanceOf(bunq.BunqMonetaryAccount); console.log(`Primary account: ${primaryAccount.description} (${primaryAccount.balance.value} ${primaryAccount.balance.currency})`); }); tap.test('should create and execute a payment draft', async () => { const draft = new bunq.BunqDraftPayment(testBunqAccount, primaryAccount); // Create a draft payment const draftId = await draft.create({ numberOfRequiredAccepts: 1, entries: [{ amount: { currency: 'EUR', value: '5.00' }, counterparty_alias: { type: 'IBAN', value: 'NL91ABNA0417164300', name: 'Draft Test Recipient' }, description: 'Test draft payment entry' }] }); expect(draftId).toBeTypeofNumber(); console.log(`Created draft payment with ID: ${draftId}`); // List drafts const drafts = await bunq.BunqDraftPayment.list(testBunqAccount, primaryAccount.id); expect(drafts).toBeArray(); expect(drafts.length).toBeGreaterThan(0); const createdDraft = drafts.find((d: any) => d.DraftPayment?.id === draftId); expect(createdDraft).toBeDefined(); // Verify we can get the draft details const draftDetails = await draft.get(); expect(draftDetails).toBeDefined(); expect(draftDetails.id).toEqual(draftId); expect(draftDetails.entries).toBeArray(); expect(draftDetails.entries.length).toEqual(1); console.log(`Draft payment verified - status: ${draftDetails.status || 'unknown'}`); // Note: Draft payment update/cancel operations are limited in sandbox // The API only accepts certain status transitions and field updates }); tap.test('should test payment builder with various options', async () => { // Test different payment builder configurations // 1. Simple IBAN payment const simplePayment = bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('1.00', 'EUR') .toIban('NL91ABNA0417164300', 'Simple Test') .description('Simple payment test'); expect(simplePayment).toBeDefined(); // 2. Payment with custom request ID const customIdPayment = bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('2.50', 'EUR') .toIban('NL91ABNA0417164300', 'Custom ID Test') .description('Payment with custom request ID') .customRequestId('test-request-123'); expect(customIdPayment).toBeDefined(); // 3. Payment to email const emailPayment = bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('3.00', 'EUR') .toEmail('test@example.com', 'Email Test') .description('Payment to email'); expect(emailPayment).toBeDefined(); // 4. Payment to phone number const phonePayment = bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('4.00', 'EUR') .toPhoneNumber('+31612345678', 'Phone Test') .description('Payment to phone'); expect(phonePayment).toBeDefined(); console.log('All payment builder variations created successfully'); }); tap.test('should test batch payments', async () => { const paymentBatch = new bunq.BunqPaymentBatch(testBunqAccount); // Create a batch payment const batchPayments = [ { amount: { currency: 'EUR', value: '1.00' }, counterparty_alias: { type: 'IBAN', value: 'NL91ABNA0417164300', name: 'Batch Recipient 1' }, description: 'Batch payment 1' }, { amount: { currency: 'EUR', value: '2.00' }, counterparty_alias: { type: 'IBAN', value: 'NL91ABNA0417164300', name: 'Batch Recipient 2' }, description: 'Batch payment 2' } ]; try { const batchId = await paymentBatch.create(primaryAccount, batchPayments); expect(batchId).toBeTypeofNumber(); console.log(`Created batch payment with ID: ${batchId}`); // Get batch details const batchDetails = await paymentBatch.get(primaryAccount, batchId); expect(batchDetails).toBeDefined(); expect(batchDetails.payments).toBeArray(); expect(batchDetails.payments.length).toEqual(2); console.log(`Batch contains ${batchDetails.payments.length} payments`); } catch (error) { console.log('Batch payment creation failed (may not be supported in sandbox):', error.message); } }); tap.test('should test scheduled payments', async () => { const schedulePayment = new bunq.BunqSchedulePayment(testBunqAccount); // Create a scheduled payment for tomorrow const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); try { const scheduleId = await schedulePayment.create(primaryAccount, { payment: { amount: { currency: 'EUR', value: '10.00' }, counterparty_alias: { type: 'IBAN', value: 'NL91ABNA0417164300', name: 'Scheduled Recipient' }, description: 'Scheduled payment test' }, schedule: { time_start: tomorrow.toISOString(), time_end: tomorrow.toISOString(), recurrence_unit: 'ONCE', recurrence_size: 1 } }); expect(scheduleId).toBeTypeofNumber(); console.log(`Created scheduled payment with ID: ${scheduleId}`); // List scheduled payments const schedules = await schedulePayment.list(primaryAccount); expect(schedules).toBeArray(); // Cancel the scheduled payment await schedulePayment.delete(primaryAccount, scheduleId); console.log('Scheduled payment cancelled successfully'); } catch (error) { console.log('Scheduled payment creation failed (may not be supported in sandbox):', error.message); } }); tap.test('should test payment requests', async () => { const paymentRequest = new bunq.BunqRequestInquiry(testBunqAccount, primaryAccount); // Create a payment request try { const requestId = await paymentRequest.create({ amountInquired: { currency: 'EUR', value: '15.00' }, counterpartyAlias: { type: 'EMAIL', value: 'requester@example.com', name: 'Request Sender' }, description: 'Payment request test', allowBunqme: true }); expect(requestId).toBeTypeofNumber(); console.log(`Created payment request with ID: ${requestId}`); // List requests const requests = await bunq.BunqRequestInquiry.list(testBunqAccount, primaryAccount.id); expect(requests).toBeArray(); // Cancel the request await paymentRequest.update(requestId, { status: 'CANCELLED' }); console.log('Payment request cancelled successfully'); } catch (error) { console.log('Payment request creation failed:', error.message); } }); tap.test('should test payment response (accepting a request)', async () => { const paymentResponse = new bunq.BunqRequestResponse(testBunqAccount, primaryAccount); // First create a request to respond to const paymentRequest = new bunq.BunqRequestInquiry(testBunqAccount, primaryAccount); try { // Create a self-request (from same account) for testing const requestId = await paymentRequest.create({ amountInquired: { currency: 'EUR', value: '5.00' }, counterpartyAlias: { type: 'IBAN', value: primaryAccount.iban, name: primaryAccount.displayName }, description: 'Self request for testing response' }); console.log(`Created self-request with ID: ${requestId}`); // Accept the request const responseId = await paymentResponse.accept(requestId); expect(responseId).toBeTypeofNumber(); console.log(`Accepted request with response ID: ${responseId}`); } catch (error) { console.log('Payment response test failed:', error.message); } }); tap.test('should test transaction filtering and pagination', async () => { try { // Get transactions with filters const recentTransactions = await primaryAccount.getTransactions({ count: 5, older_id: undefined, newer_id: undefined }); expect(recentTransactions).toBeArray(); expect(recentTransactions.length).toBeLessThanOrEqual(5); console.log(`Retrieved ${recentTransactions.length} recent transactions`); // Test transaction details if (recentTransactions.length > 0) { const firstTx = recentTransactions[0]; expect(firstTx.id).toBeTypeofNumber(); expect(firstTx.created).toBeTypeofString(); expect(firstTx.amount).toHaveProperty('value'); expect(firstTx.amount).toHaveProperty('currency'); expect(firstTx.description).toBeTypeofString(); expect(firstTx.type).toBeTypeofString(); // Check transaction type expect(firstTx.type).toBeOneOf([ 'IDEAL', 'BUNQ', 'MASTERCARD', 'MAESTRO', 'SAVINGS', 'INTEREST', 'REQUEST', 'SOFORT', 'EBA_SCT' ]); console.log(`First transaction: ${firstTx.type} - ${firstTx.amount.value} ${firstTx.amount.currency}`); } } catch (error) { if (error.message && error.message.includes('Insufficient authentication')) { console.log('Transaction filtering test skipped - insufficient permissions in sandbox'); // At least verify that the error is handled properly expect(error).toBeInstanceOf(Error); } else { throw error; } } }); tap.test('should test payment with attachments', async () => { // Create a payment with attachment placeholder const paymentWithAttachment = bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('2.00', 'EUR') .toIban('NL91ABNA0417164300', 'Attachment Test') .description('Payment with attachment test'); // Note: Actual attachment upload would require: // 1. Upload attachment using BunqAttachment.upload() // 2. Get attachment ID // 3. Include attachment_id in payment expect(paymentWithAttachment).toBeDefined(); console.log('Payment with attachment builder created (attachment upload not tested in sandbox)'); }); tap.test('should cleanup test resources', async () => { await testBunqAccount.stop(); console.log('Payment test cleanup completed'); }); export default tap.start();