test: add automated coverage for Stripe checkout flow (#153)#160
test: add automated coverage for Stripe checkout flow (#153)#160
Conversation
Backend: - stripe.service.test.ts: test-mode stubs for coffee/meeting, StripeServiceError constructor, isStripeServiceError, mapStripeErrorCode (all 4 codes) - stripe.mutations.test.ts: extend with meeting product, returnUrl passthrough, INVALID_RETURN_URL → BAD_USER_INPUT mapping Frontend: - useStripeCheckout.test.tsx: redirect on success, GraphQL/network error handling, missing URL guard, analytics tracking (checkout_started + checkout_error) - Stripe.test.tsx: meeting product selection, error alert rendering, loading state disables continue button
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughAdds and expands unit tests across backend and frontend to validate Stripe checkout flows: createCheckoutSession behavior (including meeting product and returnUrl), Stripe service stubs and error mappings, hook behavior, async states, error handling, and analytics triggers. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/src/__tests__/unit/stripe.mutations.test.ts (1)
4-14:⚠️ Potential issue | 🟠 MajorMake the Stripe error mock stop lying.
This stub treats any object with a
codefield as a Stripe service error, but the real guard inbackend/src/services/stripe.tsonly returns true forinstanceof StripeServiceError. That means these resolver tests can pass with dressed-up plainErrorobjects even if production would route them down the generic error path. Right now the suite is shadowboxing ghosts.💡 Tighten the mock to match production semantics
-jest.mock('../../services/stripe', () => ({ - createCheckoutSession: jest.fn(), - getCheckoutSessionStatus: jest.fn(), - isStripeServiceError: (error: unknown) => !!error && typeof error === 'object' && 'code' in error, - mapStripeErrorCode: (code: string) => { +jest.mock('../../services/stripe', () => { + const actual = jest.requireActual('../../services/stripe'); + + return { + StripeServiceError: actual.StripeServiceError, + createCheckoutSession: jest.fn(), + getCheckoutSessionStatus: jest.fn(), + isStripeServiceError: (error: unknown) => error instanceof actual.StripeServiceError, + mapStripeErrorCode: (code: string) => { if (code === 'SESSION_NOT_FOUND') return 'NOT_FOUND'; if (code === 'NOT_CONFIGURED' || code === 'MISSING_PRICE') return 'SERVICE_UNAVAILABLE'; if (code === 'INVALID_RETURN_URL') return 'BAD_USER_INPUT'; return 'INTERNAL_SERVER_ERROR'; - }, -})); + }, + }; +});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/__tests__/unit/stripe.mutations.test.ts` around lines 4 - 14, The mock's isStripeServiceError currently treats any object with a code field as a StripeServiceError, which diverges from the real guard (it checks instanceof StripeServiceError); update the mock in the test to call the real constructor check by using jest.requireActual('../../services/stripe') and returning (error: unknown) => error instanceof actualModule.StripeServiceError so the mocked isStripeServiceError mirrors production behavior; keep the rest of the mocked exports (createCheckoutSession, getCheckoutSessionStatus, mapStripeErrorCode) the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/src/__tests__/unit/stripe.mutations.test.ts`:
- Around line 141-145: The coffee-path unit test's expected call shape for
createCheckoutSession is missing the forwarded returnUrl field; update the
coffee-path assertion that calls
expect(createCheckoutSession).toHaveBeenCalledWith(...) to include returnUrl:
undefined so it matches the resolver's actual payload (i.e., ensure the expected
object contains productKey, email, and returnUrl: undefined for the
createCheckoutSession call).
In `@frontend/src/__tests__/lib/hooks/useStripeCheckout.test.tsx`:
- Around line 237-249: The test title overstates what it verifies; rename the
test case to remove the ordering claim or explicitly assert ordering. Easiest
fix: change the it(...) description from "tracks checkout_started event before
mutation" to something like "tracks stripe_checkout_started event" to match the
assertion (which only checks mockTrackClientEvent called), referencing the
useStripeCheckout hook, its startCheckout method, and the mockTrackClientEvent
spy; alternatively, if you want ordering enforced, add an explicit assertion
that mockTrackClientEvent was called prior to the network/mutation mock (e.g.,
verify mockTrackClientEvent.mock.invocation order relative to your mutation mock
such as successMock) after invoking result.current.startCheckout.
- Around line 83-84: Replace the ad-hoc typed error object in the test with a
properly constructed GraphQLError instance: remove the "errors: [{ message:
'Return URL must belong to the frontend origin' } as any]" escape hatch and
create new GraphQLError('Return URL must belong to the frontend origin', {
extensions: { /* include the same extension shape used in other tests (e.g.,
code, exception, path, etc.) to match expectations */ } }); this keeps
TypeScript strict mode happy and matches the pattern used in
AuthContext.test.tsx / GogginsDialog.rate-limit.test.tsx / Apod.test.tsx so the
GraphQL-error path is typed correctly.
---
Outside diff comments:
In `@backend/src/__tests__/unit/stripe.mutations.test.ts`:
- Around line 4-14: The mock's isStripeServiceError currently treats any object
with a code field as a StripeServiceError, which diverges from the real guard
(it checks instanceof StripeServiceError); update the mock in the test to call
the real constructor check by using jest.requireActual('../../services/stripe')
and returning (error: unknown) => error instanceof
actualModule.StripeServiceError so the mocked isStripeServiceError mirrors
production behavior; keep the rest of the mocked exports (createCheckoutSession,
getCheckoutSessionStatus, mapStripeErrorCode) the same.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bd7eafe3-4145-4479-82fb-5e922c7da2af
📒 Files selected for processing (4)
backend/src/__tests__/unit/stripe.mutations.test.tsbackend/src/__tests__/unit/stripe.service.test.tsfrontend/src/__tests__/components/Stripe.test.tsxfrontend/src/__tests__/lib/hooks/useStripeCheckout.test.tsx
- Add returnUrl: undefined to coffee test assertion for explicit coverage - Use new GraphQLError() instead of as-any cast in hook test - Rename test to 'tracks stripe_checkout_started event when checkout starts'
Backend:
Frontend:
Summary by CodeRabbit