From a1e07ef80e50f8a8147893db04e3232bb2f9ddd7 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 31 Dec 2024 12:37:26 -0500 Subject: [PATCH] ref: Migrate useReposTeam to TS Query V5 (#3615) --- ...m.test.tsx => ReposTeamQueryOpts.test.tsx} | 59 ++++++++---- ...seReposTeam.tsx => ReposTeamQueryOpts.tsx} | 50 +++++++--- src/services/repos/index.ts | 3 +- .../repos/{config.ts => orderingOptions.ts} | 0 src/services/repos/useRepos.tsx | 2 +- ...eTeam.test.jsx => ReposTableTeam.test.tsx} | 91 +++++++++---------- .../ReposTableTeam/ReposTableTeam.tsx | 31 ++++--- .../ReposTableTeam/{index.js => index.ts} | 0 8 files changed, 140 insertions(+), 96 deletions(-) rename src/services/repos/{useReposTeam.test.tsx => ReposTeamQueryOpts.test.tsx} (77%) rename src/services/repos/{useReposTeam.tsx => ReposTeamQueryOpts.tsx} (75%) rename src/services/repos/{config.ts => orderingOptions.ts} (100%) rename src/shared/ListRepo/ReposTableTeam/{ReposTableTeam.test.jsx => ReposTableTeam.test.tsx} (95%) rename src/shared/ListRepo/ReposTableTeam/{index.js => index.ts} (100%) diff --git a/src/services/repos/useReposTeam.test.tsx b/src/services/repos/ReposTeamQueryOpts.test.tsx similarity index 77% rename from src/services/repos/useReposTeam.test.tsx rename to src/services/repos/ReposTeamQueryOpts.test.tsx index b2e1e4d839..366b5aaa92 100644 --- a/src/services/repos/useReposTeam.test.tsx +++ b/src/services/repos/ReposTeamQueryOpts.test.tsx @@ -1,21 +1,25 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { + QueryClientProvider as QueryClientProviderV5, + QueryClient as QueryClientV5, + useInfiniteQuery as useInfiniteQueryV5, +} from '@tanstack/react-queryV5' import { renderHook, waitFor } from '@testing-library/react' import { graphql, HttpResponse } from 'msw' import { setupServer } from 'msw/node' import { MemoryRouter, Route } from 'react-router-dom' import { MockInstance } from 'vitest' -import { useReposTeam } from './useReposTeam' +import { ReposTeamQueryOpts } from './ReposTeamQueryOpts' -const queryClient = new QueryClient({ +const queryClientV5 = new QueryClientV5({ defaultOptions: { queries: { retry: false } }, }) const wrapper: React.FC = ({ children }) => ( - + {children} - + ) const repo1 = { @@ -88,8 +92,8 @@ beforeAll(() => { }) beforeEach(() => { + queryClientV5.clear() server.resetHandlers() - queryClient.clear() }) afterAll(() => { @@ -129,7 +133,14 @@ describe('useReposTeam', () => { it('returns repositories', async () => { setup() const { result } = renderHook( - () => useReposTeam({ activated: true, owner: 'codecov' }), + () => + useInfiniteQueryV5( + ReposTeamQueryOpts({ + provider: 'gh', + activated: true, + owner: 'codecov', + }) + ), { wrapper } ) @@ -145,7 +156,7 @@ describe('useReposTeam', () => { }, }, ], - pageParams: [undefined], + pageParams: [''], }) ) }) @@ -155,7 +166,15 @@ describe('useReposTeam', () => { it('returns repositories of the user', async () => { setup() const { result } = renderHook( - () => useReposTeam({ owner: 'codecov', activated: true, first: 2 }), + () => + useInfiniteQueryV5( + ReposTeamQueryOpts({ + provider: 'gh', + activated: true, + owner: 'codecov', + first: 2, + }) + ), { wrapper } ) @@ -178,13 +197,10 @@ describe('useReposTeam', () => { { repos: [repo3, repo4], isCurrentUserPartOfOrg: true, - pageInfo: { - hasNextPage: false, - endCursor: 'aa', - }, + pageInfo: { hasNextPage: false, endCursor: 'aa' }, }, ], - pageParams: [undefined, 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA='], + pageParams: ['', 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA='], }) ) }) @@ -204,13 +220,24 @@ describe('useReposTeam', () => { it('throws an error', async () => { setup({ invalidResponse: true }) const { result } = renderHook( - () => useReposTeam({ owner: 'codecov', activated: true, first: 2 }), + () => + useInfiniteQueryV5( + ReposTeamQueryOpts({ + provider: 'gh', + activated: true, + owner: 'codecov', + first: 2, + }) + ), { wrapper } ) await waitFor(() => expect(result.current.error).toEqual( - expect.objectContaining({ status: 404 }) + expect.objectContaining({ + status: 404, + dev: 'ReposTeamQueryOpts - 404 Failed to parse schema', + }) ) ) }) diff --git a/src/services/repos/useReposTeam.tsx b/src/services/repos/ReposTeamQueryOpts.tsx similarity index 75% rename from src/services/repos/useReposTeam.tsx rename to src/services/repos/ReposTeamQueryOpts.tsx index 5dcebb842c..a5008a348d 100644 --- a/src/services/repos/useReposTeam.tsx +++ b/src/services/repos/ReposTeamQueryOpts.tsx @@ -1,11 +1,16 @@ -import { useInfiniteQuery } from '@tanstack/react-query' -import { useParams } from 'react-router-dom' +import { infiniteQueryOptions as infiniteQueryOptionsV5 } from '@tanstack/react-queryV5' import { z } from 'zod' import Api from 'shared/api' +import { rejectNetworkError } from 'shared/api/helpers' import { mapEdges } from 'shared/utils/graphql' -import { orderingOptions } from './config' +import { + nonActiveOrderingOptions, + OrderingDirection, + orderingOptions, + TeamOrdering, +} from './orderingOptions' const RepositorySchema = z .object({ @@ -27,7 +32,7 @@ const RepositorySchema = z }) .nullable() -export type Repository = z.infer +type Repository = z.infer const RequestSchema = z.object({ owner: z @@ -92,7 +97,8 @@ const query = `query GetReposTeam( } }` -interface UseReposTeamArgs { +interface ReposTeamQueryArgs { + provider: string activated?: boolean term?: string owner: string @@ -104,16 +110,15 @@ interface UseReposTeamArgs { repoNames?: string[] } -export function useReposTeam({ +function ReposTeamQueryOpts({ + provider, activated, term, owner, sortItem = orderingOptions[0], first = 20, repoNames, - ...options -}: UseReposTeamArgs) { - const { provider } = useParams<{ provider: string }>() +}: ReposTeamQueryArgs) { const variables = { filters: { activated, term, repoNames }, ordering: sortItem?.ordering, @@ -121,7 +126,7 @@ export function useReposTeam({ first, } - return useInfiniteQuery({ + return infiniteQueryOptionsV5({ queryKey: ['GetReposTeam', provider, variables, owner], queryFn: ({ pageParam, signal }) => { return Api.graphql({ @@ -137,9 +142,11 @@ export function useReposTeam({ const parsedRes = RequestSchema.safeParse(res?.data) if (!parsedRes.success) { - return Promise.reject({ + return rejectNetworkError({ status: 404, - data: null, + data: {}, + dev: 'ReposTeamQueryOpts - 404 Failed to parse schema', + error: parsedRes.error, }) } @@ -152,8 +159,21 @@ export function useReposTeam({ } }) }, - getNextPageParam: (data) => - data?.pageInfo?.hasNextPage ? data.pageInfo.endCursor : undefined, - ...options, + initialPageParam: '', + getNextPageParam: (data) => { + if (data?.pageInfo?.hasNextPage) { + return data.pageInfo.endCursor + } + return null + }, }) } + +export { + type Repository, + orderingOptions, + nonActiveOrderingOptions, + OrderingDirection, + ReposTeamQueryOpts, + TeamOrdering, +} diff --git a/src/services/repos/index.ts b/src/services/repos/index.ts index d541d18530..ae1f8c951b 100644 --- a/src/services/repos/index.ts +++ b/src/services/repos/index.ts @@ -1,3 +1,2 @@ export * from './useRepos' -export * from './config' -export * from './useReposTeam' +export * from './orderingOptions' diff --git a/src/services/repos/config.ts b/src/services/repos/orderingOptions.ts similarity index 100% rename from src/services/repos/config.ts rename to src/services/repos/orderingOptions.ts diff --git a/src/services/repos/useRepos.tsx b/src/services/repos/useRepos.tsx index ec15bd3007..73ac854710 100644 --- a/src/services/repos/useRepos.tsx +++ b/src/services/repos/useRepos.tsx @@ -5,7 +5,7 @@ import { RepositoryConfigSchema } from 'services/repo/useRepoConfig' import Api from 'shared/api' import { mapEdges } from 'shared/utils/graphql' -import { orderingOptions } from './config' +import { orderingOptions } from './orderingOptions' const RepositorySchema = z .object({ diff --git a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.jsx b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx similarity index 95% rename from src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.jsx rename to src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx index 4b0782311f..4d78b98db9 100644 --- a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.jsx +++ b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.test.tsx @@ -1,4 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { + QueryClientProvider as QueryClientProviderV5, + QueryClient as QueryClientV5, +} from '@tanstack/react-queryV5' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { subDays } from 'date-fns' @@ -16,14 +20,34 @@ import { repoDisplayOptions } from '../ListRepo' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() +const queryClientV5 = new QueryClientV5({ + defaultOptions: { queries: { retry: false } }, +}) + +const wrapper = + (repoDisplay: string): React.FC => + ({ children }) => ( + + + + + + {children} + + + + + + ) +const server = setupServer() beforeAll(() => { server.listen() }) afterEach(() => { queryClient.clear() + queryClientV5.clear() server.resetHandlers() }) @@ -31,22 +55,13 @@ afterAll(() => { server.close() }) -const wrapper = - (repoDisplay) => - ({ children }) => ( - - - - - {children} - - - - - ) +interface SetupArgs { + edges: object[] + isCurrentUserPartOfOrg?: boolean +} describe('ReposTableTeam', () => { - function setup({ edges = [], isCurrentUserPartOfOrg = true }) { + function setup({ edges = [], isCurrentUserPartOfOrg = true }: SetupArgs) { const mockApiVars = vi.fn() const fetchNextPage = vi.fn() const user = userEvent.setup() @@ -80,8 +95,13 @@ describe('ReposTableTeam', () => { } describe('rendering table', () => { + interface EdgeArgs { + coverageEnabled?: boolean + bundleAnalysisEnabled?: boolean + } + const edges = ( - { coverageEnabled, bundleAnalysisEnabled } = { + { coverageEnabled = true, bundleAnalysisEnabled = true }: EdgeArgs = { coverageEnabled: true, bundleAnalysisEnabled: true, } @@ -444,15 +464,8 @@ describe('ReposTableTeam', () => { }) describe('when rendered empty repos', () => { - beforeEach(() => { - setup({ - edges: [], - repoDisplayPassed: repoDisplayOptions.ALL.text, - privateAccess: true, - }) - }) - it('renders no repos detected', async () => { + setup({ edges: [] }) render(, { wrapper: wrapper(repoDisplayOptions.CONFIGURED.text), }) @@ -469,12 +482,8 @@ describe('ReposTableTeam', () => { }) describe('when rendered empty search', () => { - beforeEach(() => { - setup({ - edges: [], - }) - }) it('renders no results found', async () => { + setup({ edges: [] }) render(, { wrapper: wrapper(repoDisplayOptions.ALL.text), }) @@ -911,24 +920,14 @@ describe('ReposTableTeam', () => { describe('getSortingOption', () => { it('returns the correct sorting options for name column', () => { - const nameAsc = getSortingOption([ - { - id: 'name', - desc: false, - }, - ]) + const nameAsc = getSortingOption([{ id: 'name', desc: false }]) expect(nameAsc).toEqual({ ordering: TeamOrdering.NAME, direction: OrderingDirection.ASC, }) - const nameDesc = getSortingOption([ - { - id: 'name', - desc: true, - }, - ]) + const nameDesc = getSortingOption([{ id: 'name', desc: true }]) expect(nameDesc).toEqual({ ordering: TeamOrdering.NAME, @@ -938,10 +937,7 @@ describe('getSortingOption', () => { it('returns the correct sorting options for last updated column', () => { const lastUpdatedAsc = getSortingOption([ - { - id: 'latestCommitAt', - desc: false, - }, + { id: 'latestCommitAt', desc: false }, ]) expect(lastUpdatedAsc).toEqual({ @@ -950,10 +946,7 @@ describe('getSortingOption', () => { }) const lastUpdatedDesc = getSortingOption([ - { - id: 'latestCommitAt', - desc: true, - }, + { id: 'latestCommitAt', desc: true }, ]) expect(lastUpdatedDesc).toEqual({ diff --git a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx index ee78d834bd..fd12686adf 100644 --- a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx +++ b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx @@ -1,3 +1,4 @@ +import { useInfiniteQuery as useInfiniteQueryV5 } from '@tanstack/react-queryV5' import type { SortingState } from '@tanstack/react-table' import { createColumnHelper, @@ -8,16 +9,16 @@ import { } from '@tanstack/react-table' import cs from 'classnames' import isEmpty from 'lodash/isEmpty' -import PropTypes from 'prop-types' import { useContext, useMemo, useState } from 'react' import { useParams } from 'react-router-dom' import { OrderingDirection, Repository, + ReposTeamQueryOpts, TeamOrdering, - useReposTeam, -} from 'services/repos' +} from 'services/repos/ReposTeamQueryOpts' +import { Provider } from 'shared/api/helpers' import { ActiveContext } from 'shared/context' import { formatTimeToNow } from 'shared/utils/dates' import Button from 'ui/Button' @@ -144,7 +145,12 @@ const getColumns = ({ ] } +interface URLParams { + provider: Provider +} + const ReposTableTeam = ({ searchValue }: ReposTableTeamProps) => { + const { provider } = useParams() const [sorting, setSorting] = useState([ { id: 'latestCommitAt', @@ -168,12 +174,15 @@ const ReposTableTeam = ({ searchValue }: ReposTableTeamProps) => { hasNextPage, isFetching, isFetchingNextPage, - } = useReposTeam({ - activated, - sortItem: getSortingOption(sorting), - term: searchValue, - owner, - }) + } = useInfiniteQueryV5( + ReposTeamQueryOpts({ + provider, + activated, + sortItem: getSortingOption(sorting), + term: searchValue, + owner, + }) + ) const isCurrentUserPartOfOrg = !!reposData?.pages?.[0]?.isCurrentUserPartOfOrg @@ -278,8 +287,4 @@ const ReposTableTeam = ({ searchValue }: ReposTableTeamProps) => { ) } -ReposTableTeam.propTypes = { - searchValue: PropTypes.string.isRequired, -} - export default ReposTableTeam diff --git a/src/shared/ListRepo/ReposTableTeam/index.js b/src/shared/ListRepo/ReposTableTeam/index.ts similarity index 100% rename from src/shared/ListRepo/ReposTableTeam/index.js rename to src/shared/ListRepo/ReposTableTeam/index.ts