Skip to content

Commit

Permalink
chore: Migrate useEnterpriseAccountDetails to TS Query V5 (#3571)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholas-codecov authored Dec 11, 2024
1 parent 0993878 commit 7b9fe28
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { MemoryRouter, Route, useLocation } from 'react-router'

import AccountOrgs from './AccountOrgs'

import { Account } from '../hooks/useEnterpriseAccountDetails'
import { Account } from '../queries/EnterpriseAccountDetailsQueryOpts'

const mockAccount: Account = {
name: 'my-account',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Icon from 'ui/Icon'
import Spinner from 'ui/Spinner'
import { Tooltip } from 'ui/Tooltip'

import { Account } from '../hooks/useEnterpriseAccountDetails'
import { Account } from '../queries/EnterpriseAccountDetailsQueryOpts'
import { InfiniteAccountOrganizationsQueryOpts } from '../queries/InfiniteAccountOrganizationsQueryOpts'

interface AccountOrgsArgs {
Expand Down
84 changes: 50 additions & 34 deletions src/pages/PlanPage/subRoutes/CurrentOrgPlan/CurrentOrgPlan.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
} from '@tanstack/react-queryV5'
import { render, screen } from '@testing-library/react'
import noop from 'lodash/noop'
import { graphql, http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { Suspense } from 'react'
import { MemoryRouter, Route } from 'react-router-dom'
import { z } from 'zod'

Expand All @@ -12,21 +17,13 @@ import { Plans } from 'shared/utils/billing'
import { AlertOptions, type AlertOptionsType } from 'ui/Alert'

import CurrentOrgPlan from './CurrentOrgPlan'
import { useEnterpriseAccountDetails } from './hooks/useEnterpriseAccountDetails'
import { EnterpriseAccountDetailsRequestSchema } from './queries/EnterpriseAccountDetailsQueryOpts'

vi.mock('./BillingDetails', () => ({ default: () => 'BillingDetails' }))
vi.mock('./CurrentPlanCard', () => ({ default: () => 'CurrentPlanCard' }))
vi.mock('./LatestInvoiceCard', () => ({ default: () => 'LatestInvoiceCard' }))
vi.mock('./AccountOrgs', () => ({ default: () => 'AccountOrgs' }))

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})

const mockedAccountDetails = {
planProvider: 'github',
rootOrganization: {},
Expand Down Expand Up @@ -81,26 +78,38 @@ const mockEnterpriseAccountDetailsHundredPercent = {
},
}

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})

const queryClientV5 = new QueryClientV5({
defaultOptions: { queries: { retry: false } },
})

const alertOptionWrapperCreator = (
alertOptionString: AlertOptionsType | '',
isCancellation?: boolean
) => {
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
<MemoryRouter initialEntries={['/billing/gh/codecov']}>
<Route path="/billing/:provider/:owner">
<QueryClientProvider client={queryClient}>
<PlanUpdatedPlanNotificationContext.Provider
value={{
updatedNotification: {
alertOption: alertOptionString,
isCancellation,
},
setUpdatedNotification: noop,
}}
>
{children}
</PlanUpdatedPlanNotificationContext.Provider>
</QueryClientProvider>
<QueryClientProviderV5 client={queryClientV5}>
<QueryClientProvider client={queryClient}>
<Suspense fallback={<div>Loading</div>}>
<PlanUpdatedPlanNotificationContext.Provider
value={{
updatedNotification: {
alertOption: alertOptionString,
isCancellation,
},
setUpdatedNotification: noop,
}}
>
{children}
</PlanUpdatedPlanNotificationContext.Provider>
</Suspense>
</QueryClientProvider>
</QueryClientProviderV5>
</Route>
</MemoryRouter>
)
Expand All @@ -112,18 +121,25 @@ const wrapper = alertOptionWrapperCreator(AlertOptions.SUCCESS)
const noUpdatedPlanWrapper = alertOptionWrapperCreator('')
const cancellationPlanWrapper = alertOptionWrapperCreator('', true)

beforeAll(() => server.listen())
beforeAll(() => {
server.listen()
})

afterEach(() => {
queryClient.clear()
queryClientV5.clear()
server.resetHandlers()
})
afterAll(() => server.close())

afterAll(() => {
server.close()
})

interface SetupArgs {
accountDetails?: z.infer<typeof AccountDetailsSchema>
enterpriseAccountDetails?: ReturnType<
typeof useEnterpriseAccountDetails
>['data']
enterpriseAccountDetails?: z.infer<
typeof EnterpriseAccountDetailsRequestSchema
>
}

