#!/usr/bin/env node /** * Test Stripe Integration for Koha Donation System * Tests the complete donation flow with Stripe test mode */ require('dotenv').config(); const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); const COLORS = { reset: '\x1b[0m', green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m' }; function log(color, symbol, message) { console.log(`${color}${symbol} ${message}${COLORS.reset}`); } async function testStripeIntegration() { console.log('\n' + '═'.repeat(60)); console.log(' Stripe Integration Test - Koha Donation System'); console.log('═'.repeat(60) + '\n'); let allTestsPassed = true; try { // Test 1: Verify environment variables console.log(`${COLORS.blue}▶ Test 1: Environment Variables${COLORS.reset}\n`); const requiredVars = { 'STRIPE_SECRET_KEY': process.env.STRIPE_SECRET_KEY, 'STRIPE_PUBLISHABLE_KEY': process.env.STRIPE_PUBLISHABLE_KEY, 'STRIPE_KOHA_PRODUCT_ID': process.env.STRIPE_KOHA_PRODUCT_ID, 'STRIPE_KOHA_5_PRICE_ID': process.env.STRIPE_KOHA_5_PRICE_ID, 'STRIPE_KOHA_15_PRICE_ID': process.env.STRIPE_KOHA_15_PRICE_ID, 'STRIPE_KOHA_50_PRICE_ID': process.env.STRIPE_KOHA_50_PRICE_ID }; for (const [key, value] of Object.entries(requiredVars)) { if (!value || value.includes('placeholder') || value.includes('PLACEHOLDER')) { log(COLORS.red, '✗', `${key} is missing or placeholder`); allTestsPassed = false; } else { const displayValue = key.includes('KEY') ? value.substring(0, 20) + '...' : value; log(COLORS.green, '✓', `${key}: ${displayValue}`); } } // Test 2: Verify product exists console.log(`\n${COLORS.blue}▶ Test 2: Verify Stripe Product${COLORS.reset}\n`); try { const product = await stripe.products.retrieve(process.env.STRIPE_KOHA_PRODUCT_ID); log(COLORS.green, '✓', `Product found: ${product.name}`); console.log(` ID: ${product.id}`); console.log(` Active: ${product.active}`); } catch (error) { log(COLORS.red, '✗', `Product not found: ${error.message}`); allTestsPassed = false; } // Test 3: Verify prices exist console.log(`\n${COLORS.blue}▶ Test 3: Verify Stripe Prices${COLORS.reset}\n`); const priceIds = [ { name: 'Foundation ($5/month)', id: process.env.STRIPE_KOHA_5_PRICE_ID }, { name: 'Advocate ($15/month)', id: process.env.STRIPE_KOHA_15_PRICE_ID }, { name: 'Champion ($50/month)', id: process.env.STRIPE_KOHA_50_PRICE_ID } ]; for (const priceConfig of priceIds) { try { const price = await stripe.prices.retrieve(priceConfig.id); const amount = price.unit_amount / 100; const currency = price.currency.toUpperCase(); const interval = price.recurring ? `/${price.recurring.interval}` : '(one-time)'; log(COLORS.green, '✓', `${priceConfig.name}: ${currency} $${amount}${interval}`); } catch (error) { log(COLORS.red, '✗', `${priceConfig.name} not found: ${error.message}`); allTestsPassed = false; } } // Test 4: Create test checkout session (Foundation tier) console.log(`\n${COLORS.blue}▶ Test 4: Create Test Checkout Session${COLORS.reset}\n`); try { const session = await stripe.checkout.sessions.create({ mode: 'subscription', payment_method_types: ['card'], line_items: [{ price: process.env.STRIPE_KOHA_5_PRICE_ID, quantity: 1 }], success_url: `${process.env.FRONTEND_URL || 'http://localhost:9000'}/koha/success.html?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.FRONTEND_URL || 'http://localhost:9000'}/koha.html`, metadata: { frequency: 'monthly', tier: '5', test: 'true' }, customer_email: 'test@example.com' }); log(COLORS.green, '✓', `Checkout session created: ${session.id}`); console.log(` Status: ${session.status}`); console.log(` Amount: ${session.amount_total / 100} ${session.currency.toUpperCase()}`); console.log(` URL: ${session.url.substring(0, 60)}...`); // Clean up test session await stripe.checkout.sessions.expire(session.id); log(COLORS.cyan, 'ℹ', 'Test session expired (cleanup)'); } catch (error) { log(COLORS.red, '✗', `Failed to create checkout session: ${error.message}`); allTestsPassed = false; } // Test 5: Create test one-time donation checkout console.log(`\n${COLORS.blue}▶ Test 5: Create One-Time Donation Checkout${COLORS.reset}\n`); try { const oneTimeSession = await stripe.checkout.sessions.create({ mode: 'payment', payment_method_types: ['card'], line_items: [{ price_data: { currency: 'nzd', product: process.env.STRIPE_KOHA_PRODUCT_ID, unit_amount: 2500, // $25.00 NZD }, quantity: 1 }], success_url: `${process.env.FRONTEND_URL || 'http://localhost:9000'}/koha/success.html?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.FRONTEND_URL || 'http://localhost:9000'}/koha.html`, metadata: { frequency: 'one_time', amount: '2500', test: 'true' }, customer_email: 'test@example.com' }); log(COLORS.green, '✓', `One-time donation session created: ${oneTimeSession.id}`); console.log(` Status: ${oneTimeSession.status}`); console.log(` Amount: ${oneTimeSession.amount_total / 100} ${oneTimeSession.currency.toUpperCase()}`); // Clean up test session await stripe.checkout.sessions.expire(oneTimeSession.id); log(COLORS.cyan, 'ℹ', 'Test session expired (cleanup)'); } catch (error) { log(COLORS.red, '✗', `Failed to create one-time donation: ${error.message}`); allTestsPassed = false; } // Summary console.log('\n' + '═'.repeat(60)); if (allTestsPassed) { log(COLORS.green, '✅', 'All integration tests passed!'); console.log('\n📋 Next steps:'); console.log(' 1. Start local server: npm start'); console.log(' 2. Test donation form at: http://localhost:9000/koha.html'); console.log(' 3. Use test card: 4242 4242 4242 4242'); console.log(' 4. Set up webhooks: ./scripts/stripe-webhook-setup.sh'); } else { log(COLORS.red, '❌', 'Some tests failed. Please fix issues above.'); } console.log('═'.repeat(60) + '\n'); } catch (error) { log(COLORS.red, '✗', `Test suite error: ${error.message}`); console.error('\nFull error:', error); process.exit(1); } } // Run tests testStripeIntegration();