From 653074be3e7a6069f451dbf3c1808f237afaad6c Mon Sep 17 00:00:00 2001 From: root Date: Mon, 17 Aug 2026 21:15:35 -0400 Subject: [PATCH] fix stripe removal tests --- .../src/modules/operations.schemas.test.ts | 2 +- .../payments/payment.schemas.edge.test.ts | 1 - .../subscription.manual.schemas.test.ts | 2 +- .../subscription.schemas.edge.test.ts | 2 +- apps/api/src/services/stripeService.ts | 127 ------------------ .../subscription-team-boundaries.api.test.ts | 2 +- .../subscription-team-boundaries.e2e.test.ts | 2 +- .../public-validation-boundaries.test.ts | 17 +-- .../integration/schema-boundaries.test.ts | 2 +- 9 files changed, 15 insertions(+), 142 deletions(-) delete mode 100644 apps/api/src/services/stripeService.ts diff --git a/apps/api/src/modules/operations.schemas.test.ts b/apps/api/src/modules/operations.schemas.test.ts index 3bb17b3..1627fc3 100644 --- a/apps/api/src/modules/operations.schemas.test.ts +++ b/apps/api/src/modules/operations.schemas.test.ts @@ -38,7 +38,7 @@ describe('operational schemas', () => { plan: 'PRO', billingPeriod: 'MONTHLY', currency: 'MAD', - method: 'STRIPE', + method: 'CASH', idempotencyKey: '11111111-1111-4111-8111-111111111111', }).success).toBe(false) expect(startTrialSchema.parse({ plan: 'STARTER', billingPeriod: 'ANNUAL' })).toMatchObject({ currency: 'MAD' }) diff --git a/apps/api/src/modules/payments/payment.schemas.edge.test.ts b/apps/api/src/modules/payments/payment.schemas.edge.test.ts index dcb36b8..ed40fdc 100644 --- a/apps/api/src/modules/payments/payment.schemas.edge.test.ts +++ b/apps/api/src/modules/payments/payment.schemas.edge.test.ts @@ -7,7 +7,6 @@ describe('payment schemas edge cases', () => { expect(manualPaymentSchema.safeParse({ amount: 0, paymentMethod: 'CHECK' }).success).toBe(false) expect(manualPaymentSchema.safeParse({ amount: 100, paymentMethod: 'PAYPAL' }).success).toBe(false) expect(manualPaymentSchema.safeParse({ amount: 100, paymentMethod: 'CASH' }).success).toBe(false) - expect(manualPaymentSchema.safeParse({ amount: 100, paymentMethod: 'STRIPE' as any }).success).toBe(false) }) it('validates refund and payment parameter payloads', () => { diff --git a/apps/api/src/modules/subscriptions/subscription.manual.schemas.test.ts b/apps/api/src/modules/subscriptions/subscription.manual.schemas.test.ts index 95bdc25..2dd2de4 100644 --- a/apps/api/src/modules/subscriptions/subscription.manual.schemas.test.ts +++ b/apps/api/src/modules/subscriptions/subscription.manual.schemas.test.ts @@ -10,7 +10,7 @@ describe('manual subscription payment contracts', () => { it('accepts only bank transfer and check manual checkout', () => { const base = { plan: 'GROWTH', billingPeriod: 'ANNUAL', currency: 'MAD', idempotencyKey: crypto.randomUUID() } expect(manualCheckoutSchema.safeParse({ ...base, method: 'BANK_TRANSFER' }).success).toBe(true) - expect(manualCheckoutSchema.safeParse({ ...base, method: 'STRIPE' }).success).toBe(false) + expect(manualCheckoutSchema.safeParse({ ...base, method: 'CASH' }).success).toBe(false) }) it('normalizes references without discarding the display value', () => { diff --git a/apps/api/src/modules/subscriptions/subscription.schemas.edge.test.ts b/apps/api/src/modules/subscriptions/subscription.schemas.edge.test.ts index 60dd4e5..f431a67 100644 --- a/apps/api/src/modules/subscriptions/subscription.schemas.edge.test.ts +++ b/apps/api/src/modules/subscriptions/subscription.schemas.edge.test.ts @@ -18,7 +18,7 @@ describe('subscription.schemas edge contracts', () => { expect(manualCheckoutSchema.parse(payload)).toEqual(payload) expect(manualCheckoutSchema.safeParse({ ...payload, currency: 'USD' }).success).toBe(false) - expect(manualCheckoutSchema.safeParse({ ...payload, method: 'STRIPE' }).success).toBe(false) + expect(manualCheckoutSchema.safeParse({ ...payload, method: 'CASH' }).success).toBe(false) expect(manualCheckoutSchema.safeParse({ ...payload, idempotencyKey: 'not-a-uuid' }).success).toBe(false) }) diff --git a/apps/api/src/services/stripeService.ts b/apps/api/src/services/stripeService.ts deleted file mode 100644 index 9ecb8e7..0000000 --- a/apps/api/src/services/stripeService.ts +++ /dev/null @@ -1,127 +0,0 @@ -import Stripe from 'stripe' - -const STRIPE_API_KEY = process.env.STRIPE_API_KEY ?? '' -const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET ?? '' - -let client: Stripe | null = null - -function getClient() { - if (!client) { - client = new Stripe(STRIPE_API_KEY, { - apiVersion: '2026-06-24.dahlia', - appInfo: { - name: 'RentalDriveGo', - version: '1.0.0', - }, - }) - } - return client -} - -function integrationIdentifier() { - const suffix = Math.random().toString(36).replace(/[^a-z]/g, '').slice(0, 8).padEnd(8, 'x') - return `rentaldrivego_${suffix}` -} - -export interface StripeCheckoutParams { - amount: number - currency: string - orderId: string - description: string - customerEmail?: string | null - successUrl: string - cancelUrl: string - reservationId?: string - companyId: string - subscriptionId?: string - type: 'CHARGE' | 'DEPOSIT' | 'SUBSCRIPTION' -} - -export interface StripeCheckoutResult { - checkoutUrl: string - sessionId: string -} - -export async function createCheckoutSession(params: StripeCheckoutParams): Promise { - const session = await getClient().checkout.sessions.create({ - mode: 'payment', - success_url: params.successUrl, - cancel_url: params.cancelUrl, - customer_email: params.customerEmail ?? undefined, - client_reference_id: params.orderId, - line_items: [ - { - quantity: 1, - price_data: { - currency: params.currency.toLowerCase(), - unit_amount: params.amount, - product_data: { - name: params.description, - }, - }, - }, - ], - metadata: { - ...(params.reservationId ? { reservationId: params.reservationId } : {}), - companyId: params.companyId, - ...(params.subscriptionId ? { subscriptionId: params.subscriptionId } : {}), - type: params.type, - orderId: params.orderId, - }, - payment_intent_data: { - metadata: { - ...(params.reservationId ? { reservationId: params.reservationId } : {}), - companyId: params.companyId, - ...(params.subscriptionId ? { subscriptionId: params.subscriptionId } : {}), - type: params.type, - orderId: params.orderId, - }, - }, - integration_identifier: integrationIdentifier(), - }) - - if (!session.url) { - throw new Error('Stripe checkout session did not include a checkout URL') - } - - return { checkoutUrl: session.url, sessionId: session.id } -} - -export function constructWebhookEvent(rawBody: string | Buffer, signature: string) { - return getClient().webhooks.constructEvent(rawBody, signature, STRIPE_WEBHOOK_SECRET) -} - -export async function refundPaymentIntent(paymentIntentId: string, amount: number, reason?: string) { - return getClient().refunds.create({ - payment_intent: paymentIntentId, - amount, - metadata: reason ? { reason } : undefined, - }) -} - -export function isConfigured(): boolean { - return getConfigurationStatus().configured -} - -export function getConfigurationStatus() { - const problems: string[] = [] - - if (!STRIPE_API_KEY) { - problems.push('STRIPE_API_KEY is missing') - } else if (STRIPE_API_KEY.includes('placeholder')) { - problems.push('STRIPE_API_KEY is still a placeholder') - } else if (!STRIPE_API_KEY.startsWith('sk_') && !STRIPE_API_KEY.startsWith('rk_')) { - problems.push('STRIPE_API_KEY must be a Stripe secret or restricted key') - } - - if (!STRIPE_WEBHOOK_SECRET) { - problems.push('STRIPE_WEBHOOK_SECRET is missing') - } else if (!STRIPE_WEBHOOK_SECRET.startsWith('whsec_')) { - problems.push('STRIPE_WEBHOOK_SECRET must be a Stripe webhook signing secret') - } - - return { - configured: problems.length === 0, - problems, - } -} diff --git a/apps/api/src/tests/api/subscription-team-boundaries.api.test.ts b/apps/api/src/tests/api/subscription-team-boundaries.api.test.ts index 765c2c0..3559fd5 100644 --- a/apps/api/src/tests/api/subscription-team-boundaries.api.test.ts +++ b/apps/api/src/tests/api/subscription-team-boundaries.api.test.ts @@ -72,7 +72,7 @@ describe('subscription and team API validation contracts', () => { plan: 'PRO', billingPeriod: 'ANNUAL', currency: 'MAD', - method: 'STRIPE', + method: 'CASH', idempotencyKey: '11111111-1111-4111-8111-111111111111', }) diff --git a/apps/api/src/tests/e2e/subscription-team-boundaries.e2e.test.ts b/apps/api/src/tests/e2e/subscription-team-boundaries.e2e.test.ts index 89d0825..dbf084f 100644 --- a/apps/api/src/tests/e2e/subscription-team-boundaries.e2e.test.ts +++ b/apps/api/src/tests/e2e/subscription-team-boundaries.e2e.test.ts @@ -12,7 +12,7 @@ const app = createApp() describe('subscription and team public boundary smoke', () => { it('rejects malformed protected subscription checkout without leaking internals', async () => { - const res = await request(app).post('/api/v1/subscriptions/manual-checkout').send({ method: 'STRIPE' }) + const res = await request(app).post('/api/v1/subscriptions/manual-checkout').send({ method: 'CASH' }) expect([400, 401]).toContain(res.status) expect(JSON.stringify(res.body)).not.toContain('stack') diff --git a/apps/api/src/tests/integration/public-validation-boundaries.test.ts b/apps/api/src/tests/integration/public-validation-boundaries.test.ts index 6af578d..352134f 100644 --- a/apps/api/src/tests/integration/public-validation-boundaries.test.ts +++ b/apps/api/src/tests/integration/public-validation-boundaries.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { parseBody, parseQuery } from '../../http/validate' import { carplaceReservationSchema, paginationSchema } from '../../modules/carplace/carplace.schemas' -import { paySchema } from '../../modules/site/site.schemas' +import { manualCheckoutSchema } from '../../modules/subscriptions/subscription.schemas' function reqWith(body: unknown, query: unknown = {}) { return { body, query, params: {} } as any @@ -15,13 +15,14 @@ describe('public validation boundaries', () => { }) }) - it('blocks unsupported public payment providers before service orchestration', () => { - expect(() => parseBody(paySchema, reqWith({ - provider: 'STRIPE', - successUrl: 'https://ok.example.test', - failureUrl: 'https://fail.example.test', - accessToken: 'booking-access-token-123', - }))).toThrow('Invalid enum value') + it('blocks unsupported payment methods before service orchestration', () => { + expect(() => parseBody(manualCheckoutSchema, reqWith({ + plan: 'PRO', + billingPeriod: 'MONTHLY', + currency: 'MAD', + method: 'CASH', + idempotencyKey: '11111111-1111-4111-8111-111111111111', + }))).toThrow() }) it('requires enough anonymous carplace reservation identity to create a booking request', () => { diff --git a/apps/api/src/tests/integration/schema-boundaries.test.ts b/apps/api/src/tests/integration/schema-boundaries.test.ts index b013962..87ce7ef 100644 --- a/apps/api/src/tests/integration/schema-boundaries.test.ts +++ b/apps/api/src/tests/integration/schema-boundaries.test.ts @@ -18,7 +18,7 @@ describe('schema boundary integration markers', () => { plan: 'PRO', billingPeriod: 'MONTHLY', currency: 'MAD', - method: 'STRIPE', + method: 'CASH', idempotencyKey: '11111111-1111-4111-8111-111111111111', }).success).toBe(false) })