-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
72cd37d
commit 969f83f
Showing
9 changed files
with
424 additions
and
16 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
218 changes: 218 additions & 0 deletions
218
...s/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
import { Elements } from '@stripe/react-stripe-js' | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query' | ||
import { render, screen } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
import { MemoryRouter, Route } from 'react-router-dom' | ||
import { vi } from 'vitest' | ||
import { z } from 'zod' | ||
|
||
import { SubscriptionDetailSchema } from 'services/account/useAccountDetails' | ||
|
||
import PaymentMethodForm from './PaymentMethodForm' | ||
|
||
const queryClient = new QueryClient() | ||
|
||
const mockElements = { | ||
submit: vi.fn(), | ||
getElement: vi.fn(), | ||
} | ||
|
||
vi.mock('@stripe/react-stripe-js', () => ({ | ||
Elements: ({ children }: { children: React.ReactNode }) => children, | ||
useElements: () => mockElements, | ||
PaymentElement: 'div', | ||
})) | ||
|
||
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => ( | ||
<QueryClientProvider client={queryClient}> | ||
<Elements stripe={null}> | ||
<MemoryRouter initialEntries={['/plan/gh/codecov']}> | ||
<Route path="/plan/:provider/:owner">{children}</Route> | ||
</MemoryRouter> | ||
</Elements> | ||
</QueryClientProvider> | ||
) | ||
|
||
const subscriptionDetail: z.infer<typeof SubscriptionDetailSchema> = { | ||
defaultPaymentMethod: { | ||
billingDetails: { | ||
address: { | ||
line1: '123 Main St', | ||
city: 'San Francisco', | ||
state: 'CA', | ||
postalCode: '94105', | ||
country: 'US', | ||
line2: null, | ||
}, | ||
phone: '1234567890', | ||
name: 'John Doe', | ||
email: '[email protected]', | ||
}, | ||
card: { | ||
brand: 'visa', | ||
expMonth: 12, | ||
expYear: 2025, | ||
last4: '4242', | ||
}, | ||
}, | ||
currentPeriodEnd: 1706851492, | ||
cancelAtPeriodEnd: false, | ||
customer: { | ||
id: 'cust_123', | ||
email: '[email protected]', | ||
}, | ||
latestInvoice: null, | ||
taxIds: [], | ||
trialEnd: null, | ||
} | ||
|
||
const mocks = { | ||
useUpdatePaymentMethod: vi.fn(), | ||
} | ||
|
||
vi.mock('services/account/useUpdatePaymentMethod', () => ({ | ||
useUpdatePaymentMethod: () => mocks.useUpdatePaymentMethod(), | ||
})) | ||
|
||
afterEach(() => { | ||
vi.clearAllMocks() | ||
}) | ||
|
||
describe('PaymentMethodForm', () => { | ||
describe('when the user clicks on Edit payment method', () => { | ||
it(`doesn't render the payment method anymore`, async () => { | ||
const user = userEvent.setup() | ||
const updatePaymentMethod = vi.fn() | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: updatePaymentMethod, | ||
isLoading: false, | ||
}) | ||
|
||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={() => {}} | ||
/>, | ||
{ wrapper } | ||
) | ||
await user.click(screen.getByTestId('update-payment-method')) | ||
|
||
expect(screen.queryByText(/Visa/)).not.toBeInTheDocument() | ||
}) | ||
|
||
it('renders the form', async () => { | ||
const user = userEvent.setup() | ||
const updatePaymentMethod = vi.fn() | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: updatePaymentMethod, | ||
isLoading: false, | ||
}) | ||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={() => {}} | ||
/>, | ||
{ wrapper } | ||
) | ||
await user.click(screen.getByTestId('update-payment-method')) | ||
|
||
expect(screen.getByRole('button', { name: /Save/i })).toBeInTheDocument() | ||
}) | ||
|
||
describe('when submitting', () => { | ||
it('calls the service to update the payment method', async () => { | ||
const user = userEvent.setup() | ||
const updatePaymentMethod = vi.fn() | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: updatePaymentMethod, | ||
isLoading: false, | ||
}) | ||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={() => {}} | ||
/>, | ||
{ wrapper } | ||
) | ||
await user.click(screen.getByTestId('update-payment-method')) | ||
expect(updatePaymentMethod).toHaveBeenCalled() | ||
}) | ||
}) | ||
|
||
describe('when the user clicks on cancel', () => { | ||
it(`doesn't render the form anymore`, async () => { | ||
const user = userEvent.setup() | ||
const closeForm = vi.fn() | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: vi.fn(), | ||
isLoading: false, | ||
}) | ||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={closeForm} | ||
/>, | ||
{ wrapper } | ||
) | ||
|
||
await user.click(screen.getByTestId('update-payment-method')) | ||
await user.click(screen.getByRole('button', { name: /Cancel/ })) | ||
|
||
expect(closeForm).toHaveBeenCalled() | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when there is an error in the form', () => { | ||
it('renders the error', async () => { | ||
const user = userEvent.setup() | ||
const randomError = 'not rich enough' | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: vi.fn(), | ||
error: { message: randomError }, | ||
}) | ||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={() => {}} | ||
/>, | ||
{ wrapper } | ||
) | ||
|
||
await user.click(screen.getByTestId('update-payment-method')) | ||
|
||
expect(screen.getByText(randomError)).toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
describe('when the form is loading', () => { | ||
it('has the error and save button disabled', async () => { | ||
mocks.useUpdatePaymentMethod.mockReturnValue({ | ||
mutate: vi.fn(), | ||
isLoading: true, | ||
}) | ||
render( | ||
<PaymentMethodForm | ||
subscriptionDetail={subscriptionDetail} | ||
provider="gh" | ||
owner="codecov" | ||
closeForm={() => {}} | ||
/>, | ||
{ wrapper } | ||
) | ||
|
||
expect(screen.queryByRole('button', { name: /Save/i })).toBeDisabled() | ||
expect(screen.queryByRole('button', { name: /Cancel/i })).toBeDisabled() | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.