415 lines
12 KiB
TypeScript
415 lines
12 KiB
TypeScript
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(); |