Skip to content

Commit

Permalink
feat: New flake aggregate hook
Browse files Browse the repository at this point in the history
  • Loading branch information
RulaKhaled committed Oct 13, 2024
1 parent 6817eb9 commit 7de4e14
Show file tree
Hide file tree
Showing 3 changed files with 301 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useFlakeAggregates } from './useFlakeAggregates'
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { graphql, HttpResponse } from 'msw2'
import { setupServer } from 'msw2/node'
import { MemoryRouter, Route } from 'react-router-dom'
import { MockInstance } from 'vitest'

import { MeasurementInterval, useFlakeAggregates } from './useFlakeAggregates'

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

const wrapper = ({ children }: { children: React.ReactNode }) => (
<MemoryRouter initialEntries={['/gh/codecov/gazebo']}>
<Route path="/:provider/:owner/:repo">
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</Route>
</MemoryRouter>
)

const server = setupServer()

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

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

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

const mockNotFoundError = {
owner: {
repository: {
__typename: 'NotFoundError',
message: 'repo not found',
},
},
}

const mockIncorrectResponse = {
owner: {
repository: {
invalid: 'invalid',
},
},
}

const mockResponse = {
owner: {
repository: {
__typename: 'Repository',
testAnalytics: {
flakeAggregates: {
flakeCount: 10,
flakeCountPercentChange: 5.0,
flakeRate: 0.1,
flakeRatePercentChange: 2.0,
},
},
},
},
}

describe('useFlakeAggregates', () => {
function setup({
isNotFoundError = false,
isUnsuccessfulParseError = false,
}) {
server.use(
graphql.query('GetFlakeAggregates', (info) => {
if (isNotFoundError) {
return HttpResponse.json({ data: mockNotFoundError })
} else if (isUnsuccessfulParseError) {
return HttpResponse.json({ data: mockIncorrectResponse })
}
return HttpResponse.json({ data: mockResponse })
})
)
}

describe('when called with successful res', () => {
describe('when data is loaded', () => {
it('returns the data', async () => {
setup({})
const { result } = renderHook(
() =>
useFlakeAggregates({ history: MeasurementInterval.INTERVAL_1_DAY }),
{
wrapper,
}
)

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

await waitFor(() =>
expect(result.current.data).toEqual({
flakeCount: 10,
flakeCountPercentChange: 5.0,
flakeRate: 0.1,
flakeRatePercentChange: 2.0,
})
)
})
})
})

describe('when failed to parse data', () => {
let consoleSpy: MockInstance
beforeAll(() => {
consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
})

afterAll(() => {
consoleSpy.mockRestore()
})

it('returns a failed to parse error', async () => {
setup({ isUnsuccessfulParseError: true })
const { result } = renderHook(
() =>
useFlakeAggregates({ history: MeasurementInterval.INTERVAL_1_DAY }),
{
wrapper,
}
)

await waitFor(() =>
expect(result.current.error).toEqual(
expect.objectContaining({
status: 404,
dev: 'useFlakeAggregates - 404 Failed to parse data',
})
)
)
})
})

describe('when data not found', () => {
let consoleSpy: MockInstance
beforeAll(() => {
consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
})

afterAll(() => {
consoleSpy.mockRestore()
})

it('returns a not found error', async () => {
setup({ isNotFoundError: true })
const { result } = renderHook(
() =>
useFlakeAggregates({ history: MeasurementInterval.INTERVAL_1_DAY }),
{
wrapper,
}
)

await waitFor(() =>
expect(result.current.error).toEqual(
expect.objectContaining({
status: 404,
data: {},
})
)
)
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { useQuery } from '@tanstack/react-query'
import { useParams } from 'react-router-dom'
import { z } from 'zod'

import { RepoNotFoundErrorSchema } from 'services/repo'
import Api from 'shared/api'
import { NetworkErrorObject } from 'shared/api/helpers'

const FlakeAggregatesSchema = z.object({
owner: z
.object({
repository: z.discriminatedUnion('__typename', [
z.object({
__typename: z.literal('Repository'),
testAnalytics: z
.object({
flakeAggregates: z.object({
flakeCount: z.number(),
flakeCountPercentChange: z.number().nullable(),
flakeRate: z.number(),
flakeRatePercentChange: z.number().nullable(),
}),
})
.nullable(),
}),
RepoNotFoundErrorSchema,
]),
})
.nullable(),
})

const query = `
query GetFlakeAggregates(
$owner: String!
$repo: String!
$history: MeasurementInterval
) {
owner(username: $owner) {
repository: repository(name: $repo) {
__typename
... on Repository {
testAnalytics {
flakeAggregates(history: $history) {
flakeCount
flakeCountPercentChange
flakeRate
flakeRatePercentChange
}
}
}
... on NotFoundError {
message
}
}
}
}
`

export enum MeasurementInterval {
INTERVAL_1_DAY = 'INTERVAL_1_DAY',
INTERVAL_7_DAY = 'INTERVAL_7_DAY',
INTERVAL_30_DAY = 'INTERVAL_30_DAY',
}

interface URLParams {
provider: string
owner: string
repo: string
}

interface UseFlakeAggregatesOptions {
enabled?: boolean
suspense?: boolean
}

interface UseFlakeAggregatesParams {
history?: MeasurementInterval
opts?: UseFlakeAggregatesOptions
}

export const useFlakeAggregates = ({
history,
opts,
}: UseFlakeAggregatesParams) => {
const { provider, owner, repo } = useParams<URLParams>()

return useQuery({
queryKey: ['GetFlakeAggregates', provider, owner, repo, history],
queryFn: ({ signal }) =>
Api.graphql({
provider,
query,
signal,
variables: {
provider,
owner,
repo,
history,
},
}).then((res) => {
const parsedData = FlakeAggregatesSchema.safeParse(res?.data)

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

const data = parsedData.data

if (data?.owner?.repository?.__typename === 'NotFoundError') {
return Promise.reject({
status: 404,
data: {},
dev: 'useFlakeAggregates - 404 Not found error',
} satisfies NetworkErrorObject)
}

return data.owner?.repository.testAnalytics?.flakeAggregates
}),
...opts,
})
}

0 comments on commit 7de4e14

Please sign in to comment.