import { Client, Databases, Query } from 'node-appwrite'; import Stripe from 'stripe'; // Load environment variables const requiredEnvVars = [ 'APPWRITE_ENDPOINT', 'APPWRITE_PROJECT_ID', 'APPWRITE_API_KEY', 'APPWRITE_DATABASE_ID', 'STRIPE_SECRET_KEY' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { console.error(`โŒ Missing required environment variable: ${envVar}`); process.exit(1); } } const client = new Client() .setEndpoint(process.env.APPWRITE_ENDPOINT) .setProject(process.env.APPWRITE_PROJECT_ID) .setKey(process.env.APPWRITE_API_KEY); const databases = new Databases(client); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); console.log('๐Ÿงช Starting End-to-End Test\n'); // Test 1: Load Questions console.log('Test 1: Loading questions from Appwrite...'); try { const productsResponse = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'products', [Query.equal('slug', 'email-sorter'), Query.equal('isActive', true)] ); if (productsResponse.documents.length === 0) { console.error('โŒ No active product found with slug "email-sorter"'); process.exit(1); } const product = productsResponse.documents[0]; console.log(`โœ… Product found: ${product.title} (${product.priceCents / 100} ${product.currency.toUpperCase()})`); const questionsResponse = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'questions', [ Query.equal('productId', product.$id), Query.equal('isActive', true), Query.orderAsc('step'), Query.orderAsc('order') ] ); console.log(`โœ… Loaded ${questionsResponse.documents.length} questions`); // Verify questions are ordered correctly let lastStep = 0; let lastOrder = 0; for (const question of questionsResponse.documents) { if (question.step < lastStep || (question.step === lastStep && question.order < lastOrder)) { console.error('โŒ Questions are not properly ordered'); process.exit(1); } lastStep = question.step; lastOrder = question.order; } console.log('โœ… Questions are properly ordered by step and order'); // Test 2: Create Submission console.log('\nTest 2: Creating submission with test answers...'); const testAnswers = { email: 'test@example.com', name: 'Test User', company: 'Test Company', employees: '1-10', emailVolume: '100-500', currentProvider: 'Gmail', painPoints: ['Spam', 'Organization'], budget: '50-100', timeline: 'Sofort', features: ['Auto-Sorting', 'Priority Inbox'], integration: 'Ja', dataPrivacy: 'Sehr wichtig', additionalInfo: 'This is a test submission' }; const submission = await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', 'unique()', { productId: product.$id, status: 'draft', customerEmail: testAnswers.email, customerName: testAnswers.name, finalSummaryJson: JSON.stringify(testAnswers), priceCents: product.priceCents, currency: product.currency } ); console.log(`โœ… Submission created with ID: ${submission.$id}`); // Test 3: Save Answers console.log('\nTest 3: Saving answers to Appwrite...'); const answer = await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'answers', 'unique()', { submissionId: submission.$id, answersJson: JSON.stringify(testAnswers) } ); console.log(`โœ… Answers saved with ID: ${answer.$id}`); // Verify answers can be retrieved const retrievedAnswers = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'answers', [Query.equal('submissionId', submission.$id)] ); if (retrievedAnswers.documents.length === 0) { console.error('โŒ Failed to retrieve saved answers'); process.exit(1); } const savedAnswers = JSON.parse(retrievedAnswers.documents[0].answersJson); if (savedAnswers.email !== testAnswers.email) { console.error('โŒ Retrieved answers do not match saved answers'); process.exit(1); } console.log('โœ… Answers can be retrieved correctly'); // Test 4: Create Stripe Checkout Session console.log('\nTest 4: Creating Stripe checkout session...'); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [ { price_data: { currency: submission.currency, product_data: { name: 'Email Sortierer Service', }, unit_amount: submission.priceCents, }, quantity: 1, }, ], mode: 'payment', success_url: `http://localhost:3000/success.html`, cancel_url: `http://localhost:3000/cancel.html`, metadata: { submissionId: submission.$id } }); console.log(`โœ… Stripe session created: ${session.id}`); console.log(` Checkout URL: ${session.url}`); // Test 5: Verify Webhook Signature (simulated) console.log('\nTest 5: Verifying webhook signature validation...'); if (!process.env.STRIPE_WEBHOOK_SECRET) { console.log('โš ๏ธ STRIPE_WEBHOOK_SECRET not set - skipping webhook signature test'); } else { console.log('โœ… Webhook secret is configured'); console.log(' Note: Actual webhook testing requires Stripe CLI or real webhook events'); } // Test 6: Simulate Payment Completion (update submission status) console.log('\nTest 6: Simulating payment completion...'); const updatedSubmission = await databases.updateDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', submission.$id, { status: 'paid' } ); if (updatedSubmission.status !== 'paid') { console.error('โŒ Failed to update submission status'); process.exit(1); } console.log('โœ… Submission status updated to "paid"'); // Create order record const order = await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'orders', 'unique()', { submissionId: submission.$id, orderDataJson: JSON.stringify({ sessionId: session.id, testOrder: true }) } ); console.log(`โœ… Order record created with ID: ${order.$id}`); // Test 7: Verify Complete Data Flow console.log('\nTest 7: Verifying complete data flow...'); const finalSubmission = await databases.getDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', submission.$id ); const finalAnswers = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'answers', [Query.equal('submissionId', submission.$id)] ); const finalOrders = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'orders', [Query.equal('submissionId', submission.$id)] ); console.log('โœ… Data verification:'); console.log(` - Submission status: ${finalSubmission.status}`); console.log(` - Answers records: ${finalAnswers.documents.length}`); console.log(` - Order records: ${finalOrders.documents.length}`); if (finalSubmission.status !== 'paid') { console.error('โŒ Submission status is not "paid"'); process.exit(1); } if (finalAnswers.documents.length === 0) { console.error('โŒ No answers found for submission'); process.exit(1); } if (finalOrders.documents.length === 0) { console.error('โŒ No orders found for submission'); process.exit(1); } console.log('\nโœ… All tests passed!'); console.log('\n๐Ÿ“Š Test Summary:'); console.log(' โœ… Questions loaded and ordered correctly'); console.log(' โœ… Submission created successfully'); console.log(' โœ… Answers saved and retrieved correctly'); console.log(' โœ… Stripe checkout session created'); console.log(' โœ… Webhook configuration verified'); console.log(' โœ… Payment completion simulated'); console.log(' โœ… Complete data flow verified'); console.log('\n๐ŸŽ‰ End-to-End test completed successfully!'); } catch (error) { console.error('\nโŒ Test failed with error:'); console.error(error); process.exit(1); }