feat(billing): useStripeCheckout hook + post-redirect upgrade success
- useStripeCheckout: mutation + redirect full-page, pendingPriceType exposed - PricingPage migré vers useStripeCheckout (suppression useMutation inline) - useUpgradeSuccessHandler: détecte ?upgrade=success, invalide plan cache, clean URL - UpgradeSuccessBanner: callout success dans DashboardPage - Tests: 203 → 212 verts (+9) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9edfbb3c95
commit
bda7feb196
7 changed files with 371 additions and 25 deletions
|
|
@ -0,0 +1,88 @@
|
|||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { renderHook, act } from '@testing-library/react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
import { PLAN_QUERY_KEY } from '@/entities/user/query-keys'
|
||||
import { useUpgradeSuccessHandler } from '../useUpgradeSuccessHandler'
|
||||
|
||||
let invalidateSpy: ReturnType<typeof vi.fn>
|
||||
let queryClient: QueryClient
|
||||
|
||||
function wrapper({ children }: { children: ReactNode }) {
|
||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
}
|
||||
|
||||
function setLocation(search: string) {
|
||||
window.history.replaceState(null, '', `/dashboard${search}`)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } },
|
||||
})
|
||||
invalidateSpy = vi.fn().mockResolvedValue(undefined)
|
||||
// Spy sur la méthode invalidateQueries pour vérifier la clé exacte.
|
||||
queryClient.invalidateQueries = invalidateSpy as unknown as typeof queryClient.invalidateQueries
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
setLocation('')
|
||||
})
|
||||
|
||||
describe('useUpgradeSuccessHandler', () => {
|
||||
it('?upgrade=success → showSuccess=true, invalidate(PLAN_QUERY_KEY) appelé, URL nettoyée', () => {
|
||||
setLocation('?upgrade=success')
|
||||
|
||||
const { result } = renderHook(() => useUpgradeSuccessHandler(), { wrapper })
|
||||
|
||||
expect(result.current.showSuccess).toBe(true)
|
||||
expect(invalidateSpy).toHaveBeenCalledTimes(1)
|
||||
expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: PLAN_QUERY_KEY })
|
||||
// URL nettoyée : plus de `upgrade` dans la query string.
|
||||
expect(window.location.search).toBe('')
|
||||
})
|
||||
|
||||
it('absence de query param → showSuccess=false, invalidate non appelé', () => {
|
||||
setLocation('')
|
||||
|
||||
const { result } = renderHook(() => useUpgradeSuccessHandler(), { wrapper })
|
||||
|
||||
expect(result.current.showSuccess).toBe(false)
|
||||
expect(invalidateSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("?upgrade=cancelled (autre valeur) → showSuccess=false, pas d'action", () => {
|
||||
setLocation('?upgrade=cancelled')
|
||||
|
||||
const { result } = renderHook(() => useUpgradeSuccessHandler(), { wrapper })
|
||||
|
||||
expect(result.current.showSuccess).toBe(false)
|
||||
expect(invalidateSpy).not.toHaveBeenCalled()
|
||||
// URL conservée intacte (autre valeur, hors scope du nettoyage).
|
||||
expect(window.location.search).toBe('?upgrade=cancelled')
|
||||
})
|
||||
|
||||
it('dismiss() bascule showSuccess à false', () => {
|
||||
setLocation('?upgrade=success')
|
||||
|
||||
const { result } = renderHook(() => useUpgradeSuccessHandler(), { wrapper })
|
||||
expect(result.current.showSuccess).toBe(true)
|
||||
|
||||
act(() => {
|
||||
result.current.dismiss()
|
||||
})
|
||||
expect(result.current.showSuccess).toBe(false)
|
||||
})
|
||||
|
||||
it('conserve les autres query params (utm_*, etc.) lors du nettoyage', () => {
|
||||
setLocation('?upgrade=success&utm_source=email&ref=abc')
|
||||
|
||||
renderHook(() => useUpgradeSuccessHandler(), { wrapper })
|
||||
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
expect(params.has('upgrade')).toBe(false)
|
||||
expect(params.get('utm_source')).toBe('email')
|
||||
expect(params.get('ref')).toBe('abc')
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue