Skip to content

Commit b45b599

Browse files
committed
feat(online-payments): test cards for sandboxes
1 parent a87530f commit b45b599

4 files changed

Lines changed: 912 additions & 0 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
import { getIconURL } from "@sumup-oss/icons";
3+
import { testCards } from "../../lib/testCards";
4+
5+
const successCards = testCards.filter((card) => !card.error && !card.challenge);
6+
const challengeCards = testCards.filter((card) => card.challenge);
7+
const errorCards = testCards.filter((card) => card.error);
8+
9+
const sections = [
10+
{ title: "Successful Transactions", cards: successCards },
11+
{ title: "3DS Challenge Flows", cards: challengeCards },
12+
{ title: "Error Cases", cards: errorCards },
13+
];
14+
---
15+
16+
<div class="test-cards">
17+
{
18+
sections.map(({ title, cards }) => (
19+
<div class="test-cards-section">
20+
<h2 class="test-cards-section-title">{title}</h2>
21+
<div class="test-cards-list">
22+
{cards.map((card) => (
23+
<div class="test-card">
24+
<div class="test-card-header">
25+
<img
26+
src={getIconURL(card.brand, "24")}
27+
alt={card.brand}
28+
class="test-card-brand-icon"
29+
/>
30+
<span class="test-card-name">{card.name}</span>
31+
{card.returnsMethodData && (
32+
<span class="test-card-badge">Method Data</span>
33+
)}
34+
</div>
35+
<div class="test-card-number-wrapper">
36+
<code class="test-card-number">{card.number}</code>
37+
<button
38+
class="test-card-copy"
39+
data-number={card.number.replace(/\s/g, "")}
40+
aria-label="Copy card number"
41+
>
42+
📋
43+
</button>
44+
</div>
45+
<p class="test-card-description">{card.description}</p>
46+
</div>
47+
))}
48+
</div>
49+
</div>
50+
))
51+
}
52+
</div>
53+
54+
<style>
55+
.test-cards {
56+
display: flex;
57+
flex-direction: column;
58+
gap: 3rem;
59+
margin: 2rem 0;
60+
}
61+
62+
.test-cards-section {
63+
display: flex;
64+
flex-direction: column;
65+
gap: 1.5rem;
66+
}
67+
68+
.test-cards-section-title {
69+
font-size: 1.75rem;
70+
font-weight: 600;
71+
margin: 0;
72+
padding-bottom: 0.5rem;
73+
border-bottom: 2px solid var(--sl-color-gray-5);
74+
}
75+
76+
.test-cards-list {
77+
display: grid;
78+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
79+
gap: 1rem;
80+
}
81+
82+
.test-card {
83+
display: flex;
84+
flex-direction: column;
85+
gap: 0.5rem;
86+
padding: 1rem;
87+
border: 1px solid var(--sl-color-gray-5);
88+
border-radius: 0.5rem;
89+
background-color: var(--sl-color-bg-nav);
90+
transition: border-color 0.2s ease;
91+
}
92+
93+
.test-card:hover {
94+
border-color: var(--sl-color-text-accent);
95+
}
96+
97+
.test-card-header {
98+
display: flex;
99+
align-items: center;
100+
gap: 0.5rem;
101+
}
102+
103+
.test-card-brand-icon {
104+
width: 1.5rem;
105+
height: 1.5rem;
106+
object-fit: contain;
107+
flex-shrink: 0;
108+
}
109+
110+
.test-card-name {
111+
font-weight: 600;
112+
font-size: 0.9rem;
113+
color: var(--sl-color-white);
114+
flex: 1;
115+
}
116+
117+
.test-card-badge {
118+
font-size: 0.75rem;
119+
padding: 0.25rem 0.5rem;
120+
border-radius: 0.25rem;
121+
background-color: var(--sl-color-gray-6);
122+
color: var(--sl-color-gray-2);
123+
white-space: nowrap;
124+
}
125+
126+
.test-card-number-wrapper {
127+
position: relative;
128+
display: flex;
129+
align-items: center;
130+
gap: 0.5rem;
131+
}
132+
133+
.test-card-number {
134+
font-family: var(--sl-font-mono);
135+
font-size: 1rem;
136+
font-weight: 600;
137+
padding: 0.5rem;
138+
background-color: var(--sl-color-gray-7);
139+
border-radius: 0.25rem;
140+
letter-spacing: 0.05em;
141+
user-select: all;
142+
flex: 1;
143+
}
144+
145+
.test-card-copy {
146+
position: absolute;
147+
right: 0.5rem;
148+
padding: 0.25rem 0.5rem;
149+
background-color: var(--sl-color-gray-6);
150+
border: 1px solid var(--sl-color-gray-5);
151+
border-radius: 0.25rem;
152+
cursor: pointer;
153+
font-size: 0.875rem;
154+
opacity: 0;
155+
transition: opacity 0.2s ease;
156+
}
157+
158+
.test-card-number-wrapper:hover .test-card-copy {
159+
opacity: 1;
160+
}
161+
162+
.test-card-copy:hover {
163+
background-color: var(--sl-color-gray-5);
164+
}
165+
166+
.test-card-description {
167+
font-size: 0.875rem;
168+
color: var(--sl-color-gray-2);
169+
margin: 0;
170+
line-height: 1.5;
171+
}
172+
</style>
173+
174+
<script>
175+
document.addEventListener("DOMContentLoaded", () => {
176+
const copyButtons = document.querySelectorAll(".test-card-copy");
177+
178+
copyButtons.forEach((button) => {
179+
button.addEventListener("click", async () => {
180+
const number = button.getAttribute("data-number");
181+
if (!number) return;
182+
183+
try {
184+
await navigator.clipboard.writeText(number);
185+
const originalText = button.textContent;
186+
button.textContent = "✓";
187+
setTimeout(() => {
188+
button.textContent = originalText;
189+
}, 2000);
190+
} catch (err) {
191+
console.error("Failed to copy:", err);
192+
}
193+
});
194+
});
195+
});
196+
</script>

src/components/TestCards/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as TestCards } from "./TestCards.astro";
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
title: Testing
3+
description: Learn how to test online payments using sandbox accounts and test cards with different 3D Secure flows.
4+
sidebar:
5+
order: 6
6+
---
7+
8+
import { Aside, Steps } from '@astrojs/starlight/components';
9+
import { TestCards } from '@components/TestCards';
10+
11+
Testing your online payments integration is crucial before going live. SumUp provides sandbox test accounts and a comprehensive set of test cards to simulate various payment scenarios, including different 3D Secure authentication flows.
12+
13+
## Setting up a Test Account
14+
15+
Before you can test online payments, you need to create a test account in the SumUp Dashboard.
16+
17+
<Steps>
18+
19+
1. Log in to your SumUp account.
20+
21+
2. Open the drop-down menu between Support and your user panel.
22+
23+
3. Select **Test Account**. Your merchant account is now switched to test mode.
24+
25+
</Steps>
26+
27+
<Aside type="note">
28+
Test accounts **do not** process transactions with real funds. All transactions are simulated for testing purposes only.
29+
</Aside>
30+
31+
## Test Card Details
32+
33+
When testing with card payments, you can use the following common details for all test cards:
34+
35+
- **CVV**: Any 3 digits (e.g., `123`)
36+
- **Expiry Date**: Any future date (e.g., `12/25`)
37+
- **Cardholder Name**: Any name
38+
39+
## Testing Failed Transactions
40+
41+
To test failed transactions with your test account, create a checkout with an amount of `11` in any currency. This will always result in a failed transaction, allowing you to test your error handling logic.
42+
43+
<Aside type="tip">
44+
Example: A checkout amount of `11.00 EUR` or `11.00 USD` will always fail.
45+
</Aside>
46+
47+
## Test Cards by Card Scheme
48+
49+
Use the test cards below to simulate different payment scenarios and 3D Secure flows. Each card is designed to trigger specific authentication behaviors:
50+
51+
- **Frictionless**: Authentication completes without user interaction
52+
- **Challenge**: Requires user authentication (e.g., entering a code or using biometrics)
53+
- **Error**: Simulates various error conditions
54+
55+
<TestCards />
56+
57+
## Understanding 3D Secure Test Responses
58+
59+
When testing with these cards, you'll encounter different 3D Secure transaction statuses:
60+
61+
- **TransactionStatus=Y**: Authentication successful
62+
- **TransactionStatus=A**: Authentication attempted (issuer or cardholder not participating)
63+
- **TransactionStatus=N**: Authentication failed
64+
- **TransactionStatus=U**: Technical error during authentication
65+
66+
The **ECI (Electronic Commerce Indicator)** values vary by card scheme:
67+
- **ECI=05**: Full authentication (Visa, Amex, Discover, JCB)
68+
- **ECI=02**: Full authentication (Mastercard, Maestro)
69+
- **ECI=06**: Attempted authentication (Visa, Amex, Discover, JCB)
70+
- **ECI=01**: Attempted authentication (Mastercard, Maestro)
71+
72+
## Next Steps
73+
74+
Once you've thoroughly tested your integration with sandbox accounts and test cards:
75+
76+
1. Switch back to your live account in the Dashboard
77+
2. Ensure your production credentials are properly configured
78+
3. Process a small real transaction to verify everything works as expected
79+
4. Monitor your first transactions closely to ensure proper payment processing
80+
81+
<Aside type="caution">
82+
Remember to switch from your test account to your live account before accepting real payments from customers.
83+
</Aside>

0 commit comments

Comments
 (0)