Skip to main content

Overview

This guide walks you through testing your BOOP Network integration using our development environment at dev.app.boop.it. You’ll learn how to simulate authentication flows, test edge cases, and verify your integration works correctly.

Test Environment Setup

1. Get Test Credentials

Request test credentials from our team:
# Test credentials format
Vendor ID: ven_test_abc123
API Key: sk_test_xyz789
Environment: https://dev.app.boop.it
Test credentials only work in the development environment. They cannot process real transactions.

2. Configure Your Application

Set up environment-specific configuration:
# Development
BOOP_ENV=development
BOOP_API_URL=https://dev.app.boop.it
BOOP_WS_URL=wss://dev.app.boop.it/ws/vendor
BOOP_API_KEY=sk_test_xyz789
BOOP_VENDOR_ID=ven_test_abc123

# Production (for later)
# BOOP_ENV=production
# BOOP_API_URL=https://app.boop.it
# BOOP_WS_URL=wss://app.boop.it/ws/vendor
# BOOP_API_KEY=sk_live_[your_production_key]
# BOOP_VENDOR_ID=ven_live_[your_production_id]

Mock Tools

Palm Vein Scanner Simulator

Access our mock PVS interface to simulate palm scans: URL: https://mock-pvs.dev.event-vendor.boop.it Features:
  • Register test users
  • Simulate successful/failed scans
  • Test different authentication scenarios
  • Generate test biometric data

Test User Management

Create and manage test users for your integration:
// Register a test user
const registerTestUser = async (userId, attributes) => {
  const response = await fetch('https://dev.app.boop.it/api/v1/test-users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': 'sk_test_xyz789'
    },
    body: JSON.stringify({
      user_id: userId,
      attributes: {
        email: `${userId}@test.boop.network`,
        name: `Test User ${userId}`,
        age_verified: true,
        ...attributes
      }
    })
  });

  return response.json();
};

// Create test users with different profiles
await registerTestUser('test_adult_user', { age_verified: true });
await registerTestUser('test_minor_user', { age_verified: false });
await registerTestUser('test_vip_user', { membership_level: 'vip' });

Testing Scenarios

1. Basic Authentication Flow

Test the complete authentication cycle:
// Test script for basic authentication
async function testBasicAuth() {
  console.log('🧪 Testing Basic Authentication Flow');

  // 1. Create authentication context
  const contextId = await client.createAuthContext(
    'payment',
    ['email', 'name'],
    { amount: 10.00, test_mode: true }
  );
  console.log(`✓ Context created: ${contextId}`);

  // 2. Simulate user scanning palm
  // Use mock PVS interface at mock-pvs.dev.event-vendor.boop.it
  await simulatePalmScan(contextId, 'test_user_1');

  // 3. Wait for authentication result
  const result = await waitForAuthResult(contextId, 30000);

  if (result.success) {
    console.log('✓ Authentication successful');
    console.log('  User ID:', result.user_id);
    console.log('  Attributes:', result.attributes);
  } else {
    console.log('✗ Authentication failed:', result.reason);
  }
}

2. Attribute Verification

Test requesting and receiving user attributes:
// Test different attribute combinations
const attributeTests = [
  {
    name: 'Basic Attributes',
    attributes: ['email', 'name'],
    expectedFields: ['email', 'name']
  },
  {
    name: 'Age Verification',
    attributes: ['age_verified'],
    expectedFields: ['age_verified']
  },
  {
    name: 'Complete Profile',
    attributes: ['email', 'name', 'phone', 'address'],
    expectedFields: ['email', 'name', 'phone', 'address']
  }
];

for (const test of attributeTests) {
  console.log(`\n🧪 Testing: ${test.name}`);

  const contextId = await client.createAuthContext(
    'verification',
    test.attributes,
    { test_scenario: test.name }
  );

  const result = await performAuthentication(contextId);

  // Verify all requested attributes are returned
  for (const field of test.expectedFields) {
    if (field in result.attributes) {
      console.log(`  ✓ ${field}: ${result.attributes[field]}`);
    } else {
      console.log(`  ✗ Missing attribute: ${field}`);
    }
  }
}

3. Error Handling

