agmission/Development/server/tests/test_multi_subscription_auth.js

144 lines
5.9 KiB
JavaScript

// tests/test_multi_subscription_auth.js
const path = require('path');
require('dotenv').config({ path: path.resolve(process.cwd(), 'environment.env') });
const stripe = require('stripe')(process.env.STRIPE_SEC_KEY);
const { IntentStatus } = require('../model/subscription');
async function testDoubleCallAuth() {
console.log('🧪 Testing Multi-Subscription 3DS Behavior\n');
// Create customer first
const customer = await stripe.customers.create({
email: 'test-multi-3ds@example.com'
});
console.log('✅ Customer created:', customer.id);
// Create a fresh payment method with 3DS card
const paymentMethod = await stripe.paymentMethods.create({
type: 'card',
card: {
number: '4000002500003155', // 3DS required card
exp_month: 12,
exp_year: 2030,
cvc: '123'
}
});
console.log('✅ Payment method created:', paymentMethod.id);
// Attach to customer
await stripe.paymentMethods.attach(paymentMethod.id, {
customer: customer.id
});
console.log('✅ Payment method attached to customer\n');
// First subscription - Package (will require 3DS)
console.log('📦 Creating FIRST subscription (Package)...');
const sub1 = await stripe.subscriptions.create({
customer: customer.id,
items: [{ price: process.env.ESS_1 }],
default_payment_method: paymentMethod.id,
expand: ['latest_invoice.payment_intent'],
payment_behavior: 'default_incomplete',
metadata: { type: 'package' }
});
const pi1 = sub1.latest_invoice.payment_intent;
console.log(` Subscription: ${sub1.id}, Status: ${sub1.status}`);
console.log(` PaymentIntent: ${pi1.id}, Status: ${pi1.status}`);
console.log(` Requires 3DS: ${pi1.status === IntentStatus.REQUIRES_ACTION}\n`);
// Backend confirms payment intent if requires_confirmation
if (pi1.status === IntentStatus.REQUIRES_CONFIRMATION) {
console.log('🔄 Confirming payment intent (backend logic)...');
const confirmedPi1 = await stripe.paymentIntents.confirm(pi1.id, {
return_url: 'http://localhost:4100/payment-complete'
});
console.log(` Status after confirmation: ${confirmedPi1.status}\n`);
if (confirmedPi1.status === IntentStatus.REQUIRES_ACTION) {
console.log('🔐 3DS required for package subscription');
console.log(' Backend would return client_secret to frontend');
console.log(' (In real flow, frontend would use stripe.confirmCardPayment())');
console.log(' NOTE: Cannot simulate 3DS completion in backend-only test\n');
}
} else if (pi1.status === IntentStatus.REQUIRES_ACTION) {
console.log('🔐 3DS required for package subscription');
console.log(' (In real flow, frontend would use stripe.confirmCardPayment())');
console.log(' NOTE: Cannot simulate 3DS completion in backend-only test\n');
}
// Verify package is active
const sub1Updated = await stripe.subscriptions.retrieve(sub1.id);
console.log(`✅ Package subscription: ${sub1Updated.status}\n`);
// Second subscription - Addon (with SAME payment method, minutes later)
console.log('📦 Creating SECOND subscription (Addon) with SAME card...');
console.log(' (Simulating second /update call)\n');
const sub2 = await stripe.subscriptions.create({
customer: customer.id,
items: [{ price: process.env.ADDON_1, quantity: 1 }],
default_payment_method: paymentMethod.id,
expand: ['latest_invoice.payment_intent'],
payment_behavior: 'default_incomplete',
metadata: { type: 'addon' }
});
const pi2 = sub2.latest_invoice.payment_intent;
console.log(` Subscription: ${sub2.id}, Status: ${sub2.status}`);
console.log(` PaymentIntent: ${pi2.id}, Status: ${pi2.status}`);
let addonRequires3DS = false;
let confirmedPi2 = pi2;
// Backend confirms payment intent if requires_confirmation
if (pi2.status === 'requires_confirmation') {
console.log('🔄 Confirming payment intent (backend logic)...');
confirmedPi2 = await stripe.paymentIntents.confirm(pi2.id, {
payment_method: paymentMethod.id
});
console.log(` Status after confirmation: ${confirmedPi2.status}\n`);
if (confirmedPi2.status === IntentStatus.REQUIRES_ACTION) {
addonRequires3DS = true;
console.log('⚠️ ANSWER: YES - Second subscription REQUIRES 3DS AGAIN!');
console.log(' Even though same card was just used.');
console.log(' Each PaymentIntent is independent.\n');
} else {
console.log('✅ ANSWER: NO - Authentication was reused!\n');
}
} else if (pi2.status === IntentStatus.REQUIRES_ACTION) {
addonRequires3DS = true;
console.log('⚠️ ANSWER: YES - Second subscription requires 3DS\n');
} else {
console.log(`✅ ANSWER: NO - Addon status is ${pi2.status}\n`);
}
// === RESULT SUMMARY ===
console.log('\n📊 Test Results:');
console.log(` ✅ Package subscription: required 3DS`);
console.log(` ${addonRequires3DS ? '⚠️' : '✅'} Addon subscription: ${addonRequires3DS ? 'REQUIRES 3DS AGAIN' : 'no 3DS needed'}`);
if (addonRequires3DS) {
console.log('\n💡 Conclusion:');
console.log(' Each subscription creates a separate PaymentIntent.');
console.log(' Even when using the same payment method immediately after,');
console.log(' Stripe does NOT reuse 3DS authentication between PaymentIntents.');
console.log(' Frontend must handle 3DS for EACH subscription.');
}
// Check the subscription statuses for both
const sub1Final = await stripe.subscriptions.retrieve(sub1.id);
console.log(`\n✅ Final Package subscription status: ${sub1Final.status}`);
const sub2Updated = await stripe.subscriptions.retrieve(sub2.id);
console.log(`\n✅ Addon subscription: ${sub2Updated.status}`);
// Cleanup
await stripe.subscriptions.del(sub1.id);
await stripe.subscriptions.del(sub2.id);
await stripe.customers.del(customer.id);
console.log('\n🧹 Cleaned up test data');
}
testDoubleCallAuth().catch(console.error);