Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Payment Testing Tool</title> | |
| <!-- Tailwind CSS --> | |
| <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> | |
| <!-- Font Awesome --> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| <!-- Google Fonts --> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #635bff; | |
| --primary-light: #7a73ff; | |
| --primary-dark: #4b44d1; | |
| --secondary-color: #0a2540; | |
| --success-color: #3ecf8e; | |
| --warning-color: #f7b500; | |
| --danger-color: #e25950; | |
| --neutral-light: #f6f9fc; | |
| --neutral-medium: #e3e8ee; | |
| --neutral-dark: #697386; | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background-color: var(--neutral-light); | |
| color: var(--secondary-color); | |
| } | |
| .navbar { | |
| background-color: white; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| } | |
| .card { | |
| background-color: white; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); | |
| transition: all 0.3s; | |
| } | |
| .card:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 7px 14px rgba(50, 50, 93, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08); | |
| } | |
| .btn-primary { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border-radius: 6px; | |
| padding: 10px 20px; | |
| font-weight: 500; | |
| transition: all 0.2s; | |
| } | |
| .btn-primary:hover { | |
| background-color: var(--primary-light); | |
| } | |
| .btn-secondary { | |
| background-color: white; | |
| color: var(--secondary-color); | |
| border: 1px solid var(--neutral-medium); | |
| border-radius: 6px; | |
| padding: 10px 20px; | |
| font-weight: 500; | |
| transition: all 0.2s; | |
| } | |
| .btn-secondary:hover { | |
| background-color: var(--neutral-light); | |
| } | |
| .tab-active { | |
| border-bottom: 2px solid var(--primary-color); | |
| color: var(--primary-color); | |
| font-weight: 500; | |
| } | |
| .tab { | |
| padding: 10px 16px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .tab:hover:not(.tab-active) { | |
| color: var(--primary-light); | |
| } | |
| .test-card { | |
| border: 1px solid var(--neutral-medium); | |
| border-radius: 6px; | |
| padding: 12px; | |
| margin-bottom: 8px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .test-card:hover { | |
| border-color: var(--primary-color); | |
| background-color: rgba(99, 91, 255, 0.05); | |
| } | |
| .copy-btn { | |
| color: var(--neutral-dark); | |
| transition: all 0.2s; | |
| } | |
| .copy-btn:hover { | |
| color: var(--primary-color); | |
| } | |
| .badge { | |
| font-size: 0.75rem; | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| font-weight: 500; | |
| } | |
| .badge-success { | |
| background-color: rgba(62, 207, 142, 0.2); | |
| color: var(--success-color); | |
| } | |
| .badge-warning { | |
| background-color: rgba(247, 181, 0, 0.2); | |
| color: var(--warning-color); | |
| } | |
| .badge-danger { | |
| background-color: rgba(226, 89, 80, 0.2); | |
| color: var(--danger-color); | |
| } | |
| .badge-primary { | |
| background-color: rgba(99, 91, 255, 0.2); | |
| color: var(--primary-color); | |
| } | |
| .search-input { | |
| border: 1px solid var(--neutral-medium); | |
| border-radius: 6px; | |
| padding: 10px 16px; | |
| width: 100%; | |
| transition: all 0.2s; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 1px var(--primary-color); | |
| } | |
| .sidebar { | |
| background-color: white; | |
| border-right: 1px solid var(--neutral-medium); | |
| } | |
| .sidebar-item { | |
| padding: 10px 16px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| border-radius: 6px; | |
| margin: 4px 0; | |
| } | |
| .sidebar-item:hover { | |
| background-color: var(--neutral-light); | |
| } | |
| .sidebar-item.active { | |
| background-color: rgba(99, 91, 255, 0.1); | |
| color: var(--primary-color); | |
| font-weight: 500; | |
| } | |
| .code-block { | |
| background-color: var(--secondary-color); | |
| color: white; | |
| border-radius: 6px; | |
| padding: 16px; | |
| font-family: monospace; | |
| overflow-x: auto; | |
| } | |
| .slider { | |
| -webkit-appearance: none; | |
| width: 100%; | |
| height: 6px; | |
| border-radius: 5px; | |
| background: var(--neutral-medium); | |
| outline: none; | |
| -webkit-transition: .2s; | |
| transition: opacity .2s; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: var(--primary-color); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .slider::-webkit-slider-thumb:hover { | |
| transform: scale(1.1); | |
| box-shadow: 0 0 0 6px rgba(99, 91, 255, 0.2); | |
| } | |
| .slider::-moz-range-thumb { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: var(--primary-color); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .slider::-moz-range-thumb:hover { | |
| transform: scale(1.1); | |
| box-shadow: 0 0 0 6px rgba(99, 91, 255, 0.2); | |
| } | |
| /* Custom switch */ | |
| .switch { | |
| position: relative; | |
| display: inline-block; | |
| width: 48px; | |
| height: 24px; | |
| } | |
| .switch input { | |
| opacity: 0; | |
| width: 0; | |
| height: 0; | |
| } | |
| .slider-switch { | |
| position: absolute; | |
| cursor: pointer; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background-color: var(--neutral-medium); | |
| transition: .4s; | |
| border-radius: 24px; | |
| } | |
| .slider-switch:before { | |
| position: absolute; | |
| content: ""; | |
| height: 18px; | |
| width: 18px; | |
| left: 3px; | |
| bottom: 3px; | |
| background-color: white; | |
| transition: .4s; | |
| border-radius: 50%; | |
| } | |
| input:checked + .slider-switch { | |
| background-color: var(--primary-color); | |
| } | |
| input:checked + .slider-switch:before { | |
| transform: translateX(24px); | |
| } | |
| /* Tooltip */ | |
| .tooltip { | |
| position: relative; | |
| display: inline-block; | |
| } | |
| .tooltip .tooltip-text { | |
| visibility: hidden; | |
| width: 200px; | |
| background-color: var(--secondary-color); | |
| color: white; | |
| text-align: center; | |
| border-radius: 6px; | |
| padding: 8px; | |
| position: absolute; | |
| z-index: 1; | |
| bottom: 125%; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| font-size: 0.75rem; | |
| } | |
| .tooltip:hover .tooltip-text { | |
| visibility: visible; | |
| opacity: 1; | |
| } | |
| /* Responsive table */ | |
| .responsive-table { | |
| width: 100%; | |
| overflow-x: auto; | |
| } | |
| .responsive-table table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .responsive-table th { | |
| background-color: var(--neutral-light); | |
| padding: 12px; | |
| text-align: left; | |
| font-weight: 500; | |
| color: var(--neutral-dark); | |
| } | |
| .responsive-table td { | |
| padding: 12px; | |
| border-bottom: 1px solid var(--neutral-medium); | |
| } | |
| /* Animations */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.3s ease-in-out; | |
| } | |
| @keyframes slideIn { | |
| from { transform: translateY(10px); opacity: 0; } | |
| to { transform: translateY(0); opacity: 1; } | |
| } | |
| .slide-in { | |
| animation: slideIn 0.3s ease-in-out; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Navbar --> | |
| <nav class="navbar p-4 flex items-center justify-between"> | |
| <div class="flex items-center"> | |
| <div class="text-2xl font-bold text-primary-color flex items-center"> | |
| <i class="fas fa-credit-card mr-2 text-primary-color"></i> | |
| <span>Payment Testing Tool</span> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button class="btn-secondary"> | |
| <i class="fas fa-moon mr-2"></i> | |
| Dark Mode | |
| </button> | |
| <button class="btn-primary"> | |
| <i class="fas fa-code mr-2"></i> | |
| API Reference | |
| </button> | |
| </div> | |
| </nav> | |
| <!-- Main Content --> | |
| <div class="flex"> | |
| <!-- Sidebar --> | |
| <div class="sidebar w-64 h-screen sticky top-0 p-4 hidden md:block"> | |
| <div class="mb-6"> | |
| <div class="text-sm text-neutral-dark mb-2">TESTING</div> | |
| <div class="sidebar-item active"> | |
| <i class="fas fa-credit-card mr-2"></i> | |
| Card Testing | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-globe mr-2"></i> | |
| Payment Methods | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-exclamation-triangle mr-2"></i> | |
| Error Simulation | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-shield-alt mr-2"></i> | |
| 3D Secure | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-exchange-alt mr-2"></i> | |
| Webhooks | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <div class="text-sm text-neutral-dark mb-2">RESOURCES</div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-book mr-2"></i> | |
| Documentation | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-code mr-2"></i> | |
| API Reference | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-question-circle mr-2"></i> | |
| Help & Support | |
| </div> | |
| </div> | |
| <div> | |
| <div class="text-sm text-neutral-dark mb-2">SETTINGS</div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-cog mr-2"></i> | |
| Preferences | |
| </div> | |
| <div class="sidebar-item"> | |
| <i class="fas fa-key mr-2"></i> | |
| API Keys | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Content --> | |
| <div class="flex-1 p-6"> | |
| <div class="mb-8"> | |
| <h1 class="text-3xl font-bold mb-2">Payment Testing Tool</h1> | |
| <p class="text-neutral-dark">Simulate payments and test your integration without moving any money.</p> | |
| </div> | |
| <!-- Tabs --> | |
| <div class="flex border-b border-neutral-medium mb-6"> | |
| <div class="tab tab-active" onclick="switchTab('card-testing')">Card Testing</div> | |
| <div class="tab" onclick="switchTab('payment-methods')">Payment Methods</div> | |
| <div class="tab" onclick="switchTab('error-simulation')">Error Simulation</div> | |
| <div class="tab" onclick="switchTab('3d-secure')">3D Secure</div> | |
| </div> | |
| <!-- Card Testing Tab --> | |
| <div id="card-testing" class="tab-content slide-in"> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <!-- Left Column --> | |
| <div class="lg:col-span-2"> | |
| <div class="card p-6 mb-6"> | |
| <h2 class="text-xl font-semibold mb-4">Test Card Numbers</h2> | |
| <p class="mb-4">Use these card numbers to test different payment scenarios. Any future expiration date and any 3-digit CVC will work.</p> | |
| <!-- Search and Filter --> | |
| <div class="flex flex-col md:flex-row space-y-2 md:space-y-0 md:space-x-4 mb-4"> | |
| <div class="flex-1"> | |
| <input type="text" class="search-input" placeholder="Search cards..." id="card-search"> | |
| </div> | |
| <div> | |
| <select class="search-input" id="card-filter"> | |
| <option value="all">All Cards</option> | |
| <option value="brand">By Brand</option> | |
| <option value="country">By Country</option> | |
| <option value="scenario">By Scenario</option> | |
| </select> | |
| </div> | |
| </div> | |
| <!-- Cards by Brand --> | |
| <div class="mb-4"> | |
| <h3 class="text-lg font-medium mb-3">Cards by Brand</h3> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4242424242424242')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4242 4242 4242 4242</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-success mr-2">Success</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4242424242424242')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000056655665556')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (debit)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0566 5566 5556</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-success mr-2">Success</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000056655665556')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('5555555555554444')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.mastercard.us/content/dam/public/mastercardcom/na/us/en/homepage/Home/mc-logo-52.svg" alt="Mastercard" class="h-6 mr-2"> | |
| <span class="font-medium">Mastercard</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">5555 5555 5555 4444</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-success mr-2">Success</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('5555555555554444')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('378282246310005')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/217-2172284_transparent-amex-logo-american-express-black-logo-hd.png" alt="American Express" class="h-6 mr-2"> | |
| <span class="font-medium">American Express</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">3782 822463 10005</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-success mr-2">Success</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('378282246310005')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('6011111111111117')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/292-2924859_discover-network-logo-png-transparent-png.png" alt="Discover" class="h-6 mr-2"> | |
| <span class="font-medium">Discover</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">6011 1111 1111 1117</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-success mr-2">Success</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('6011111111111117')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Declined Payments --> | |
| <div class="mb-4"> | |
| <h3 class="text-lg font-medium mb-3">Declined Payments</h3> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000000000000002')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (Generic Decline)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0000 0000 0002</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-danger mr-2">Declined</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000000000000002')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000000000009995')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (Insufficient Funds)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0000 0000 9995</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-danger mr-2">Declined</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000000000009995')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000000000009987')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (Lost Card)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0000 0000 9987</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-danger mr-2">Declined</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000000000009987')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 3D Secure Authentication --> | |
| <div> | |
| <h3 class="text-lg font-medium mb-3">3D Secure Authentication</h3> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000002500003155')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (3DS Required)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0025 0000 3155</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-primary mr-2">3D Secure</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000002500003155')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="test-card flex justify-between items-center" onclick="copyToClipboard('4000002760003184')"> | |
| <div> | |
| <div class="flex items-center"> | |
| <img src="https://www.pngitem.com/pimgs/m/6-62449_visa-logo-png-transparent-visa-card-logo-png.png" alt="Visa" class="h-6 mr-2"> | |
| <span class="font-medium">Visa (3DS2 Frictionless)</span> | |
| </div> | |
| <div class="text-neutral-dark mt-1">4000 0027 6000 3184</div> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="badge badge-primary mr-2">3D Secure</span> | |
| <button class="copy-btn" onclick="event.stopPropagation(); copyToClipboard('4000002760003184')"> | |
| <i class="far fa-copy"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Column --> | |
| <div> | |
| <!-- Test Card Form --> | |
| <div class="card p-6 mb-6"> | |
| <h2 class="text-xl font-semibold mb-4">Test Payment Form</h2> | |
| <p class="mb-4">Enter a test card number to simulate a payment.</p> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium mb-2">Card Number</label> | |
| <input type="text" id="card-number" class="search-input" placeholder="4242 4242 4242 4242"> | |
| </div> | |
| <div class="grid grid-cols-2 gap-4 mb-4"> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">Expiration Date</label> | |
| <input type="text" class="search-input" placeholder="MM / YY"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">CVC</label> | |
| <input type="text" class="search-input" placeholder="123"> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium mb-2">Amount</label> | |
| <div class="relative"> | |
| <span class="absolute left-3 top-2.5 text-neutral-dark">$</span> | |
| <input type="text" class="search-input pl-8" placeholder="100.00"> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <label class="block text-sm font-medium mb-2">Currency</label> | |
| <select class="search-input"> | |
| <option>USD - US Dollar</option> | |
| <option>EUR - Euro</option> | |
| <option>GBP - British Pound</option> | |
| <option>JPY - Japanese Yen</option> | |
| </select> | |
| </div> | |
| <button class="btn-primary w-full" onclick="processPayment()"> | |
| <i class="fas fa-credit-card mr-2"></i> | |
| Process Payment | |
| </button> | |
| </div> | |
| <!-- Test Result --> | |
| <div class="card p-6" id="test-result" style="display: none;"> | |
| <h2 class="text-xl font-semibold mb-4">Test Result</h2> | |
| <div id="result-content"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Payment Methods Tab (Hidden by default) --> | |
| <div id="payment-methods" class="tab-content hidden"> | |
| <div class="card p-6 mb-6"> | |
| <h2 class="text-xl font-semibold mb-4">Payment Methods</h2> | |
| <p class="mb-4">Test different payment methods using these test values.</p> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium mb-3">ACH Direct Debit</h3> | |
| <div class="responsive-table"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Account Number</th> | |
| <th>Routing Number</th> | |
| <th>Result</th> | |
| <th>Action</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>000123456789</td> | |
| <td>110000000</td> | |
| <td><span class="badge badge-success">Success</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>000111111116</td> | |
| <td>110000000</td> | |
| <td><span class="badge badge-danger">Declined</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium mb-3">SEPA Direct Debit</h3> | |
| <div class="responsive-table"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>IBAN</th> | |
| <th>Result</th> | |
| <th>Action</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>DE89370400440532013000</td> | |
| <td><span class="badge badge-success">Success</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>DE62370400440532013001</td> | |
| <td><span class="badge badge-danger">Declined</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-medium mb-3">BACS Direct Debit</h3> | |
| <div class="responsive-table"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Account Number</th> | |
| <th>Sort Code</th> | |
| <th>Result</th> | |
| <th>Action</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>00012345</td> | |
| <td>108800</td> | |
| <td><span class="badge badge-success">Success</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>00012346</td> | |
| <td>108800</td> | |
| <td><span class="badge badge-danger">Declined</span></td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Error Simulation Tab (Hidden by default) --> | |
| <div id="error-simulation" class="tab-content hidden"> | |
| <div class="card p-6 mb-6"> | |
| <h2 class="text-xl font-semibold mb-4">Error Simulation</h2> | |
| <p class="mb-4">Simulate various error scenarios to test your error handling.</p> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium mb-3">API Errors</h3> | |
| <div class="responsive-table"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Error Type</th> | |
| <th>Test Value</th> | |
| <th>Description</th> | |
| <th>Action</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Card Declined</td> | |
| <td>4000000000000002</td> | |
| <td>Generic decline</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>Insufficient Funds</td> | |
| <td>4000000000009995</td> | |
| <td>Insufficient funds error</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>Processing Error</td> | |
| <td>4000000000009987</td> | |
| <td>Processing error</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>Incorrect CVC</td> | |
| <td>4000000000000127</td> | |
| <td>Incorrect CVC code</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>Expired Card</td> | |
| <td>4000000000000069</td> | |
| <td>Expired card error</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-medium mb-3">Rate Limiting</h3> | |
| <p class="mb-4">Simulate rate limiting errors by making multiple requests in quick succession.</p> | |
| <div class="flex items-center mb-4"> | |
| <div class="mr-4"> | |
| <label class="switch"> | |
| <input type="checkbox" id="rate-limit-toggle"> | |
| <span class="slider-switch"></span> | |
| </label> | |
| </div> | |
| <div> | |
| <div class="font-medium">Enable Rate Limit Simulation</div> | |
| <div class="text-sm text-neutral-dark">Simulates rate limiting after 3 consecutive requests</div> | |
| </div> | |
| </div> | |
| <button class="btn-primary" id="test-rate-limit"> | |
| <i class="fas fa-bolt mr-2"></i> | |
| Test Rate Limiting | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 3D Secure Tab (Hidden by default) --> | |
| <div id="3d-secure" class="tab-content hidden"> | |
| <div class="card p-6 mb-6"> | |
| <h2 class="text-xl font-semibold mb-4">3D Secure Authentication</h2> | |
| <p class="mb-4">Test 3D Secure authentication flows with these test cards.</p> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium mb-3">3D Secure 2 Test Cards</h3> | |
| <div class="responsive-table"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Card Number</th> | |
| <th>Authentication</th> | |
| <th>Description</th> | |
| <th>Action</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>4000002500003155</td> | |
| <td><span class="badge badge-primary">Challenge</span></td> | |
| <td>3DS authentication with challenge</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>4000002760003184</td> | |
| <td><span class="badge badge-success">Frictionless</span></td> | |
| <td>3DS authentication without challenge</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| <tr> | |
| <td>4000008260003178</td> | |
| <td><span class="badge badge-danger">Failed</span></td> | |
| <td>3DS authentication fails</td> | |
| <td><button class="copy-btn"><i class="far fa-copy"></i></button></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-medium mb-3">Test 3D Secure Authentication</h3> | |
| <p class="mb-4">Enter a 3D Secure test card to simulate the authentication flow.</p> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium mb-2">Card Number</label> | |
| <input type="text" id="3ds-card-number" class="search-input" placeholder="4000 0025 0000 3155"> | |
| </div> | |
| <div class="grid grid-cols-2 gap-4 mb-6"> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">Expiration Date</label> | |
| <input type="text" class="search-input" placeholder="MM / YY"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium mb-2">CVC</label> | |
| <input type="text" class="search-input" placeholder="123"> | |
| </div> | |
| </div> | |
| <button class="btn-primary w-full" onclick="test3DSecure()"> | |
| <i class="fas fa-shield-alt mr-2"></i> | |
| Test 3D Secure | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 3D Secure Modal --> | |
| <div id="3ds-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-lg p-6 max-w-md w-full"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-semibold">3D Secure Authentication</h3> | |
| <button onclick="close3DSModal()" class="text-neutral-dark hover:text-secondary-color"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="mb-6"> | |
| <p class="mb-4">Please complete the authentication to proceed with your payment.</p> | |
| <div class="bg-neutral-light p-4 rounded mb-4"> | |
| <div class="flex justify-between mb-2"> | |
| <span class="text-neutral-dark">Card:</span> | |
| <span class="font-medium" id="3ds-card-display">**** **** **** 3155</span> | |
| </div> | |
| <div class="flex justify-between"> | |
| <span class="text-neutral-dark">Amount:</span> | |
| <span class="font-medium">$100.00</span> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium mb-2">Authentication Code</label> | |
| <input type="text" class="search-input" placeholder="Enter code: 123456"> | |
| </div> | |
| </div> | |
| <div class="flex space-x-4"> | |
| <button class="btn-secondary flex-1" onclick="close3DSModal()">Cancel</button> | |
| <button class="btn-primary flex-1" onclick="complete3DSAuth()">Complete Authentication</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Switch tabs | |
| function switchTab(tabId) { | |
| // Hide all tab contents | |
| document.querySelectorAll('.tab-content').forEach(tab => { | |
| tab.classList.add('hidden'); | |
| }); | |
| // Remove active class from all tabs | |
| document.querySelectorAll('.tab').forEach(tab => { | |
| tab.classList.remove('tab-active'); | |
| }); | |
| // Show selected tab content | |
| document.getElementById(tabId).classList.remove('hidden'); | |
| document.getElementById(tabId).classList.add('slide-in'); | |
| // Add active class to selected tab | |
| document.querySelector(`.tab[onclick="switchTab('${tabId}')"]`).classList.add('tab-active'); | |
| } | |
| // Copy to clipboard | |
| function copyToClipboard(text) { | |
| navigator.clipboard.writeText(text).then(() => { | |
| // Show a temporary tooltip or notification | |
| alert('Copied to clipboard: ' + text); | |
| }); | |
| } | |
| // Process payment | |
| function processPayment() { | |
| const cardNumber = document.getElementById('card-number').value.replace(/\s/g, ''); | |
| let result = ''; | |
| // Show test result | |
| document.getElementById('test-result').style.display = 'block'; | |
| // Simulate different results based on card number | |
| if (cardNumber === '4242424242424242') { | |
| result = ` | |
| <div class="bg-green-50 border border-green-200 rounded p-4 mb-4"> | |
| <div class="flex items-center text-green-800 font-medium mb-2"> | |
| <i class="fas fa-check-circle mr-2"></i> | |
| Payment Successful | |
| </div> | |
| <p class="text-green-700">The payment was processed successfully.</p> | |
| </div> | |
| <div class="bg-neutral-light p-4 rounded"> | |
| <div class="grid grid-cols-2 gap-2"> | |
| <div class="text-neutral-dark">Transaction ID:</div> | |
| <div class="font-medium">ch_1NjK9L2eZvKYlo2C0A2Uvl7g</div> | |
| <div class="text-neutral-dark">Amount:</div> | |
| <div class="font-medium">$100.00</div> | |
| <div class="text-neutral-dark">Status:</div> | |
| <div class="font-medium">Succeeded</div> | |
| <div class="text-neutral-dark">Card:</div> | |
| <div class="font-medium">Visa **** 4242</div> | |
| </div> | |
| </div> | |
| `; | |
| } else if (cardNumber === '4000000000000002') { | |
| result = ` | |
| <div class="bg-red-50 border border-red-200 rounded p-4 mb-4"> | |
| <div class="flex items-center text-red-800 font-medium mb-2"> | |
| <i class="fas fa-exclamation-circle mr-2"></i> | |
| Payment Failed | |
| </div> | |
| <p class="text-red-700">Your card was declined.</p> | |
| </div> | |
| <div class="bg-neutral-light p-4 rounded"> | |
| <div class="grid grid-cols-2 gap-2"> | |
| <div class="text-neutral-dark">Error Code:</div> | |
| <div class="font-medium">card_declined</div> | |
| <div class="text-neutral-dark">Error Message:</div> | |
| <div class="font-medium">Your card was declined.</div> | |
| <div class="text-neutral-dark">Card:</div> | |
| <div class="font-medium">Visa **** 0002</div> | |
| </div> | |
| </div> | |
| `; | |
| } else if (cardNumber === '4000002500003155') { | |
| // Show 3D Secure modal | |
| show3DSModal('4000 0025 0000 3155'); | |
| return; | |
| } else { | |
| result = ` | |
| <div class="bg-yellow-50 border border-yellow-200 rounded p-4 mb-4"> | |
| <div class="flex items-center text-yellow-800 font-medium mb-2"> | |
| <i class="fas fa-exclamation-triangle mr-2"></i> | |
| Invalid Card | |
| </div> | |
| <p class="text-yellow-700">Please enter a valid test card number.</p> | |
| </div> | |
| `; | |
| } | |
| document.getElementById('result-content').innerHTML = result; | |
| } | |
| // 3D Secure functions | |
| function test3DSecure() { | |
| const cardNumber = document.getElementById('3ds-card-number').value.replace(/\s/g, ''); | |
| if (cardNumber === '4000002500003155' || cardNumber === '4000002760003184') { | |
| show3DSModal(cardNumber); | |
| } else { | |
| alert('Please enter a valid 3D Secure test card number.'); | |
| } | |
| } | |
| function show3DSModal(cardNumber) { | |
| // Format card number for display | |
| const formattedCard = cardNumber.replace(/(\d{4})/g, '$1 ').trim(); | |
| document.getElementById('3ds-card-display').textContent = formattedCard; | |
| // Show modal | |
| document.getElementById('3ds-modal').classList.remove('hidden'); | |
| } | |
| function close3DSModal() { | |
| document.getElementById('3ds-modal').classList.add('hidden'); | |
| } | |
| function complete3DSAuth() { | |
| close3DSModal(); | |
| // Show success result | |
| document.getElementById('test-result').style.display = 'block'; | |
| document.getElementById('result-content').innerHTML = ` | |
| <div class="bg-green-50 border border-green-200 rounded p-4 mb-4"> | |
| <div class="flex items-center text-green-800 font-medium mb-2"> | |
| <i class="fas fa-check-circle mr-2"></i> | |
| 3D Secure Authentication Successful | |
| </div> | |
| <p class="text-green-700">The payment was authenticated and processed successfully.</p> | |
| </div> | |
| <div class="bg-neutral-light p-4 rounded"> | |
| <div class="grid grid-cols-2 gap-2"> | |
| <div class="text-neutral-dark">Transaction ID:</div> | |
| <div class="font-medium">ch_1NjK9L2eZvKYlo2C0A2Uvl7g</div> | |
| <div class="text-neutral-dark">Amount:</div> | |
| <div class="font-medium">$100.00</div> | |
| <div class="text-neutral-dark">Status:</div> | |
| <div class="font-medium">Succeeded</div> | |
| <div class="text-neutral-dark">Authentication:</div> | |
| <div class="font-medium">3D Secure</div> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| // Rate limiting test | |
| document.getElementById('test-rate-limit').addEventListener('click', function() { | |
| const isEnabled = document.getElementById('rate-limit-toggle').checked; | |
| if (isEnabled) { | |
| let count = 0; | |
| const interval = setInterval(() => { | |
| count++; | |
| if (count < 3) { | |
| alert(`Request ${count} successful`); | |
| } else { | |
| clearInterval(interval); | |
| alert('Rate limit exceeded. Too many requests in a short period.'); | |
| } | |
| }, 500); | |
| } else { | |
| alert('Please enable rate limit simulation first.'); | |
| } | |
| }); | |
| // Card search functionality | |
| document.getElementById('card-search').addEventListener('input', function() { | |
| const searchTerm = this.value.toLowerCase(); | |
| const cards = document.querySelectorAll('.test-card'); | |
| cards.forEach(card => { | |
| const cardText = card.textContent.toLowerCase(); | |
| if (cardText.includes(searchTerm)) { | |
| card.style.display = 'flex'; | |
| } else { | |
| card.style.display = 'none'; | |
| } | |
| }); | |
| }); | |
| // Initialize | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Start with card testing tab active | |
| switchTab('card-testing'); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |