Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что тестировать в платёжной системе
Оплата - это критическая часть приложения, которая требует наиболее тщательного тестирования. Любая ошибка может привести к потере денег клиентов или потере доходов компании.
Базовые сценарии оплаты
Первый уровень тестирования - проверка основных flow:
describe('Payment Flow', () => {
// ВАЖНО: Успешная оплата
it('should complete successful payment', async () => {
const paymentData = {
cardNumber: '4242424242424242',
expiryDate: '12/25',
cvv: '123',
amount: 100,
currency: 'USD',
};
const result = await processPayment(paymentData);
expect(result.status).toBe('success');
expect(result.transactionId).toBeDefined();
expect(result.amount).toBe(100);
});
// КРИТИЧНО: Отклонённая карта
it('should handle declined card', async () => {
const paymentData = {
cardNumber: '4000000000000002', // Declined card
expiryDate: '12/25',
cvv: '123',
amount: 100,
};
const result = await processPayment(paymentData);
expect(result.status).toBe('failed');
expect(result.error).toBe('Card declined');
// Убедиться, что деньги не списаны
const transaction = await getTransaction(result.transactionId);
expect(transaction.status).toBe('failed');
});
// КРИТИЧНО: Истёкшая карта
it('should reject expired card', async () => {
const paymentData = {
cardNumber: '4242424242424242',
expiryDate: '01/20', // Expired
cvv: '123',
amount: 100,
};
const result = await processPayment(paymentData);
expect(result.error).toContain('expired');
expect(result.status).toBe('failed');
});
});
Валидация данных перед оплатой
describe('Payment Validation', () => {
// Валидация номера карты (Luhn algorithm)
it('should validate card number', () => {
expect(isValidCardNumber('4242424242424242')).toBe(true);
expect(isValidCardNumber('1234567890123456')).toBe(false);
expect(isValidCardNumber('424242424242424')).toBe(false); // Too short
});
// Валидация срока действия
it('should validate expiry date', () => {
const futureDate = '12/26';
const pastDate = '12/20';
expect(isValidExpiryDate(futureDate)).toBe(true);
expect(isValidExpiryDate(pastDate)).toBe(false);
});
// Валидация CVV
it('should validate CVV', () => {
expect(isValidCVV('123')).toBe(true);
expect(isValidCVV('12')).toBe(false); // Too short
expect(isValidCVV('abcd')).toBe(false); // Not a number
});
// Валидация суммы
it('should validate payment amount', () => {
expect(isValidAmount(0.01)).toBe(true); // Минимум
expect(isValidAmount(0)).toBe(false);
expect(isValidAmount(-100)).toBe(false);
expect(isValidAmount(999999999)).toBe(true);
});
});
Обработка ошибок и edge cases
describe('Payment Error Handling', () => {
// Timeout при платеже
it('should handle payment timeout', async () => {
jest.useFakeTimers();
const paymentPromise = processPayment(validPaymentData);
jest.advanceTimersByTime(31000); // Timeout 30s
const result = await paymentPromise;
expect(result.error).toContain('timeout');
expect(result.status).toBe('timeout');
// Проверить, что запрос в очереди повтора
const pendingTransaction = await getPendingTransaction();
expect(pendingTransaction).toBeDefined();
});
// Недостаточно средств
it('should handle insufficient funds', async () => {
const result = await processPayment({
...validPaymentData,
amount: 999999999,
});
expect(result.error).toContain('Insufficient funds');
expect(result.status).toBe('failed');
});
// 3D Secure / 2FA
it('should handle 3D Secure authentication', async () => {
const result = await processPayment(validPaymentData);
if (result.requires3DSecure) {
expect(result.authUrl).toBeDefined();
// Пользователь прошёл аутентификацию
const authResult = await complete3DSecure(result.authUrl);
expect(authResult.status).toBe('success');
}
});
// Сетевая ошибка
it('should retry on network failure', async () => {
let attempts = 0;
jest.spyOn(api, 'processPayment').mockImplementation(async () => {
attempts++;
if (attempts < 3) throw new Error('Network error');
return { status: 'success', transactionId: '123' };
});
const result = await processPaymentWithRetry(validPaymentData);
expect(result.status).toBe('success');
expect(attempts).toBe(3);
});
});
Проверка интеграции с БД
describe('Payment Database Integration', () => {
// Транзакция создана в БД
it('should create transaction record', async () => {
const paymentData = validPaymentData;
const result = await processPayment(paymentData);
const transaction = await db.transactions.findById(result.transactionId);
expect(transaction).toBeDefined();
expect(transaction.amount).toBe(paymentData.amount);
expect(transaction.status).toBe('completed');
expect(transaction.createdAt).toBeDefined();
});
// Идемпотентность платежа
it('should prevent duplicate charges', async () => {
const idempotencyKey = 'unique-key-123';
// Первый платёж
const result1 = await processPayment(validPaymentData, {
idempotencyKey,
});
// Повторный платёж с тем же ключом
const result2 = await processPayment(validPaymentData, {
idempotencyKey,
});
// Должны получить один и тот же результат
expect(result1.transactionId).toBe(result2.transactionId);
// В БД только одна транзакция
const transactions = await db.transactions.findByIdempotencyKey(
idempotencyKey
);
expect(transactions.length).toBe(1);
});
// Возврат средств
it('should refund payment correctly', async () => {
const result = await processPayment(validPaymentData);
const transactionId = result.transactionId;
// Проверяем исходное состояние
let transaction = await db.transactions.findById(transactionId);
expect(transaction.status).toBe('completed');
expect(transaction.amount).toBe(100);
// Запрашиваем возврат
const refundResult = await refundPayment(transactionId);
// Проверяем что возврат записан
transaction = await db.transactions.findById(transactionId);
expect(transaction.status).toBe('refunded');
expect(transaction.refundedAmount).toBe(100);
expect(transaction.refundedAt).toBeDefined();
});
});
Security тесты
describe('Payment Security', () => {
// Карточные данные не логируются
it('should never log sensitive data', () => {
const consoleSpy = jest.spyOn(console, 'log');
processPayment({
cardNumber: '4242424242424242',
cvv: '123',
});
expect(consoleSpy).not.toHaveBeenCalledWith(
expect.stringContaining('4242')
);
expect(consoleSpy).not.toHaveBeenCalledWith(
expect.stringContaining('123')
);
});
// PCI DSS compliance
it('should use HTTPS and encryption', async () => {
const request = await capturePaymentRequest();
expect(request.url).toMatch(/^https:\/\//);
});
// CSRF protection
it('should include CSRF token', async () => {
const csrfToken = getCSRFToken();
expect(csrfToken).toBeDefined();
const result = await processPayment(validPaymentData, {
csrfToken,
});
expect(result.status).toBe('success');
});
});
Контрольный список тестирования платежей
- Успешная оплата работает
- Отклонённая карта обрабатывается
- Истёкшая карта обрабатывается
- Валидация номера карты (Luhn)
- Валидация срока действия
- Валидация CVV
- Обработка timeout
- Retry механизм работает
- 3D Secure поддерживается
- Идемпотентность гарантирована
- Возвраты работают корректно
- Чувствительные данные не логируются
- Используется HTTPS
- Транзакции записываются в БД
- Аудит логируется для compliance
Платёжные системы требуют наивысшего уровня тестирования - здесь не может быть ошибок.