Session Management
Basic Testing Workflow
// Example testing workflow
async function testGeftScenario(scenarioName) {
try {
// 1. Authenticate
const authResponse = await authenticate();
// 2. Create session with test data
const sessionData = getTestScenarioData(scenarioName);
const session = await createSession(sessionData, authResponse.access_token);
// 3. Monitor events
setupEventMonitoring(session.sessionId);
// 4. Launch iframe
launchGeftIframe(session.sessionId);
// 5. Poll status
const finalStatus = await pollSessionStatus(
session.sessionId,
authResponse.access_token
);
return {
scenario: scenarioName,
success: finalStatus.status === 'Completed',
status: finalStatus
};
} catch (error) {
console.error(`Test failed for ${scenarioName}:`, error);
throw error;
}
}
Test Data Management
function getTestScenarioData(scenario) {
const scenarios = {
'Happy1': {
referenceId: 'Happy1',
payor: {
firstName: 'John',
lastName: 'Doe',
email: 'j.doe@gmail.com'
}
},
'Happy2': {
referenceId: 'Happy2',
payor: {
firstName: 'Steve',
lastName: 'Diamond',
email: 'steve.diamond@example.com'
}
},
'Unhappy1': {
referenceId: 'Unhappy1',
payor: {
firstName: 'Joe',
lastName: 'Fails',
email: 'joe.fails@example.com'
}
}
};
return {
...scenarios[scenario],
type: 'EFT',
direction: 'DEBIT',
currency: 'CAD',
options: {
guarantee: { enable: true },
notificationPreferences: { language: 'EN' }
}
};
}
Event Testing
Event Monitoring Setup
function setupEventMonitoring(sessionId) {
const events = [];
window.addEventListener('message', function(e) {
if (e.data && e.data.sessionId === sessionId) {
events.push({
timestamp: new Date(),
event: e.data
});
console.log('Test Event:', e.data);
// Verify expected events for scenario
validateEventSequence(events);
}
});
return events;
}
Event Validation
function validateEventSequence(events) {
const eventSteps = events.map(e => e.event.Step);
// Validate event order for successful flow
const expectedSuccess = [
'APP_MOUNTED',
'INSTITUTION_SELECTED',
'SUBMIT_CREDENTIAL',
'ACCOUNT_SELECTED',
'COMPONENT_DEPOSIT_CONTINUE',
'GUARANTEE_OFFERED',
'COMPONENT_PAD_DOWNLOADED',
'SUCCESS'
];
// Check if events follow expected pattern
let expectedIndex = 0;
for (const step of eventSteps) {
if (step === expectedSuccess[expectedIndex]) {
expectedIndex++;
}
}
return expectedIndex === expectedSuccess.length;
}
Automated Testing
Full Test Suite
// Run all test scenarios
async function runFullTestSuite() {
const scenarios = [
'Happy1',
'Happy2',
'Happy3',
'Unhappy1',
'Unhappy2',
'Unhappy3'
];
const results = [];
for (const scenario of scenarios) {
try {
const result = await testGeftScenario(scenario);
results.push(result);
console.log(`✓ ${scenario} passed`);
} catch (error) {
results.push({
scenario,
success: false,
error: error.message
});
console.log(`✗ ${scenario} failed:`, error.message);
}
}
return results;
}
Parallel Testing
// Run multiple scenarios in parallel
async function runParallelTests(scenarios) {
const promises = scenarios.map(scenario => testGeftScenario(scenario));
try {
const results = await Promise.allSettled(promises);
return results.map((result, index) => ({
scenario: scenarios[index],
success: result.status === 'fulfilled',
data: result.value || result.reason
}));
} catch (error) {
console.error('Parallel test execution failed:', error);
throw error;
}
}
Authentication Testing
API Key Configuration
// Configure API authentication headers
const API_CONFIG = {
baseUrl: 'https://payments-uat.flinksapp.com',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.GEFT_API_KEY,
'x-client-id': process.env.GEFT_CLIENT_ID
}
};
async function createSession(sessionData) {
const response = await fetch(`${API_CONFIG.baseUrl}/api/v2/sessions`, {
method: 'POST',
headers: API_CONFIG.headers,
body: JSON.stringify(sessionData)
});
if (!response.ok) {
throw new Error(`Session creation failed: ${response.status}`);
}
return response.json();
}
Status Polling
Robust Polling Implementation
async function pollSessionStatus(sessionId, maxAttempts = 20) {
const pollInterval = 30000; // 30 seconds
for (let i = 0; i < maxAttempts; i++) {
try {
const response = await fetch(
`https://payments-uat.flinksapp.com/api/v2/sessions/${sessionId}/status`
);
if (!response.ok) {
throw new Error(`Status check failed: ${response.status}`);
}
const status = await response.json();
// Check for terminal states
if (['Completed', 'Failed', 'Canceled', 'Expired'].includes(status.status)) {
return status;
}
// Wait before next poll
await new Promise(resolve => setTimeout(resolve, pollInterval));
} catch (error) {
console.error('Status polling error:', error);
if (i === maxAttempts - 1) throw error;
}
}
throw new Error('Polling timeout - session status unknown');
}
Error Handling
Comprehensive Error Testing
async function testErrorHandling() {
const errorTests = [
{
name: 'Invalid credentials',
test: () => authenticateWithWrongCredentials(),
expectedError: 'Unauthorized'
},
{
name: 'Malformed session data',
test: () => createSessionWithInvalidData(),
expectedError: 'Bad Request'
},
{
name: 'Network timeout',
test: () => testWithNetworkDelay(),
expectedError: 'Timeout'
}
];
const results = [];
for (const errorTest of errorTests) {
try {
await errorTest.test();
results.push({
test: errorTest.name,
success: false,
error: 'Expected error was not thrown'
});
} catch (error) {
const success = error.message.includes(errorTest.expectedError);
results.push({
test: errorTest.name,
success,
error: success ? null : `Unexpected error: ${error.message}`
});
}
}
return results;
}
Performance Testing
Load Testing
async function performanceTest() {
const concurrentSessions = 5;
const sessionPromises = [];
console.log(`Starting ${concurrentSessions} concurrent sessions...`);
for (let i = 0; i < concurrentSessions; i++) {
sessionPromises.push(
measureSessionTime(`Happy1_${i}`)
);
}
const results = await Promise.allSettled(sessionPromises);
const successful = results.filter(r => r.status === 'fulfilled');
const failed = results.filter(r => r.status === 'rejected');
console.log(`Performance results:`);
console.log(`Successful: ${successful.length}`);
console.log(`Failed: ${failed.length}`);
if (successful.length > 0) {
const times = successful.map(r => r.value.duration);
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
console.log(`Average completion time: ${avgTime}ms`);
}
}
async function measureSessionTime(referenceId) {
const startTime = Date.now();
try {
const result = await testGeftScenario('Happy1', { referenceId });
return {
success: true,
duration: Date.now() - startTime,
result
};
} catch (error) {
return {
success: false,
duration: Date.now() - startTime,
error: error.message
};
}
}
CI/CD Integration
Test Runner for CI
// test-runner.js - For use in CI/CD pipelines
const { testGeftScenario, runFullTestSuite } = require('./geft-tests');
async function ciTestRunner() {
console.log('Starting GEFT integration tests...');
try {
const results = await runFullTestSuite();
const passed = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`Tests completed: ${passed} passed, ${failed} failed`);
if (failed > 0) {
console.error('Failed tests:', results.filter(r => !r.success));
process.exit(1);
}
console.log('All tests passed!');
process.exit(0);
} catch (error) {
console.error('Test suite failed:', error);
process.exit(1);
}
}
if (require.main === module) {
ciTestRunner();
}
module.exports = { ciTestRunner };
Next Steps
- Production Readiness: Verify you’re ready to go live
- Test Scenarios: Review all available test cases
- Event Handling: Understanding widget events