Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/codecov/gazebo into 625-rem…
Browse files Browse the repository at this point in the history
…ove-flags-page-for-team-tier
  • Loading branch information
adrian-codecov committed Oct 19, 2023
2 parents d478ca3 + 53e6b17 commit ebff54b
Show file tree
Hide file tree
Showing 3 changed files with 351 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/services/repos/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './useRepos'
export * from './config'
export * from './useReposTeam'
173 changes: 173 additions & 0 deletions src/services/repos/useReposTeam.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { graphql } from 'msw'
import { setupServer } from 'msw/node'
import { MemoryRouter, Route } from 'react-router-dom'

import { useReposTeam } from './useReposTeam'

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
})
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={['/gh/some-owner']}>
<Route path="/:provider/:owner">{children}</Route>
</MemoryRouter>
</QueryClientProvider>
)

const repo1 = {
name: 'codecov-bash',
active: true,
activated: true,
private: false,
latestCommitAt: '2021-04-22T14:09:39.826948+00:00',
lines: 99,
author: {
username: 'codecov',
},
}

const repo2 = {
name: 'codecov-bash-2',
active: true,
activated: true,
private: false,
latestCommitAt: '2021-04-22T14:09:39.826948+00:00',
lines: 99,
author: {
username: 'codecov',
},
}

const repo3 = {
name: 'codecov-bash-3',
active: true,
activated: true,
private: false,
latestCommitAt: '2021-04-22T14:09:39.826948+00:00',
lines: 99,
author: {
username: 'codecov',
},
}

const repo4 = {
name: 'codecov-bash-4',
active: true,
activated: true,
private: false,
latestCommitAt: '2021-04-22T14:09:39.826948+00:00',
lines: 99,
author: {
username: 'codecov',
},
}

const server = setupServer()

beforeAll(() => server.listen())
beforeEach(() => {
server.resetHandlers()
queryClient.clear()
})
afterAll(() => server.close())

describe('useReposTeam', () => {
function setup() {
server.use(
graphql.query('GetReposTeam', (req, res, ctx) => {
const data = {
owner: {
repositories: {
edges: req.variables.after
? [
{
node: repo3,
},
{
node: repo4,
},
]
: [
{
node: repo1,
},
{
node: repo2,
},
],
pageInfo: {
hasNextPage: req.variables.after ? false : true,
endCursor: req.variables.after
? 'aa'
: 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=',
},
},
},
}
return res(ctx.status(200), ctx.data(data))
})
)
}

describe('when called', () => {
beforeEach(() => {
setup()
})

it('returns repositories', async () => {
const { result } = renderHook(
() =>
useReposTeam({
activated: true,
owner: 'codecov',
}),
{
wrapper,
}
)

await waitFor(() =>
expect(result.current.data).toEqual({
repos: [repo1, repo2],
})
)
})
})

describe('when call next page', () => {
beforeEach(async () => {
setup()
})

it('returns repositories of the user', async () => {
const { result } = renderHook(
() =>
useReposTeam({
owner: 'codecov',
activated: true,
first: 2,
}),
{
wrapper,
}
)

await waitFor(() => result.current.isFetching)
await waitFor(() => !result.current.isFetching)

result.current.fetchNextPage()

await waitFor(() => result.current.isFetching)
await waitFor(() => !result.current.isFetching)

await waitFor(() =>
expect(result.current.data).toEqual({
repos: [repo1, repo2, repo3, repo4],
})
)
})
})
})
177 changes: 177 additions & 0 deletions src/services/repos/useReposTeam.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { useInfiniteQuery } from '@tanstack/react-query'
import { useParams } from 'react-router-dom'
import { z } from 'zod'

import Api from 'shared/api'
import { mapEdges } from 'shared/utils/graphql'

import { orderingOptions } from './config'

const RepositorySchema = z.object({
name: z.string(),
active: z.boolean(),
activated: z.boolean(),
private: z.boolean(),
latestCommitAt: z.string().nullable(),
lines: z.number().nullable(),
author: z.object({
username: z.string().nullable(),
}),
})

const repositoryFragment = `
fragment RepoForList on Repository {
name
active
activated
private
latestCommitAt
lines
author {
username
}
}
`

interface FetchReposTeamArgs {
provider: string
owner: string
variables: {
filters: {
activated: boolean
term?: string
repoNames?: string[]
}
ordering?: string
direction?: string
first?: number
}
after?: string
signal?: AbortSignal
}

const RequestSchema = z.object({
owner: z
.object({
repositories: z
.object({
edges: z.array(
z.object({
node: RepositorySchema,
})
),
pageInfo: z.object({
hasNextPage: z.boolean(),
endCursor: z.string().nullable(),
}),
})
.nullable(),
})
.nullable(),
})

function fetchReposForOwner({
provider,
owner,
variables,
after,
signal,
}: FetchReposTeamArgs) {
const query = `
query GetReposTeam($filters: RepositorySetFilters!, $owner: String!, $ordering: RepositoryOrdering!, $direction: OrderingDirection!, $after: String, $first: Int) {
owner(username: $owner) {
repositories(filters: $filters, ordering: $ordering, orderingDirection: $direction, first: $first, after: $after) {
edges {
node {
...RepoForList
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
${repositoryFragment}
`

return Api.graphql({
provider,
query,
signal,
variables: {
...variables,
owner,
after,
},
}).then((res) => {
const parsedRes = RequestSchema.safeParse(res?.data)

if (!parsedRes.success) {
return Promise.reject({
status: 404,
data: null,
})
}

const owner = parsedRes.data?.owner

return {
repos: mapEdges(owner?.repositories),
pageInfo: owner?.repositories?.pageInfo,
}
})
}

interface UseReposTeamArgs {
activated: boolean
term?: string
owner: string
sortItem?: {
ordering: string
direction: string
}
first?: number
repoNames?: string[]
}

export function useReposTeam({
activated,
term,
owner,
sortItem = orderingOptions[0],
first = 20,
repoNames,
...options
}: UseReposTeamArgs) {
const { provider } = useParams<{ provider: string }>()
const variables = {
filters: { activated, term, repoNames },
ordering: sortItem?.ordering,
direction: sortItem?.direction,
first,
}

const { data, ...rest } = useInfiniteQuery(
['GetReposTeam', provider, variables, owner],
({ pageParam, signal }) => {
return fetchReposForOwner({
provider,
variables,
owner,
after: pageParam,
signal,
})
},
{
getNextPageParam: (data) =>
data?.pageInfo?.hasNextPage ? data.pageInfo.endCursor : undefined,
...options,
}
)
return {
data: { repos: data?.pages.map((page) => page.repos).flat() },
...rest,
}
}

0 comments on commit ebff54b

Please sign in to comment.