Test error scenarios and recovery:
// Error scenario testing
async function testErrorScenarios() {
  console.log('🧪 Testing Error Scenarios');

  // Test 1: Invalid API key
  try {
    const badClient = new BOOPClient('invalid_key', 'ven_test');
    await badClient.connect();
  } catch (error) {
    console.log('✓ Invalid API key rejected:', error.message);
  }

  // Test 2: Missing required attributes
  try {
    await client.createAuthContext('payment', null);
  } catch (error) {
    console.log('✓ Missing attributes caught:', error.message);
  }

  // Test 3: Context timeout
  const contextId = await client.createAuthContext(
    'payment',
    ['email'],
    { timeout: 1 } // 1 second timeout
  );

  await sleep(2000); // Wait for timeout
  const status = await getContextStatus(contextId);
  console.log('✓ Context timeout handled:', status);

  // Test 4: Network disconnection
  await client.connect();
  client.ws.close(); // Simulate disconnect
  console.log('✓ Disconnection detected');

  // Verify reconnection
  await sleep(6000);
  if (client.ws.readyState === WebSocket.OPEN) {
    console.log('✓ Automatic reconnection successful');
  }
}

4. Performance Testing

Measure latency and throughput:
// Performance testing
async function performanceTest() {
  console.log('🧪 Performance Testing');

  const iterations = 100;
  const latencies = [];

  for (let i = 0; i < iterations; i++) {
    const startTime = Date.now();

    const contextId = await client.createAuthContext(
      'payment',
      ['email'],
      { test_iteration: i }
    );

    await simulatePalmScan(contextId, 'test_user_perf');
    const result = await waitForAuthResult(contextId, 5000);

    const latency = Date.now() - startTime;
    latencies.push(latency);

    if (i % 10 === 0) {
      console.log(`  Iteration ${i}: ${latency}ms`);
    }
  }

  // Calculate statistics
  const avg = latencies.reduce((a, b) => a + b, 0) / latencies.length;
  const min = Math.min(...latencies);
  const max = Math.max(...latencies);
  const p95 = latencies.sort((a, b) => a - b)[Math.floor(iterations * 0.95)];

  console.log('\n📊 Performance Results:');
  console.log(`  Average: ${avg.toFixed(2)}ms`);
  console.log(`  Min: ${min}ms`);
  console.log(`  Max: ${max}ms`);
  console.log(`  P95: ${p95}ms`);
}

Test Data Sets

User Profiles

Use these test user profiles for different scenarios:
User IDProfileAttributesUse Case
test_adult_01Adult Customerage_verified: true, email, nameAge-restricted purchases
test_minor_01Minor Customerage_verified: false, email, nameAge verification failure
test_vip_01VIP Membermembership: ‘vip’, email, name, phonePremium services
test_employee_01Employeeemployee_id, department, access_levelAccess control
test_restricted_01Limited Profileemail onlyMinimal data sharing

Test Amounts

For payment contexts, use these amounts to trigger different behaviors:
AmountBehavior
0.01 - 0.99Always succeeds (test mode)
1.00 - 99.99Normal processing
100.00Triggers additional verification
666.66Simulates fraud detection
999.99Simulates timeout

Automated Testing

Integration Test Suite

Create automated tests for CI/CD:
// test/integration/boop.test.js
const { BOOPClient } = require('../src/boop-client');
const assert = require('assert');

describe('BOOP Integration Tests', () => {
  let client;

  before(async () => {
    client = new BOOPClient(
      process.env.BOOP_TEST_API_KEY,
      process.env.BOOP_TEST_VENDOR_ID
    );
    await client.connect();
  });

  after(async () => {
    await client.disconnect();
  });

  describe('Authentication', () => {
    it('should connect and authenticate successfully', async () => {
      assert(client.isConnected(), 'Client should be connected');
    });

    it('should reject invalid credentials', async () => {
      const badClient = new BOOPClient('invalid', 'invalid');
      try {
        await badClient.connect();
        assert.fail('Should have thrown error');
      } catch (error) {
        assert(error.message.includes('Authentication failed'));
      }
    });
  });

  describe('Context Creation', () => {
    it('should create payment context', async () => {
      const contextId = await client.createAuthContext(
        'payment',
        ['email'],
        { amount: 10.00 }
      );
      assert(contextId.startsWith('ctx_'), 'Context ID should have correct format');
    });

    it('should create access context', async () => {
      const contextId = await client.createAuthContext(
        'access',
        ['employee_id'],
        { location: 'Test Location' }
      );
      assert(contextId, 'Context should be created');
    });
  });

  describe('Attribute Handling', () => {
    it('should return requested attributes', async () => {
      const contextId = await client.createAuthContext(
        'verification',
        ['email', 'name']
      );

      // Simulate authentication
      const result = await simulateAuth(contextId, 'test_user_attrs');

      assert(result.attributes.email, 'Email should be present');
      assert(result.attributes.name, 'Name should be present');
    });

    it('should handle optional attributes', async () => {
      const contextId = await client.createAuthContext(
        'verification',
        ['email', 'phone'] // Phone might not be available
      );

      const result = await simulateAuth(contextId, 'test_user_partial');

      assert(result.attributes.email, 'Email should be present');
      // Phone may or may not be present
    });
  });
});

