add stripe
Build & Push / Pipeline Tests (push) Failing after 1m6s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 56s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
Build & Push / Pipeline Tests (push) Failing after 1m6s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 56s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
This commit is contained in:
@@ -13,9 +13,15 @@ vi.mock('../../services/paypalService', () => ({
|
||||
verifyWebhookEvent: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../services/stripeService', () => ({
|
||||
isConfigured: vi.fn(),
|
||||
constructWebhookEvent: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../modules/payments/payment.service', () => ({
|
||||
handleAmanpayWebhook: vi.fn(),
|
||||
handlePaypalWebhook: vi.fn(),
|
||||
handleStripeWebhook: vi.fn(),
|
||||
listByCompany: vi.fn(),
|
||||
listByReservation: vi.fn(),
|
||||
initCharge: vi.fn(),
|
||||
@@ -28,6 +34,7 @@ import request from 'supertest'
|
||||
import { createApp } from '../../app'
|
||||
import * as amanpay from '../../services/amanpayService'
|
||||
import * as paypal from '../../services/paypalService'
|
||||
import * as stripe from '../../services/stripeService'
|
||||
import * as service from '../../modules/payments/payment.service'
|
||||
|
||||
const app = createApp()
|
||||
@@ -96,6 +103,37 @@ describe('payments API contract', () => {
|
||||
expect(service.handlePaypalWebhook).toHaveBeenCalledWith(payload, JSON.stringify(payload))
|
||||
})
|
||||
|
||||
it('rejects Stripe webhooks when signature validation fails', async () => {
|
||||
vi.mocked(stripe.isConfigured).mockReturnValue(true)
|
||||
vi.mocked(stripe.constructWebhookEvent).mockImplementation(() => {
|
||||
throw new Error('bad signature')
|
||||
})
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/v1/payments/webhooks/stripe')
|
||||
.set('stripe-signature', 'bad')
|
||||
.send({ id: 'evt_1', type: 'checkout.session.completed' })
|
||||
|
||||
expect(res.status).toBe(401)
|
||||
expect(res.body).toEqual({ error: 'invalid_signature' })
|
||||
expect(service.handleStripeWebhook).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('accepts verified Stripe webhooks and delegates handling', async () => {
|
||||
vi.mocked(stripe.isConfigured).mockReturnValue(true)
|
||||
vi.mocked(stripe.constructWebhookEvent).mockReturnValue({ id: 'evt_1', type: 'checkout.session.completed' } as never)
|
||||
|
||||
const payload = { id: 'evt_1', type: 'checkout.session.completed' }
|
||||
const res = await request(app)
|
||||
.post('/api/v1/payments/webhooks/stripe')
|
||||
.set('stripe-signature', 'good')
|
||||
.send(payload)
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body).toEqual({ received: true })
|
||||
expect(service.handleStripeWebhook).toHaveBeenCalledWith({ id: 'evt_1', type: 'checkout.session.completed' }, JSON.stringify(payload))
|
||||
})
|
||||
|
||||
it('keeps authenticated payment routes behind auth before any payment service call', async () => {
|
||||
const res = await request(app).get('/api/v1/payments/company')
|
||||
|
||||
|
||||
@@ -24,18 +24,25 @@ vi.mock('../../services/paypalService', () => ({
|
||||
verifyWebhookEvent: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../services/stripeService', () => ({
|
||||
isConfigured: vi.fn(),
|
||||
constructWebhookEvent: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../modules/subscriptions/subscription.service', () => ({
|
||||
getPlans: vi.fn(),
|
||||
getProviders: vi.fn(),
|
||||
getPlanFeatures: vi.fn(),
|
||||
handleAmanpayWebhook: vi.fn(),
|
||||
handlePaypalWebhook: vi.fn(),
|
||||
handleStripeWebhook: vi.fn(),
|
||||
}))
|
||||
|
||||
import request from 'supertest'
|
||||
import { createApp } from '../../app'
|
||||
import * as amanpay from '../../services/amanpayService'
|
||||
import * as paypal from '../../services/paypalService'
|
||||
import * as stripe from '../../services/stripeService'
|
||||
import * as service from '../../modules/subscriptions/subscription.service'
|
||||
|
||||
const app = createApp()
|
||||
@@ -43,7 +50,7 @@ const app = createApp()
|
||||
describe('subscriptions public API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.mocked(service.getProviders).mockReturnValue({ amanpay: false, paypal: true })
|
||||
vi.mocked(service.getProviders).mockReturnValue({ stripe: true, stripeProblems: [] })
|
||||
vi.mocked(service.getPlans).mockResolvedValue({ STARTER: { MONTHLY: { MAD: 9900 } } } as never)
|
||||
vi.mocked(service.getPlanFeatures).mockResolvedValue([
|
||||
{ id: 'feature_1', plan: 'STARTER', label: 'Vehicles', sortOrder: 1 },
|
||||
@@ -54,7 +61,7 @@ describe('subscriptions public API', () => {
|
||||
const res = await request(app).get('/api/v1/subscriptions/providers')
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body).toEqual({ data: { amanpay: false, paypal: true } })
|
||||
expect(res.body).toEqual({ data: { stripe: true, stripeProblems: [] } })
|
||||
expect(service.getProviders).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
@@ -102,4 +109,21 @@ describe('subscriptions public API', () => {
|
||||
expect(res.body).toEqual({ received: true })
|
||||
expect(service.handlePaypalWebhook).toHaveBeenCalledWith(payload, JSON.stringify(payload))
|
||||
})
|
||||
|
||||
it('accepts verified Stripe webhooks and delegates handling to the subscription service', async () => {
|
||||
vi.mocked(stripe.isConfigured).mockReturnValue(true)
|
||||
vi.mocked(stripe.constructWebhookEvent).mockReturnValue({ id: 'evt_1', type: 'checkout.session.completed' } as never)
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/v1/subscriptions/webhooks/stripe')
|
||||
.set('stripe-signature', 'good')
|
||||
.send({ id: 'evt_1' })
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body).toEqual({ received: true })
|
||||
expect(service.handleStripeWebhook).toHaveBeenCalledWith(
|
||||
{ id: 'evt_1', type: 'checkout.session.completed' },
|
||||
JSON.stringify({ id: 'evt_1' }),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,6 +7,6 @@ describe('schema boundary integration markers', () => {
|
||||
it('keeps public commercial payloads constrained before database-backed flows execute', () => {
|
||||
expect(companySignupSchema.safeParse({}).success).toBe(false)
|
||||
expect(reservationCreateSchema.safeParse({ vehicleId: 'bad', customerId: 'bad', startDate: 'bad', endDate: 'bad' }).success).toBe(false)
|
||||
expect(subscriptionCheckoutSchema.safeParse({ plan: 'PRO', billingPeriod: 'MONTHLY', currency: 'MAD', provider: 'PAYPAL', successUrl: 'https://ok.example.test', failureUrl: 'https://fail.example.test' }).success).toBe(true)
|
||||
expect(subscriptionCheckoutSchema.safeParse({ plan: 'PRO', billingPeriod: 'MONTHLY', currency: 'MAD', provider: 'STRIPE', successUrl: 'https://ok.example.test', failureUrl: 'https://fail.example.test' }).success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -99,8 +99,7 @@ describe('Subscriptions API', () => {
|
||||
const res = await request(app).get('/api/v1/subscriptions/providers')
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(typeof res.body.data.amanpay).toBe('boolean')
|
||||
expect(typeof res.body.data.paypal).toBe('boolean')
|
||||
expect(typeof res.body.data.stripe).toBe('boolean')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user