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; tap.test('should setup advanced test environment', async () => { // Create sandbox user const tempAccount = new bunq.BunqAccount({ apiKey: '', deviceName: 'bunq-advanced-test', environment: 'SANDBOX', }); sandboxApiKey = await tempAccount.createSandboxUser(); // Initialize bunq account testBunqAccount = new bunq.BunqAccount({ apiKey: sandboxApiKey, deviceName: 'bunq-advanced-test', environment: 'SANDBOX', }); await testBunqAccount.init(); // Get primary account const accounts = await testBunqAccount.getAccounts(); primaryAccount = accounts[0]; console.log('Advanced test environment setup complete'); }); tap.test('should test joint account functionality', async () => { // Test joint account creation try { const jointAccountId = await bunq.BunqMonetaryAccount.createJoint(testBunqAccount, { currency: 'EUR', description: 'Test Joint Account', daily_limit: { value: '500.00', currency: 'EUR' }, overdraft_limit: { value: '0.00', currency: 'EUR' }, alias: { type: 'EMAIL', value: 'joint-test@example.com', name: 'Joint Account Test' }, co_owner_invite: { type: 'EMAIL', value: 'co-owner@example.com' } }); expect(jointAccountId).toBeTypeofNumber(); console.log(`Created joint account with ID: ${jointAccountId}`); // List all accounts to verify const allAccounts = await testBunqAccount.getAccounts(); const jointAccount = allAccounts.find(acc => acc.id === jointAccountId); expect(jointAccount).toBeDefined(); expect(jointAccount?.accountType).toEqual('joint'); } catch (error) { console.log('Joint account creation not supported in sandbox:', error.message); } }); tap.test('should test card operations', async () => { const cardManager = new bunq.BunqCard(testBunqAccount); try { // Create a virtual card const cardId = await cardManager.create({ type: 'MASTERCARD', sub_type: 'VIRTUAL', product_type: 'MASTERCARD_DEBIT', primary_account_numbers: [{ monetary_account_id: primaryAccount.id, status: 'ACTIVE' }], pin_code_assignment: [{ type: 'PRIMARY', pin_code: '1234' // Note: In production, use secure PIN }] }); expect(cardId).toBeTypeofNumber(); console.log(`Created virtual card with ID: ${cardId}`); // Get card details const card = await cardManager.get(cardId); expect(card.id).toEqual(cardId); expect(card.type).toEqual('MASTERCARD'); expect(card.status).toBeOneOf(['ACTIVE', 'PENDING_ACTIVATION']); // Update card status await cardManager.update(cardId, { status: 'DEACTIVATED' }); console.log('Card deactivated successfully'); } catch (error) { console.log('Card operations not fully supported in sandbox:', error.message); } }); tap.test('should test savings goals', async () => { try { // Create a savings goal const savingsGoal = await bunq.BunqMonetaryAccount.create(testBunqAccount, { currency: 'EUR', description: 'Vacation Savings', daily_limit: '0.00', savings_goal: { currency: 'EUR', value: '1000.00', end_date: '2025-12-31' } }); expect(savingsGoal.id).toBeTypeofNumber(); console.log('Savings goal account created'); // Transfer to savings const payment = await bunq.BunqPayment.builder(testBunqAccount, primaryAccount) .amount('50.00', 'EUR') .toAccount(savingsGoal.id) .description('Monthly savings deposit') .create(); console.log('Savings deposit completed'); } catch (error) { console.log('Savings goals not supported in sandbox:', error.message); } }); tap.test('should test bunq.me functionality', async () => { // Create bunq.me link try { const bunqMeTab = { amount_inquired: { currency: 'EUR', value: '10.00' }, description: 'Coffee money', redirect_url: 'https://example.com/thanks' }; const httpClient = testBunqAccount['apiContext'].getHttpClient(); const tabResponse = await httpClient.post( `/v1/user/${testBunqAccount.userId}/monetary-account/${primaryAccount.id}/bunqme-tab`, { bunqme_tab_entry: bunqMeTab } ); if (tabResponse.Response && tabResponse.Response[0]) { const bunqMeUrl = tabResponse.Response[0].BunqMeTab?.bunqme_tab_share_url; expect(bunqMeUrl).toBeTypeofString(); expect(bunqMeUrl).toInclude('bunq.me'); console.log(`Created bunq.me link: ${bunqMeUrl}`); } } catch (error) { console.log('bunq.me functionality error:', error.message); } }); tap.test('should test OAuth functionality', async () => { // Test OAuth client registration try { const oauthClient = { status: 'ACTIVE', redirect_uri: ['https://example.com/oauth/callback'], display_name: 'Test OAuth App', description: 'OAuth integration test' }; const httpClient = testBunqAccount['apiContext'].getHttpClient(); const oauthResponse = await httpClient.post( `/v1/user/${testBunqAccount.userId}/oauth-client`, oauthClient ); if (oauthResponse.Response && oauthResponse.Response[0]) { const clientId = oauthResponse.Response[0].OAuthClient?.id; expect(clientId).toBeTypeofNumber(); console.log(`Created OAuth client with ID: ${clientId}`); } } catch (error) { console.log('OAuth functionality not available in sandbox:', error.message); } }); tap.test('should test QR code functionality', async () => { // Test QR code generation for payments try { const qrCodeContent = { amount: { currency: 'EUR', value: '5.00' }, description: 'QR Code Payment Test' }; // In a real implementation, you would generate QR code content // that follows the bunq QR code format const qrData = JSON.stringify({ bunq: { request: { amount: qrCodeContent.amount, description: qrCodeContent.description, merchant: 'Test Merchant' } } }); expect(qrData).toBeTypeofString(); console.log('QR code data generated for payment request'); } catch (error) { console.log('QR code generation error:', error.message); } }); tap.test('should test auto-accept settings', async () => { // Test auto-accept for small payments try { const settings = { auto_accept_small_payments: true, auto_accept_max_amount: { currency: 'EUR', value: '10.00' } }; // Update account settings await bunq.BunqMonetaryAccount.update(testBunqAccount, primaryAccount.id, { setting: settings }); console.log('Auto-accept settings updated'); } catch (error) { console.log('Auto-accept settings error:', error.message); } }); tap.test('should test export functionality', async () => { // Test statement export try { const exportRequest = { statement_format: 'PDF', date_start: '2025-01-01', date_end: '2025-07-31', regional_format: 'EUROPEAN' }; const httpClient = testBunqAccount['apiContext'].getHttpClient(); const exportResponse = await httpClient.post( `/v1/user/${testBunqAccount.userId}/monetary-account/${primaryAccount.id}/customer-statement`, exportRequest ); if (exportResponse.Response && exportResponse.Response[0]) { const statementId = exportResponse.Response[0].CustomerStatement?.id; expect(statementId).toBeTypeofNumber(); console.log(`Statement export requested with ID: ${statementId}`); } } catch (error) { console.log('Export functionality error:', error.message); } }); tap.test('should test multi-currency support', async () => { // Test creating account with different currency try { const usdAccount = await bunq.BunqMonetaryAccount.create(testBunqAccount, { currency: 'USD', description: 'USD Account', daily_limit: '1000.00' }); expect(usdAccount.id).toBeTypeofNumber(); console.log('Multi-currency account created'); // Test currency conversion const conversionQuote = { amount_from: { currency: 'EUR', value: '100.00' }, amount_to: { currency: 'USD' } }; // In production, you would get real-time conversion rates console.log('Currency conversion quote requested'); } catch (error) { console.log('Multi-currency not fully supported in sandbox:', error.message); } }); tap.test('should test tab payments (split bills)', async () => { // Test creating a tab for splitting bills try { const tab = { description: 'Dinner bill split', amount_total: { currency: 'EUR', value: '120.00' }, tab_items: [ { description: 'Pizza', amount: { currency: 'EUR', value: '40.00' } }, { description: 'Drinks', amount: { currency: 'EUR', value: '80.00' } } ] }; const httpClient = testBunqAccount['apiContext'].getHttpClient(); const tabResponse = await httpClient.post( `/v1/user/${testBunqAccount.userId}/monetary-account/${primaryAccount.id}/tab-usage-multiple`, tab ); if (tabResponse.Response && tabResponse.Response[0]) { console.log('Tab payment created for bill splitting'); } } catch (error) { console.log('Tab payments not supported in sandbox:', error.message); } }); tap.test('should test connect functionality', async () => { // Test bunq Connect (open banking) try { const connectRequest = { counterparty_bank: 'INGBNL2A', counterparty_iban: 'NL91INGB0417164300', consent_type: 'ACCOUNTS_INFORMATION', valid_until: '2025-12-31' }; const httpClient = testBunqAccount['apiContext'].getHttpClient(); const connectResponse = await httpClient.post( `/v1/user/${testBunqAccount.userId}/open-banking-connect`, connectRequest ); console.log('Open banking connect request created'); } catch (error) { console.log('Connect functionality not available in sandbox:', error.message); } }); tap.test('should test travel mode', async () => { // Test travel mode settings try { const travelSettings = { travel_mode: true, travel_regions: ['EUROPE', 'NORTH_AMERICA'], travel_end_date: '2025-12-31' }; // Update user travel settings const httpClient = testBunqAccount['apiContext'].getHttpClient(); await httpClient.put( `/v1/user/${testBunqAccount.userId}`, { travel_settings: travelSettings } ); console.log('Travel mode activated'); } catch (error) { console.log('Travel mode settings error:', error.message); } }); tap.test('should cleanup advanced test resources', async () => { // Clean up any created resources const accounts = await testBunqAccount.getAccounts(); // Close any test accounts created (except primary) for (const account of accounts) { if (account.id !== primaryAccount.id && account.description.includes('Test')) { try { await bunq.BunqMonetaryAccount.update(testBunqAccount, account.id, { status: 'CANCELLED', sub_status: 'REDEMPTION_VOLUNTARY', reason: 'OTHER', reason_description: 'Test cleanup' }); console.log(`Closed test account: ${account.description}`); } catch (error) { // Ignore cleanup errors } } } await testBunqAccount.stop(); console.log('Advanced test cleanup completed'); }); export default tap.start();