Skip to content

Commit 0df4e54

Browse files
add tests
1 parent 3210ed6 commit 0df4e54

File tree

5 files changed

+267
-30
lines changed

5 files changed

+267
-30
lines changed

src/pages/PlanPage/PlanPage.test.jsx src/pages/PlanPage/PlanPage.test.tsx

+53-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import config from 'config'
1313

1414
import { ThemeContextProvider } from 'shared/ThemeContext'
1515

16+
import { Location } from 'history'
17+
import { UnverifiedPaymentMethodSchema } from 'services/account'
18+
import { z } from 'zod'
1619
import PlanPage from './PlanPage'
1720

1821
vi.mock('config')
@@ -40,10 +43,10 @@ const queryClientV5 = new QueryClientV5({
4043
defaultOptions: { queries: { retry: false } },
4144
})
4245

43-
let testLocation
46+
let testLocation: Location<unknown>
4447
const wrapper =
4548
(initialEntries = '') =>
46-
({ children }) => (
49+
({ children }: { children: React.ReactNode }) => (
4750
<QueryClientProviderV5 client={queryClientV5}>
4851
<QueryClientProvider client={queryClient}>
4952
<ThemeContextProvider>
@@ -79,7 +82,13 @@ afterAll(() => {
7982

8083
describe('PlanPage', () => {
8184
function setup(
82-
{ owner, isSelfHosted = false } = {
85+
{
86+
owner,
87+
isSelfHosted = false,
88+
unverifiedPaymentMethods = [] as z.infer<
89+
typeof UnverifiedPaymentMethodSchema
90+
>[],
91+
} = {
8392
owner: {
8493
username: 'codecov',
8594
isCurrentUserPartOfOrg: true,
@@ -92,6 +101,17 @@ describe('PlanPage', () => {
92101
server.use(
93102
graphql.query('PlanPageData', () => {
94103
return HttpResponse.json({ data: { owner } })
104+
}),
105+
graphql.query('UnverifiedPaymentMethods', () => {
106+
return HttpResponse.json({
107+
data: {
108+
owner: {
109+
billing: {
110+
unverifiedPaymentMethods,
111+
},
112+
},
113+
},
114+
})
95115
})
96116
)
97117
}
@@ -102,7 +122,7 @@ describe('PlanPage', () => {
102122
owner: {
103123
username: 'codecov',
104124
isCurrentUserPartOfOrg: false,
105-
numberOfUploads: null,
125+
numberOfUploads: 0,
106126
},
107127
})
108128
})
@@ -120,7 +140,7 @@ describe('PlanPage', () => {
120140
owner: {
121141
username: 'codecov',
122142
isCurrentUserPartOfOrg: false,
123-
numberOfUploads: null,
143+
numberOfUploads: 0,
124144
},
125145
})
126146
})
@@ -149,6 +169,34 @@ describe('PlanPage', () => {
149169
const tabs = await screen.findByText(/Tabs/)
150170
expect(tabs).toBeInTheDocument()
151171
})
172+
173+
describe('when there are unverified payment methods', () => {
174+
beforeEach(() => {
175+
setup({
176+
owner: {
177+
username: 'codecov',
178+
isCurrentUserPartOfOrg: true,
179+
numberOfUploads: 30,
180+
},
181+
unverifiedPaymentMethods: [
182+
{
183+
paymentMethodId: 'pm_123',
184+
hostedVerificationUrl: 'https://verify.stripe.com',
185+
},
186+
],
187+
})
188+
})
189+
190+
it('renders unverified payment method alert', async () => {
191+
render(<PlanPage />, { wrapper: wrapper('/plan/gh/codecov') })
192+
193+
const alert = await screen.findByText(/Verify Your New Payment Method/)
194+
expect(alert).toBeInTheDocument()
195+
196+
const link = screen.getByText('Click here')
197+
expect(link).toHaveAttribute('href', 'https://verify.stripe.com')
198+
})
199+
})
152200
})
153201

154202
describe('testing routes', () => {

src/pages/PlanPage/subRoutes/CurrentOrgPlan/InfoMessageStripeCallback/InfoMessageStripeCallback.test.tsx

+25-6
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ const wrapper =
1212

1313
describe('InfoMessageStripeCallback', () => {
1414
describe('when rendering without success or cancel in the url', () => {
15-
const { container } = render(<InfoMessageStripeCallback />, {
16-
wrapper: wrapper('/account/gh/codecov'),
17-
})
15+
const { container } = render(
16+
<InfoMessageStripeCallback hasUnverifiedPaymentMethods={false} />,
17+
{
18+
wrapper: wrapper('/account/gh/codecov'),
19+
}
20+
)
1821

1922
it('doesnt render anything', () => {
2023
expect(container).toBeEmptyDOMElement()
@@ -23,13 +26,29 @@ describe('InfoMessageStripeCallback', () => {
2326

2427
describe('when rendering with success in the url', () => {
2528
it('renders a success message', async () => {
26-
render(<InfoMessageStripeCallback />, {
27-
wrapper: wrapper('/account/gh/codecov?success'),
28-
})
29+
render(
30+
<InfoMessageStripeCallback hasUnverifiedPaymentMethods={false} />,
31+
{
32+
wrapper: wrapper('/account/gh/codecov?success'),
33+
}
34+
)
2935

3036
await expect(
3137
screen.getByText(/Subscription Update Successful/)
3238
).toBeInTheDocument()
3339
})
3440
})
41+
42+
describe('when hasUnverifiedPaymentMethods is true', () => {
43+
it('does not enders a success message even at ?success', async () => {
44+
const { container } = render(
45+
<InfoMessageStripeCallback hasUnverifiedPaymentMethods={true} />,
46+
{
47+
wrapper: wrapper('/account/gh/codecov?success'),
48+
}
49+
)
50+
51+
expect(container).toBeEmptyDOMElement()
52+
})
53+
})
3554
})

src/pages/PlanPage/subRoutes/UpgradePlanPage/UpgradeForm/UpgradeForm.test.tsx

+103-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2+
import {
3+
QueryClientProvider as QueryClientProviderV5,
4+
QueryClient as QueryClientV5,
5+
} from '@tanstack/react-queryV5'
26
import { render, screen, waitFor } from '@testing-library/react'
37
import userEvent from '@testing-library/user-event'
48
import { graphql, http, HttpResponse } from 'msw'
@@ -233,6 +237,15 @@ const queryClient = new QueryClient({
233237
},
234238
},
235239
})
240+
241+
const queryClientV5 = new QueryClientV5({
242+
defaultOptions: {
243+
queries: {
244+
retry: false,
245+
},
246+
},
247+
})
248+
236249
const server = setupServer()
237250

238251
beforeAll(() => {
@@ -241,6 +254,7 @@ beforeAll(() => {
241254

242255
afterEach(() => {
243256
queryClient.clear()
257+
queryClientV5.clear()
244258
server.resetHandlers()
245259
vi.clearAllMocks()
246260
})
@@ -256,20 +270,22 @@ const wrapper: (
256270
) => React.FC<React.PropsWithChildren> =
257271
(initialEntries = ['/gh/codecov']) =>
258272
({ children }) => (
259-
<QueryClientProvider client={queryClient}>
260-
<MemoryRouter initialEntries={initialEntries}>
261-
<Route path="/:provider/:owner">
262-
<Suspense fallback={null}>{children}</Suspense>
263-
</Route>
264-
<Route
265-
path="*"
266-
render={({ location }) => {
267-
testLocation = location
268-
return null
269-
}}
270-
/>
271-
</MemoryRouter>
272-
</QueryClientProvider>
273+
<QueryClientProviderV5 client={queryClientV5}>
274+
<QueryClientProvider client={queryClient}>
275+
<MemoryRouter initialEntries={initialEntries}>
276+
<Route path="/:provider/:owner">
277+
<Suspense fallback={null}>{children}</Suspense>
278+
</Route>
279+
<Route
280+
path="*"
281+
render={({ location }) => {
282+
testLocation = location
283+
return null
284+
}}
285+
/>
286+
</MemoryRouter>
287+
</QueryClientProvider>
288+
</QueryClientProviderV5>
273289
)
274290

275291
type SetupArgs = {
@@ -281,6 +297,7 @@ type SetupArgs = {
281297
hasSentryPlans?: boolean
282298
monthlyPlan?: boolean
283299
planUserCount?: number
300+
hasUnverifiedPaymentMethod?: boolean
284301
}
285302

286303
describe('UpgradeForm', () => {
@@ -293,6 +310,7 @@ describe('UpgradeForm', () => {
293310
hasSentryPlans = false,
294311
monthlyPlan = true,
295312
planUserCount = 1,
313+
hasUnverifiedPaymentMethod = false,
296314
}: SetupArgs) {
297315
const addNotification = vi.fn()
298316
const user = userEvent.setup()
@@ -384,13 +402,84 @@ describe('UpgradeForm', () => {
384402
},
385403
},
386404
})
405+
}),
406+
graphql.query('UnverifiedPaymentMethods', () => {
407+
return HttpResponse.json({
408+
data: {
409+
owner: {
410+
billing: {
411+
unverifiedPaymentMethods: hasUnverifiedPaymentMethod
412+
? [
413+
{
414+
paymentMethodId: 'asdf',
415+
hostedVerficationUrl: 'https://stripe.com',
416+
},
417+
]
418+
: null,
419+
},
420+
},
421+
},
422+
})
387423
})
388424
)
389425

390426
return { addNotification, user, patchRequest }
391427
}
392428

393429
describe('when rendered', () => {
430+
describe('when user has unverified payment methods', () => {
431+
const props = {
432+
setSelectedPlan: vi.fn(),
433+
selectedPlan: proPlanYear,
434+
}
435+
436+
it('shows modal when form is submitted', async () => {
437+
const { user } = setup({
438+
planValue: Plans.USERS_BASIC,
439+
hasUnverifiedPaymentMethod: true,
440+
})
441+
render(<UpgradeForm {...props} />, { wrapper: wrapper() })
442+
443+
const proceedToCheckoutButton = await screen.findByRole('button', {
444+
name: /Proceed to checkout/,
445+
})
446+
await user.click(proceedToCheckoutButton)
447+
448+
const modal = await screen.findByText(
449+
/Are you sure you want to abandon this upgrade and start a new one/,
450+
{
451+
exact: false,
452+
}
453+
)
454+
expect(modal).toBeInTheDocument()
455+
})
456+
457+
it('does not show modal when no unverified payment methods', async () => {
458+
const { user } = setup({
459+
planValue: Plans.USERS_BASIC,
460+
hasUnverifiedPaymentMethod: false,
461+
})
462+
render(<UpgradeForm {...props} />, { wrapper: wrapper() })
463+
464+
const input = await screen.findByRole('spinbutton')
465+
await user.type(input, '{backspace}{backspace}{backspace}')
466+
await user.type(input, '20')
467+
468+
const proceedToCheckoutButton = await screen.findByRole('button', {
469+
name: /Proceed to checkout/,
470+
})
471+
await user.click(proceedToCheckoutButton)
472+
473+
const modal = screen.queryByText(
474+
/Are you sure you want to abandon this upgrade and start a new one/,
475+
{
476+
exact: false,
477+
}
478+
)
479+
expect(modal).not.toBeInTheDocument()
480+
})
481+
})
482+
394483
describe('when the user has a basic plan', () => {
395484
const props = {
396485
setSelectedPlan: vi.fn(),

src/pages/PlanPage/subRoutes/UpgradePlanPage/UpgradeForm/UpgradeForm.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
useAccountDetails,
99
useAvailablePlans,
1010
usePlanData,
11+
useUnverifiedPaymentMethods,
1112
} from 'services/account'
1213
import { Provider } from 'shared/api/helpers'
1314
import { canApplySentryUpgrade, getNextBillingDate } from 'shared/utils/billing'
@@ -45,6 +46,10 @@ function UpgradeForm({ selectedPlan, setSelectedPlan }: UpgradeFormProps) {
4546
const { data: accountDetails } = useAccountDetails({ provider, owner })
4647
const { data: plans } = useAvailablePlans({ provider, owner })
4748
const { data: planData } = usePlanData({ owner, provider })
49+
const { data: unverifiedPaymentMethods } = useUnverifiedPaymentMethods({
50+
provider,
51+
owner,
52+
})
4853
const { upgradePlan } = useUpgradeControls()
4954
const [showModal, setShowModal] = useState(false)
5055
const [formData, setFormData] = useState<UpgradeFormFields>()
@@ -95,7 +100,7 @@ function UpgradeForm({ selectedPlan, setSelectedPlan }: UpgradeFormProps) {
95100
}, [newPlan, trigger])
96101

97102
const onSubmit = handleSubmit((data) => {
98-
if (accountDetails?.unverifiedPaymentMethods?.length) {
103+
if (unverifiedPaymentMethods?.length) {
99104
setFormData(data)
100105
setShowModal(true)
101106
} else {
@@ -141,10 +146,7 @@ function UpgradeForm({ selectedPlan, setSelectedPlan }: UpgradeFormProps) {
141146
setIsUpgrading(true)
142147
upgradePlan(formData)
143148
}}
144-
url={
145-
accountDetails?.unverifiedPaymentMethods?.[0]
146-
?.hostedVerificationLink || ''
147-
}
149+
url={unverifiedPaymentMethods?.[0]?.hostedVerificationUrl || ''}
148150
isUpgrading={isUpgrading}
149151
/>
150152
)}

0 commit comments

Comments
 (0)