fix: add retry to getPayment, normalize return, env validation, webhook/builder tests
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createPayment, getPayment } from '../yookassa.js'
|
||||
import { createPayment, getPayment, buildReceipt, validateWebhook } from '../yookassa.js'
|
||||
|
||||
describe('yookassa createPayment', () => {
|
||||
beforeEach(() => {
|
||||
@@ -157,8 +157,111 @@ describe('yookassa getPayment', () => {
|
||||
const result = await getPayment('payment-id')
|
||||
expect(fetch).toHaveBeenCalledTimes(1)
|
||||
expect(fetch.mock.calls[0][0]).toBe('https://api.yookassa.ru/v3/payments/payment-id')
|
||||
expect(result.id).toBe('payment-id')
|
||||
expect(result.paymentId).toBe('payment-id')
|
||||
expect(result.status).toBe('succeeded')
|
||||
expect(result.paid).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('yookassa buildReceipt', () => {
|
||||
it('builds receipt with order items', () => {
|
||||
const result = buildReceipt({
|
||||
orderItems: [
|
||||
{ titleSnapshot: 'Test Product', qty: 2, priceCentsSnapshot: 100000 },
|
||||
],
|
||||
deliveryFeeCents: 0,
|
||||
userEmail: 'user@test.ru',
|
||||
})
|
||||
|
||||
expect(result.customer.email).toBe('user@test.ru')
|
||||
expect(result.items).toHaveLength(1)
|
||||
expect(result.items[0].description).toBe('Test Product')
|
||||
expect(result.items[0].quantity).toBe(2)
|
||||
expect(result.items[0].amount.value).toBe('1000.00')
|
||||
expect(result.items[0].vat_code).toBe(1)
|
||||
expect(result.items[0].measure).toBe('piece')
|
||||
expect(result.items[0].payment_subject).toBe('commodity')
|
||||
expect(result.items[0].payment_mode).toBe('full_prepayment')
|
||||
expect(result.tax_system_code).toBe(1)
|
||||
})
|
||||
|
||||
it('adds delivery item when deliveryFeeCents > 0', () => {
|
||||
const result = buildReceipt({
|
||||
orderItems: [
|
||||
{ titleSnapshot: 'Item A', qty: 1, priceCentsSnapshot: 50000 },
|
||||
],
|
||||
deliveryFeeCents: 35000,
|
||||
userEmail: 'user@test.ru',
|
||||
})
|
||||
|
||||
expect(result.items).toHaveLength(2)
|
||||
expect(result.items[1].description).toBe('Доставка')
|
||||
expect(result.items[1].amount.value).toBe('350.00')
|
||||
expect(result.items[1].payment_subject).toBe('service')
|
||||
})
|
||||
|
||||
it('passes through taxSystemCode', () => {
|
||||
const result = buildReceipt({
|
||||
orderItems: [
|
||||
{ titleSnapshot: 'Item', qty: 1, priceCentsSnapshot: 1000 },
|
||||
],
|
||||
deliveryFeeCents: 0,
|
||||
userEmail: 'user@test.ru',
|
||||
taxSystemCode: 3,
|
||||
})
|
||||
|
||||
expect(result.tax_system_code).toBe(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('yookassa validateWebhook', () => {
|
||||
beforeEach(() => {
|
||||
process.env.YOOKASSA_SECRET_KEY = 'test_secret'
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
delete process.env.YOOKASSA_SECRET_KEY
|
||||
})
|
||||
|
||||
it('returns event and paymentObject for valid notification', () => {
|
||||
const body = {
|
||||
type: 'notification',
|
||||
event: 'payment.succeeded',
|
||||
object: { id: 'yk-id', status: 'succeeded', paid: true },
|
||||
}
|
||||
const result = validateWebhook('127.0.0.1', body)
|
||||
expect(result.event).toBe('payment.succeeded')
|
||||
expect(result.paymentObject.id).toBe('yk-id')
|
||||
})
|
||||
|
||||
it('throws if type is not notification', () => {
|
||||
expect(() => validateWebhook('127.0.0.1', { type: 'other', event: 'x', object: {} })).toThrow(
|
||||
'Expected notification type',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws if missing event', () => {
|
||||
expect(() => validateWebhook('127.0.0.1', { type: 'notification', object: {} })).toThrow(
|
||||
'Missing event or object',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws if missing object', () => {
|
||||
expect(() => validateWebhook('127.0.0.1', { type: 'notification', event: 'x' })).toThrow(
|
||||
'Missing event or object',
|
||||
)
|
||||
})
|
||||
|
||||
it('throws for invalid body type', () => {
|
||||
expect(() => validateWebhook('127.0.0.1', 'not an object')).toThrow('Invalid webhook body')
|
||||
})
|
||||
|
||||
it('throws for null body', () => {
|
||||
expect(() => validateWebhook('127.0.0.1', null)).toThrow('Invalid webhook body')
|
||||
})
|
||||
|
||||
it('skips IP validation in test mode (test_ key)', () => {
|
||||
const body = { type: 'notification', event: 'payment.succeeded', object: {} }
|
||||
expect(() => validateWebhook('1.2.3.4', body)).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user