describe('CurrentOrgPlan', () => {
Expand All @@ -132,12 +148,12 @@ describe('CurrentOrgPlan', () => {
enterpriseAccountDetails = mockNoEnterpriseAccount,
}: SetupArgs) {
server.use(
graphql.query('EnterpriseAccountDetails', () =>
HttpResponse.json({ data: enterpriseAccountDetails })
),
http.get('/internal/:provider/:owner/account-details', () =>
HttpResponse.json(accountDetails)
)
graphql.query('EnterpriseAccountDetails', () => {
return HttpResponse.json({ data: enterpriseAccountDetails })
}),
http.get('/internal/:provider/:owner/account-details', () => {
return HttpResponse.json(accountDetails)
})
)
}

Expand Down Expand Up @@ -402,8 +418,8 @@ describe('CurrentOrgPlan', () => {
setup({
enterpriseAccountDetails: mockEnterpriseAccountDetailsHundredPercent,
})

render(<CurrentOrgPlan />, { wrapper })

const banner = await screen.findByText(
/Your account is using 100% of its seats/
)
Expand Down
13 changes: 8 additions & 5 deletions src/pages/PlanPage/subRoutes/CurrentOrgPlan/CurrentOrgPlan.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useSuspenseQuery as useSuspenseQueryV5 } from '@tanstack/react-queryV5'
import { useParams } from 'react-router-dom'

import { usePlanUpdatedNotification } from 'pages/PlanPage/context'
Expand All @@ -9,10 +10,10 @@ import { Alert } from 'ui/Alert'
import AccountOrgs from './AccountOrgs'
import BillingDetails from './BillingDetails'
import CurrentPlanCard from './CurrentPlanCard'
import { useEnterpriseAccountDetails } from './hooks/useEnterpriseAccountDetails'
import InfoAlertCancellation from './InfoAlertCancellation'
import InfoMessageStripeCallback from './InfoMessageStripeCallback'
import LatestInvoiceCard from './LatestInvoiceCard'
import { EnterpriseAccountDetailsQueryOpts } from './queries/EnterpriseAccountDetailsQueryOpts'

interface URLParams {
provider: string
Expand All @@ -25,10 +26,12 @@ function CurrentOrgPlan() {
provider,
owner,
})
const { data: enterpriseDetails } = useEnterpriseAccountDetails({
provider,
owner,
})
const { data: enterpriseDetails } = useSuspenseQueryV5(
EnterpriseAccountDetailsQueryOpts({
provider,
owner,
})
)

const scheduledPhase = accountDetails?.scheduleDetail?.scheduledPhase
const isDelinquent = accountDetails?.delinquent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
QueryClientProvider as QueryClientProviderV5,
QueryClient as QueryClientV5,
useQuery as useQueryV5,
} from '@tanstack/react-queryV5'
import { renderHook, waitFor } from '@testing-library/react'
import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'

import { useEnterpriseAccountDetails } from './useEnterpriseAccountDetails'
import { EnterpriseAccountDetailsQueryOpts } from './EnterpriseAccountDetailsQueryOpts'

const mockEnterpriseAccountDetails = {
owner: {
account: {
name: 'account-name',
totalSeatCount: 10,
activatedUserCount: 7,
organizations: {
totalCount: 3,
},
organizations: { totalCount: 3 },
},
},
}

const queryClient = new QueryClient({
const queryClientV5 = new QueryClientV5({
defaultOptions: { queries: { retry: false } },
})
const server = setupServer()

const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
<QueryClientProviderV5 client={queryClientV5}>
{children}
</QueryClientProviderV5>
)

beforeAll(() => server.listen())
beforeAll(() => {
server.listen()
})

afterEach(() => {
queryClient.clear()
queryClientV5.clear()
server.resetHandlers()
})
afterAll(() => server.close())

afterAll(() => {
server.close()
})

interface SetupArgs {
badResponse?: boolean
Expand All @@ -54,7 +64,13 @@ describe('useEnterpriseAccountDetails', () => {
setup({ badResponse: true })
console.error = () => {}
const { result } = renderHook(
() => useEnterpriseAccountDetails({ provider: 'gh', owner: 'codecov' }),
() =>
useQueryV5(
EnterpriseAccountDetailsQueryOpts({
provider: 'gh',
owner: 'codecov',
})
),
{ wrapper }
)

Expand All @@ -73,10 +89,12 @@ describe('useEnterpriseAccountDetails', () => {
setup({})
const { result } = renderHook(
() =>
useEnterpriseAccountDetails({
provider: 'gh',
owner: 'codecov',
}),
useQueryV5(
EnterpriseAccountDetailsQueryOpts({
provider: 'gh',
owner: 'codecov',
})
),
{ wrapper }
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useQuery } from '@tanstack/react-query'
import { queryOptions as queryOptionsV5 } from '@tanstack/react-queryV5'
import { z } from 'zod'

import Api from 'shared/api/api'
import { NetworkErrorObject } from 'shared/api/helpers'
import { rejectNetworkError } from 'shared/api/helpers'

const AccountSchema = z.object({
name: z.string(),
Expand All @@ -15,7 +15,7 @@ const AccountSchema = z.object({

export type Account = z.infer<typeof AccountSchema>

const RequestSchema = z.object({
export const EnterpriseAccountDetailsRequestSchema = z.object({
owner: z
.object({
account: AccountSchema.nullable(),
Expand All @@ -36,16 +36,16 @@ const query = `query EnterpriseAccountDetails($owner: String!) {
}
}`

interface UseEnterpriseAccountDetailsArgs {
interface EnterpriseAccountDetailsQueryArgs {
provider: string
owner: string
}

export function useEnterpriseAccountDetails({
export function EnterpriseAccountDetailsQueryOpts({
provider,
owner,
}: UseEnterpriseAccountDetailsArgs) {
return useQuery({
}: EnterpriseAccountDetailsQueryArgs) {
return queryOptionsV5({
queryKey: ['EnterpriseAccountDetails', provider, owner],
queryFn: ({ signal }) =>
Api.graphql({
Expand All @@ -56,14 +56,17 @@ export function useEnterpriseAccountDetails({
owner,
},
}).then((res) => {
const parsedRes = RequestSchema.safeParse(res?.data)
const parsedRes = EnterpriseAccountDetailsRequestSchema.safeParse(
res?.data
)

if (!parsedRes.success) {
return Promise.reject({
return rejectNetworkError({
status: 404,
data: {},
dev: 'useEnterpriseAccountDetails - 404 Failed to parse data',
} satisfies NetworkErrorObject)
error: parsedRes.error,
})
}

return parsedRes.data
Expand Down

0 comments on commit 7b9fe28

Please sign in to comment.