Load Testing

Test your system under load:
// load-test.js
const { Worker } = require('worker_threads');
const os = require('os');

async function loadTest() {
  const workers = os.cpus().length;
  const requestsPerWorker = 100;

  console.log(`🚀 Starting load test with ${workers} workers`);
  console.log(`   ${requestsPerWorker} requests per worker`);
  console.log(`   Total requests: ${workers * requestsPerWorker}`);

  const startTime = Date.now();
  const promises = [];

  for (let i = 0; i < workers; i++) {
    promises.push(
      new Promise((resolve, reject) => {
        const worker = new Worker('./worker.js', {
          workerData: {
            requests: requestsPerWorker,
            workerId: i
          }
        });

        worker.on('message', resolve);
        worker.on('error', reject);
      })
    );
  }

  const results = await Promise.all(promises);

  const duration = Date.now() - startTime;
  const totalRequests = results.reduce((sum, r) => sum + r.completed, 0);
  const totalErrors = results.reduce((sum, r) => sum + r.errors, 0);

  console.log('\n📊 Load Test Results:');
  console.log(`   Duration: ${duration}ms`);
  console.log(`   Successful: ${totalRequests}`);
  console.log(`   Failed: ${totalErrors}`);
  console.log(`   Throughput: ${(totalRequests / (duration / 1000)).toFixed(2)} req/s`);
}

loadTest();

Debugging

Enable Debug Logging

// Enable verbose logging for debugging
const client = new BOOPClient(apiKey, vendorId, {
  debug: true,
  logLevel: 'verbose'
});

client.on('debug', (message) => {
  console.log(`[DEBUG] ${message}`);
});

client.on('raw', (data) => {
  console.log(`[RAW] ${JSON.stringify(data, null, 2)}`);
});

Message Tracing

Track message flow through your system:
class TrackedClient extends BOOPClient {
  constructor(apiKey, vendorId) {
    super(apiKey, vendorId);
    this.messageLog = [];
  }

  send(data) {
    this.messageLog.push({
      direction: 'outbound',
      timestamp: new Date(),
      data: data
    });
    super.send(data);
  }

  handleMessage(message) {
    this.messageLog.push({
      direction: 'inbound',
      timestamp: new Date(),
      data: message
    });
    super.handleMessage(message);
  }

  exportTrace() {
    return this.messageLog;
  }
}

Monitoring & Metrics

Health Check Endpoint

Monitor your integration health:
// Health check endpoint for your service
app.get('/health/boop', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date(),
    checks: {}
  };

  // Check WebSocket connection
  health.checks.websocket = {
    connected: client.isConnected(),
    lastPing: client.lastPingTime,
    reconnectCount: client.reconnectCount
  };

  // Check authentication status
  health.checks.authentication = {
    authenticated: client.isAuthenticated(),
    vendorId: client.vendorId
  };

  // Check recent activity
  health.checks.activity = {
    activeContexts: client.activeContexts.size,
    lastActivity: client.lastActivityTime
  };

  // Overall status
  health.status = health.checks.websocket.connected ? 'healthy' : 'unhealthy';

  res.status(health.status === 'healthy' ? 200 : 503).json(health);
});

Common Issues & Solutions

Problem: WebSocket disconnects frequentlySolutions:
  • Implement exponential backoff for reconnection
  • Check network stability
  • Ensure proper ping/pong handling
  • Verify firewall/proxy settings
// Robust reconnection logic
class StableClient extends BOOPClient {
  async handleDisconnect() {
    this.reconnectDelay = Math.min(
      this.reconnectDelay * 2,
      30000
    );
    await sleep(this.reconnectDelay);
    await this.connect();
  }
}
Problem: Users can’t authenticate successfullyChecklist:
  • Verify test user is registered
  • Check requested attributes exist
  • Ensure context hasn’t expired
  • Validate API credentials
// Debug authentication issues
client.on('authentication_failed', (data) => {
  console.error('Auth failed:', {
    context: data.context_id,
    reason: data.reason,
    details: data.details
  });
});
Problem: Not receiving expected user attributesSolutions:
  • Verify attributes are configured in your vendor profile
  • Check user has granted permission
  • Ensure attributes exist for test user
// Handle partial attributes
const attributes = result.attributes || {};
const email = attributes.email || 'Not provided';
const name = attributes.name || 'Anonymous';

Next Steps