From 8815859fc7a1f4cac94dab72e7781ddef8afd3c4 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 09:11:11 -0300 Subject: [PATCH 01/20] chore: Update ui/CIStatus to Vitest (#3265) --- src/ui/CIStatus/CIStatus.spec.jsx | 26 ----------------- src/ui/CIStatus/CIStatus.stories.jsx | 23 --------------- src/ui/CIStatus/CIStatus.stories.tsx | 27 ++++++++++++++++++ src/ui/CIStatus/CIStatus.test.jsx | 28 +++++++++++++++++++ .../CIStatus/{CIStatus.jsx => CIStatus.tsx} | 25 +++++++---------- src/ui/CIStatus/{index.js => index.ts} | 0 6 files changed, 65 insertions(+), 64 deletions(-) delete mode 100644 src/ui/CIStatus/CIStatus.spec.jsx delete mode 100644 src/ui/CIStatus/CIStatus.stories.jsx create mode 100644 src/ui/CIStatus/CIStatus.stories.tsx create mode 100644 src/ui/CIStatus/CIStatus.test.jsx rename src/ui/CIStatus/{CIStatus.jsx => CIStatus.tsx} (50%) rename src/ui/CIStatus/{index.js => index.ts} (100%) diff --git a/src/ui/CIStatus/CIStatus.spec.jsx b/src/ui/CIStatus/CIStatus.spec.jsx deleted file mode 100644 index ab024a3644..0000000000 --- a/src/ui/CIStatus/CIStatus.spec.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import { render, screen } from '@testing-library/react' - -import CIStatus from '.' - -describe('CIStatus', () => { - function setup(props) { - render() - } - - describe('when rendered', () => { - it('shows ci passed', () => { - setup({ ciPassed: true }) - expect(screen.getByText(/Passed/)).toBeInTheDocument() - }) - - it('shows ci failed', () => { - setup({ ciPassed: false }) - expect(screen.getByText(/Failed/)).toBeInTheDocument() - }) - - it('shows no status if no status is given', () => { - setup({}) - expect(screen.getByText(/No Status/)).toBeInTheDocument() - }) - }) -}) diff --git a/src/ui/CIStatus/CIStatus.stories.jsx b/src/ui/CIStatus/CIStatus.stories.jsx deleted file mode 100644 index a2faed7fe8..0000000000 --- a/src/ui/CIStatus/CIStatus.stories.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import CIStatus from './CIStatus' - -const Template = (args) => - -export const Passing = Template.bind({}) -Passing.args = { - ciPassed: true, -} - -export const Failing = Template.bind({}) -Failing.args = { - ciPassed: false, -} - -export const NoStatus = Template.bind({}) -NoStatus.args = { - ciPassed: null, -} - -export default { - title: 'Components/CIStatus', - component: CIStatus, -} diff --git a/src/ui/CIStatus/CIStatus.stories.tsx b/src/ui/CIStatus/CIStatus.stories.tsx new file mode 100644 index 0000000000..5a814ec1d0 --- /dev/null +++ b/src/ui/CIStatus/CIStatus.stories.tsx @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import CIStatus from './CIStatus' + +const meta: Meta = { + title: 'Components/CIStatus', + component: CIStatus, +} + +export default meta + +type Story = StoryObj + +export const Passing: Story = { + args: { ciPassed: true }, + render: (args) => , +} + +export const Failing: Story = { + args: { ciPassed: false }, + render: (args) => , +} + +export const NoStatus: Story = { + args: { ciPassed: null }, + render: (args) => , +} diff --git a/src/ui/CIStatus/CIStatus.test.jsx b/src/ui/CIStatus/CIStatus.test.jsx new file mode 100644 index 0000000000..017b7dbd01 --- /dev/null +++ b/src/ui/CIStatus/CIStatus.test.jsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react' + +import CIStatus from '.' + +describe('CIStatus', () => { + describe('when rendered', () => { + it('shows ci passed', () => { + render() + + const passed = screen.getByText(/Passed/) + expect(passed).toBeInTheDocument() + }) + + it('shows ci failed', () => { + render() + + const failed = screen.getByText(/Failed/) + expect(failed).toBeInTheDocument() + }) + + it('shows no status if no status is given', () => { + render() + + const noStatus = screen.getByText(/No Status/) + expect(noStatus).toBeInTheDocument() + }) + }) +}) diff --git a/src/ui/CIStatus/CIStatus.jsx b/src/ui/CIStatus/CIStatus.tsx similarity index 50% rename from src/ui/CIStatus/CIStatus.jsx rename to src/ui/CIStatus/CIStatus.tsx index 46db6375f1..3fdeb9825c 100644 --- a/src/ui/CIStatus/CIStatus.jsx +++ b/src/ui/CIStatus/CIStatus.tsx @@ -1,11 +1,11 @@ -import cs from 'classnames' -import isNil from 'lodash/isNil' -import PropTypes from 'prop-types' - import Icon from 'ui/Icon' -export default function CIStatusLabel({ ciPassed }) { - if (isNil(ciPassed)) { +interface CIStatusLabelProps { + ciPassed?: boolean | null +} + +export default function CIStatusLabel({ ciPassed }: CIStatusLabelProps) { + if (typeof ciPassed !== 'boolean') { return ( @@ -16,21 +16,16 @@ export default function CIStatusLabel({ ciPassed }) { ) } + const iconName = ciPassed ? 'check' : 'x' + return ( - + CI {ciPassed ? 'Passed' : 'Failed'} ) } - -CIStatusLabel.propTypes = { - ciPassed: PropTypes.bool, -} diff --git a/src/ui/CIStatus/index.js b/src/ui/CIStatus/index.ts similarity index 100% rename from src/ui/CIStatus/index.js rename to src/ui/CIStatus/index.ts From c7f2bf44d2f05bb8f8d1261681edcb54762341f0 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 09:20:08 -0300 Subject: [PATCH 02/20] chore: Update services/access to Vitest (#3294) --- src/services/access/constants.js | 3 -- src/services/access/constants.ts | 3 ++ ...ion.spec.tsx => useDeleteSession.test.tsx} | 18 ++++++--- ....spec.js => useGenerateUserToken.test.jsx} | 39 ++++++++----------- ...n.spec.tsx => useRevokeUserToken.test.tsx} | 33 +++++++--------- src/services/access/useRevokeUserToken.ts | 18 ++++----- ...Sessions.spec.tsx => useSessions.test.tsx} | 19 +++++---- 7 files changed, 66 insertions(+), 67 deletions(-) delete mode 100644 src/services/access/constants.js create mode 100644 src/services/access/constants.ts rename src/services/access/{useDeleteSession.spec.tsx => useDeleteSession.test.tsx} (80%) rename src/services/access/{useGenerateUserToken.spec.js => useGenerateUserToken.test.jsx} (65%) rename src/services/access/{useRevokeUserToken.spec.tsx => useRevokeUserToken.test.tsx} (69%) rename src/services/access/{useSessions.spec.tsx => useSessions.test.tsx} (92%) diff --git a/src/services/access/constants.js b/src/services/access/constants.js deleted file mode 100644 index 790fea8dd5..0000000000 --- a/src/services/access/constants.js +++ /dev/null @@ -1,3 +0,0 @@ -export const USER_TOKEN_TYPE = Object.freeze({ - API: 'api', -}) diff --git a/src/services/access/constants.ts b/src/services/access/constants.ts new file mode 100644 index 0000000000..8672cdf900 --- /dev/null +++ b/src/services/access/constants.ts @@ -0,0 +1,3 @@ +export const USER_TOKEN_TYPE = { + API: 'api', +} as const diff --git a/src/services/access/useDeleteSession.spec.tsx b/src/services/access/useDeleteSession.test.tsx similarity index 80% rename from src/services/access/useDeleteSession.spec.tsx rename to src/services/access/useDeleteSession.test.tsx index ed40c3d30b..263aa29ef4 100644 --- a/src/services/access/useDeleteSession.spec.tsx +++ b/src/services/access/useDeleteSession.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useDeleteSession } from './useDeleteSession' @@ -21,18 +21,24 @@ const provider = 'gh' const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useDeleteSession', () => { function setup() { server.use( - rest.post(`/graphql/gh`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ data: { me: null } })) + graphql.mutation('DeleteSession', (info) => { + return HttpResponse.json({ data: { deleteSession: { error: null } } }) }) ) } diff --git a/src/services/access/useGenerateUserToken.spec.js b/src/services/access/useGenerateUserToken.test.jsx similarity index 65% rename from src/services/access/useGenerateUserToken.spec.js rename to src/services/access/useGenerateUserToken.test.jsx index 50dffb765c..2432075e27 100644 --- a/src/services/access/useGenerateUserToken.spec.js +++ b/src/services/access/useGenerateUserToken.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useGenerateUserToken } from './index' @@ -20,46 +20,39 @@ const wrapper = ({ children }) => ( const provider = 'gh' const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useGenerateUserToken', () => { function setup(dataReturned) { server.use( - graphql.mutation(`CreateUserToken`, (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ data: dataReturned })) + graphql.mutation(`CreateUserToken`, (info) => { + return HttpResponse.json({ data: dataReturned }) }) ) } describe('when called', () => { - beforeEach(() => { - setup({ - me: null, - }) - }) - describe('when calling the mutation', () => { - const data = { - sessionid: 1, - } - it('returns success', async () => { + setup({ me: null }) + const { result } = renderHook( () => useGenerateUserToken({ provider }), - { - wrapper, - } + { wrapper } ) - result.current.mutate(data) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) + result.current.mutate({ sessionid: 1 }) await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) }) diff --git a/src/services/access/useRevokeUserToken.spec.tsx b/src/services/access/useRevokeUserToken.test.tsx similarity index 69% rename from src/services/access/useRevokeUserToken.spec.tsx rename to src/services/access/useRevokeUserToken.test.tsx index db37a5dd01..7eebbb6357 100644 --- a/src/services/access/useRevokeUserToken.spec.tsx +++ b/src/services/access/useRevokeUserToken.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useRevokeUserToken } from './index' @@ -20,12 +20,18 @@ const wrapper: React.FC = ({ children }) => ( const provider = 'gh' const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) interface SetupArgs { me: null @@ -34,32 +40,21 @@ interface SetupArgs { describe('useRevokeUserToken', () => { function setup(dataReturned: SetupArgs) { server.use( - rest.post(`/graphql/gh`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ data: dataReturned })) + graphql.mutation('RevokeUserToken', (info) => { + return HttpResponse.json({ data: dataReturned }) }) ) } describe('when called', () => { - beforeEach(() => { - setup({ - me: null, - }) - }) - describe('when calling the mutation', () => { - const data = { - tokenid: '1', - } - it('returns success', async () => { + setup({ me: null }) const { result } = renderHook(() => useRevokeUserToken({ provider }), { wrapper, }) - result.current.mutate(data) - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) + result.current.mutate({ tokenid: '1' }) await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) }) diff --git a/src/services/access/useRevokeUserToken.ts b/src/services/access/useRevokeUserToken.ts index da9964fd0f..b834e7b17b 100644 --- a/src/services/access/useRevokeUserToken.ts +++ b/src/services/access/useRevokeUserToken.ts @@ -2,19 +2,19 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import Api from 'shared/api' +const query = ` +mutation RevokeUserToken($input: RevokeUserTokenInput!) { + revokeUserToken(input: $input) { + error { + __typename + } + } +}` + export function useRevokeUserToken({ provider }: { provider: string }) { const queryClient = useQueryClient() return useMutation({ mutationFn: ({ tokenid }: { tokenid: string }) => { - const query = ` - mutation RevokeUserToken($input: RevokeUserTokenInput!) { - revokeUserToken(input: $input) { - error { - __typename - } - } - } - ` return Api.graphqlMutation({ provider, query, diff --git a/src/services/access/useSessions.spec.tsx b/src/services/access/useSessions.test.tsx similarity index 92% rename from src/services/access/useSessions.spec.tsx rename to src/services/access/useSessions.test.tsx index a0047ad3e5..da8afe8048 100644 --- a/src/services/access/useSessions.spec.tsx +++ b/src/services/access/useSessions.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -72,13 +72,18 @@ const tokens: { edges: { node: UserToken }[] } = { } const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) interface SetupArgs { isUnsuccessfulParseError?: boolean @@ -104,11 +109,11 @@ describe('useSessions', () => { dataReturned = { me: null }, }: SetupArgs) { server.use( - graphql.query('MySessions', (req, res, ctx) => { + graphql.query('MySessions', (info) => { if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - return res(ctx.status(200), ctx.data(dataReturned)) + return HttpResponse.json({ data: dataReturned }) }) ) } From 09b16e249ba67d6ea7115c7f80dfcb014fd36be9 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 09:32:42 -0300 Subject: [PATCH 03/20] chore: Update services/account tests to Vitest (#3295) --- ...ls.spec.tsx => useAccountDetails.test.tsx} | 26 ++--- ...ivate.spec.js => useAutoActivate.test.jsx} | 66 ++++++----- ...ns.spec.tsx => useAvailablePlans.test.tsx} | 22 ++-- ...celPlan.spec.js => useCancelPlan.test.jsx} | 31 +++--- ...count.spec.js => useEraseAccount.test.jsx} | 40 ++++--- ...seInvoice.spec.tsx => useInvoice.test.tsx} | 40 ++++--- ...Invoices.spec.tsx => useInvoices.test.tsx} | 36 ++++-- ...PlanData.spec.tsx => usePlanData.test.tsx} | 21 ++-- ...Token.spec.tsx => useSentryToken.test.tsx} | 105 +++++++----------- ...c.tsx => useUpdateBillingAddress.test.tsx} | 25 ++--- ...pec.tsx => useUpdateBillingEmail.test.tsx} | 28 ++--- ...teCard.spec.tsx => useUpdateCard.test.tsx} | 77 +++++++------ ...x => useUpdateSelfHostedSettings.test.tsx} | 81 ++++++++------ ...ePlan.spec.tsx => useUpgradePlan.test.tsx} | 99 ++++++++++------- 14 files changed, 355 insertions(+), 342 deletions(-) rename src/services/account/{useAccountDetails.spec.tsx => useAccountDetails.test.tsx} (81%) rename src/services/account/{useAutoActivate.spec.js => useAutoActivate.test.jsx} (80%) rename src/services/account/{useAvailablePlans.spec.tsx => useAvailablePlans.test.tsx} (91%) rename src/services/account/{useCancelPlan.spec.js => useCancelPlan.test.jsx} (79%) rename src/services/account/{useEraseAccount.spec.js => useEraseAccount.test.jsx} (69%) rename src/services/account/{useInvoice.spec.tsx => useInvoice.test.tsx} (73%) rename src/services/account/{useInvoices.spec.tsx => useInvoices.test.tsx} (75%) rename src/services/account/{usePlanData.spec.tsx => usePlanData.test.tsx} (88%) rename src/services/account/{useSentryToken.spec.tsx => useSentryToken.test.tsx} (82%) rename src/services/account/{useUpdateBillingAddress.spec.tsx => useUpdateBillingAddress.test.tsx} (89%) rename src/services/account/{useUpdateBillingEmail.spec.tsx => useUpdateBillingEmail.test.tsx} (82%) rename src/services/account/{useUpdateCard.spec.tsx => useUpdateCard.test.tsx} (71%) rename src/services/account/{useUpdateSelfHostedSettings.spec.tsx => useUpdateSelfHostedSettings.test.tsx} (67%) rename src/services/account/{useUpgradePlan.spec.tsx => useUpgradePlan.test.tsx} (64%) diff --git a/src/services/account/useAccountDetails.spec.tsx b/src/services/account/useAccountDetails.test.tsx similarity index 81% rename from src/services/account/useAccountDetails.spec.tsx rename to src/services/account/useAccountDetails.test.tsx index d40b48e5e1..4bdd920d03 100644 --- a/src/services/account/useAccountDetails.spec.tsx +++ b/src/services/account/useAccountDetails.test.tsx @@ -1,14 +1,14 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' import { accountDetailsObject, accountDetailsParsedObj } from './mocks' import { useAccountDetails } from './useAccountDetails' -jest.mock('js-cookie') +vi.mock('js-cookie') const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -33,10 +33,12 @@ beforeAll(() => { process.env.REACT_APP_ZOD_IGNORE_TESTS = 'false' server.listen() }) + afterEach(() => { queryClient.clear() server.resetHandlers() }) + afterAll(() => { process.env.REACT_APP_ZOD_IGNORE_TESTS = 'true' server.close() @@ -45,26 +47,18 @@ afterAll(() => { describe('useAccountDetails', () => { function setup() { server.use( - rest.get( - `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json(accountDetailsObject)) - } - ) + http.get(`/internal/${provider}/${owner}/account-details/`, (info) => { + return HttpResponse.json(accountDetailsObject) + }) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('returns the data', async () => { + setup() const { result } = renderHook( () => useAccountDetails({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) await waitFor(() => diff --git a/src/services/account/useAutoActivate.spec.js b/src/services/account/useAutoActivate.test.jsx similarity index 80% rename from src/services/account/useAutoActivate.spec.js rename to src/services/account/useAutoActivate.test.jsx index 74c0d18f4a..7206042eaf 100644 --- a/src/services/account/useAutoActivate.spec.js +++ b/src/services/account/useAutoActivate.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useAutoActivate } from './useAutoActivate' @@ -23,12 +23,21 @@ const wrapper = const provider = 'gh' const owner = 'codecov' -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) describe('useAutoActivate', () => { - let onSuccess = jest.fn() + let onSuccess = vi.fn() const opts = { onSuccess, } @@ -36,21 +45,18 @@ describe('useAutoActivate', () => { describe('options is set', () => { function setup() { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json({})) + (info) => { + return HttpResponse.json({}) } ) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('opts are passed through to react-query', async () => { + setup() const { result } = renderHook( () => useAutoActivate({ @@ -58,9 +64,7 @@ describe('useAutoActivate', () => { owner, opts, }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(true) @@ -69,6 +73,7 @@ describe('useAutoActivate', () => { }) it('accountDetails cache unchanged', async () => { + setup() const { result } = renderHook( () => useAutoActivate({ @@ -76,9 +81,7 @@ describe('useAutoActivate', () => { owner, opts, }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(true) @@ -89,6 +92,7 @@ describe('useAutoActivate', () => { }) it('users cache unchanged', async () => { + setup() const { result } = renderHook( () => useAutoActivate({ @@ -96,9 +100,7 @@ describe('useAutoActivate', () => { owner, opts, }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(true) @@ -111,30 +113,25 @@ describe('useAutoActivate', () => { describe('opts is not set', () => { function setup() { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json({})) + (info) => { + return HttpResponse.json({}) } ) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('accountDetails cache unchanged', async () => { + setup() const { result } = renderHook( () => useAutoActivate({ provider, owner, }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(true) @@ -145,15 +142,14 @@ describe('useAutoActivate', () => { }) it('users cache unchanged', async () => { + setup() const { result } = renderHook( () => useAutoActivate({ provider, owner, }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(true) diff --git a/src/services/account/useAvailablePlans.spec.tsx b/src/services/account/useAvailablePlans.test.tsx similarity index 91% rename from src/services/account/useAvailablePlans.spec.tsx rename to src/services/account/useAvailablePlans.test.tsx index bc2e40845d..f5ef0d85b5 100644 --- a/src/services/account/useAvailablePlans.spec.tsx +++ b/src/services/account/useAvailablePlans.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useAvailablePlans } from './useAvailablePlans' @@ -108,12 +108,12 @@ const mockUnsuccessfulParseError = {} const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( {children} ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -138,13 +138,13 @@ describe('useAvailablePlans', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetAvailablePlans', (req, res, ctx) => { + graphql.query('GetAvailablePlans', (info) => { if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockAvailablePlansRes)) + return HttpResponse.json({ data: mockAvailablePlansRes }) } }) ) @@ -191,11 +191,11 @@ describe('useAvailablePlans', () => { describe('unsuccessful parse of zod schema', () => { beforeEach(() => { - jest.spyOn(console, 'error') + vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + vi.restoreAllMocks() }) it('throws a 404', async () => { @@ -206,9 +206,7 @@ describe('useAvailablePlans', () => { provider: 'gh', owner: 'codecov', }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.isError).toBeTruthy()) diff --git a/src/services/account/useCancelPlan.spec.js b/src/services/account/useCancelPlan.test.jsx similarity index 79% rename from src/services/account/useCancelPlan.spec.js rename to src/services/account/useCancelPlan.test.jsx index 9cc78b0872..1252a6e6e8 100644 --- a/src/services/account/useCancelPlan.spec.js +++ b/src/services/account/useCancelPlan.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { Plans } from 'shared/utils/billing' @@ -37,46 +37,45 @@ const accountDetails = { } const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) afterEach(() => { queryClient.clear() server.resetHandlers() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useCancelPlan', () => { - const mockBody = jest.fn() + const mockBody = vi.fn() function setup() { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/`, - async (req, res, ctx) => { - const body = await req.json() + async (info) => { + const body = await info.request.json() mockBody(body) - return res(ctx.status(200), ctx.json(accountDetails)) + return HttpResponse.json(accountDetails) } ) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('calls with the correct body', async () => { + setup() const { result } = renderHook(() => useCancelPlan({ provider, owner }), { wrapper: wrapper(), }) result.current.mutate() - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - await waitFor(() => expect(mockBody).toHaveBeenCalled()) await waitFor(() => expect(mockBody).toHaveBeenCalledWith({ diff --git a/src/services/account/useEraseAccount.spec.js b/src/services/account/useEraseAccount.test.jsx similarity index 69% rename from src/services/account/useEraseAccount.spec.js rename to src/services/account/useEraseAccount.test.jsx index b06d3e948a..89904cb0f7 100644 --- a/src/services/account/useEraseAccount.spec.js +++ b/src/services/account/useEraseAccount.test.jsx @@ -1,13 +1,13 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' import Cookie from 'js-cookie' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useEraseAccount } from './useEraseAccount' -jest.mock('js-cookie') +vi.mock('js-cookie') const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -26,40 +26,38 @@ const provider = 'gh' const owner = 'codecov' const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) describe('useEraseAccount', () => { function setup() { server.use( - rest.delete( - `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res(ctx.status(204), null) - } - ) + http.delete(`/internal/${provider}/${owner}/account-details/`, (info) => { + return HttpResponse.json({}) + }) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('deletes the auth cookie', async () => { + setup() const { result } = renderHook( () => useEraseAccount({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate() - await waitFor(() => result.current.isSuccess) - await waitFor(() => expect(Cookie.remove).toHaveBeenCalledWith('github-token') ) diff --git a/src/services/account/useInvoice.spec.tsx b/src/services/account/useInvoice.test.tsx similarity index 73% rename from src/services/account/useInvoice.spec.tsx rename to src/services/account/useInvoice.test.tsx index 3aba6f2e18..ecea6e9b8a 100644 --- a/src/services/account/useInvoice.spec.tsx +++ b/src/services/account/useInvoice.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -25,26 +25,30 @@ const provider = 'gh' const owner = 'codecov' const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) afterEach(() => { queryClient.clear() server.resetHandlers() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useInvoice', () => { function setup(hasError = false) { server.use( - graphql.query('Invoice', (req, res, ctx) => { + graphql.query('Invoice', (info) => { if (hasError) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - return res( - ctx.status(200), - ctx.data({ owner: { invoice: invoiceObject } }) - ) + return HttpResponse.json({ + data: { owner: { invoice: invoiceObject } }, + }) }) ) } @@ -55,9 +59,7 @@ describe('useInvoice', () => { setup() const { result } = renderHook( () => useInvoice({ provider, owner, id: invoiceObject.id }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) await waitFor(() => expect(result.current.data).toEqual(invoiceObject)) @@ -65,13 +67,19 @@ describe('useInvoice', () => { }) describe('on fail', () => { + beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + it('fails to parse if bad data', async () => { setup(true) const { result } = renderHook( () => useInvoice({ provider, owner, id: 'blah' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) await waitFor(() => expect(result.current.error).toBeTruthy()) diff --git a/src/services/account/useInvoices.spec.tsx b/src/services/account/useInvoices.test.tsx similarity index 75% rename from src/services/account/useInvoices.spec.tsx rename to src/services/account/useInvoices.test.tsx index a610035e76..0a62ee8cba 100644 --- a/src/services/account/useInvoices.spec.tsx +++ b/src/services/account/useInvoices.test.tsx @@ -1,15 +1,15 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' import { invoiceObject } from './mocks' import { useInvoices } from './useInvoices' -jest.mock('@stripe/react-stripe-js') -jest.mock('js-cookie') +vi.mock('@stripe/react-stripe-js') +vi.mock('js-cookie') const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -28,28 +28,32 @@ const provider = 'gh' const owner = 'codecov' const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) afterEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useInvoices', () => { const invoices = [invoiceObject, invoiceObject, invoiceObject, invoiceObject] function setup(hasError = false) { server.use( - graphql.query('Invoices', (req, res, ctx) => { + graphql.query('Invoices', (info) => { if (hasError) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - return res( - ctx.status(200), - ctx.data({ owner: { invoices: [...invoices] } }) - ) + return HttpResponse.json({ + data: { owner: { invoices: [...invoices] } }, + }) }) ) } @@ -67,6 +71,14 @@ describe('useInvoices', () => { }) describe('on fail', () => { + beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + it('fails to parse if bad data', async () => { setup(true) const { result } = renderHook(() => useInvoices({ provider, owner }), { diff --git a/src/services/account/usePlanData.spec.tsx b/src/services/account/usePlanData.test.tsx similarity index 88% rename from src/services/account/usePlanData.spec.tsx rename to src/services/account/usePlanData.test.tsx index 8fc6cf1551..4c82837a9b 100644 --- a/src/services/account/usePlanData.spec.tsx +++ b/src/services/account/usePlanData.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { usePlanData } from './usePlanData' @@ -35,12 +35,12 @@ const mockTrialData = { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( {children} ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -57,9 +57,9 @@ afterAll(() => { describe('usePlanData', () => { function setup({ trialData }: { trialData: any }) { server.use( - graphql.query('GetPlanData', (req, res, ctx) => - res(ctx.status(200), ctx.data({ owner: { ...trialData } })) - ) + graphql.query('GetPlanData', (info) => { + return HttpResponse.json({ data: { owner: { ...trialData } } }) + }) ) } @@ -109,9 +109,16 @@ describe('usePlanData', () => { }) describe('there is no plan data', () => { - beforeEach(() => setup({ trialData: undefined })) + beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) it('returns an empty object', async () => { + setup({ trialData: undefined }) const { result } = renderHook( () => usePlanData({ diff --git a/src/services/account/useSentryToken.spec.tsx b/src/services/account/useSentryToken.test.tsx similarity index 82% rename from src/services/account/useSentryToken.spec.tsx rename to src/services/account/useSentryToken.test.tsx index a2bf3212ee..9fdb57e61e 100644 --- a/src/services/account/useSentryToken.spec.tsx +++ b/src/services/account/useSentryToken.test.tsx @@ -1,14 +1,22 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import { useSentryToken } from './useSentryToken' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const original = await vi.importActual('services/toastNotification') + return { + ...original, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { @@ -25,7 +33,6 @@ const queryClient = new QueryClient({ log: () => null, }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( @@ -35,6 +42,7 @@ const wrapper: React.FC = ({ children }) => ( ) +const server = setupServer() beforeAll(() => { server.listen({ onUnhandledRequest: 'warn' }) }) @@ -62,73 +70,63 @@ describe('useSentryToken', () => { isUnknownError: false, } ) { - //@ts-ignore - const mockAddToast = jest.fn() - - //@ts-ignore - useAddNotification.mockReturnValue(mockAddToast) - - const mockRemoveItem = jest.spyOn( - window.localStorage.__proto__, - 'removeItem' - ) + const mockAddToast = vi.fn() + mocks.useAddNotification.mockReturnValue(mockAddToast) + const mockRemoveItem = vi.spyOn(window.localStorage.__proto__, 'removeItem') server.use( - graphql.mutation('SendSentryToken', (req, res, ctx) => { + graphql.mutation('SendSentryToken', (info) => { if (isValidationError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { saveSentryState: { error: { __typename: 'ValidationError', message: 'validation error', }, }, - }) - ) + }, + }) } if (isUnAuthError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { saveSentryState: { error: { __typename: 'UnauthenticatedError', message: 'unauthenticatedError error', }, }, - }) - ) + }, + }) } if (isUnknownError) { - return res( - ctx.status(500), - ctx.errors([{ message: 'unknown error' }]) + return HttpResponse.json( + { errors: [{ message: 'unknown error' }] }, + { status: 500 } ) } - return res(ctx.status(200), ctx.data({ saveSentryState: null })) + return HttpResponse.json({ data: { saveSentryState: null } }) }) ) return { mockAddToast, mockRemoveItem } } - afterEach(() => jest.resetAllMocks) + afterEach(() => { + vi.clearAllMocks() + }) describe('when called', () => { describe('when successful', () => { it('does not call addNotification', async () => { const { mockAddToast } = setup() - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -138,12 +136,9 @@ describe('useSentryToken', () => { it('removes item from local storage', async () => { const { mockRemoveItem } = setup() - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -158,12 +153,9 @@ describe('useSentryToken', () => { describe('when validation error', () => { it('calls addNotification', async () => { const { mockAddToast } = setup({ isValidationError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -178,12 +170,9 @@ describe('useSentryToken', () => { it('removes item from local storage', async () => { const { mockRemoveItem } = setup({ isValidationError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -198,12 +187,9 @@ describe('useSentryToken', () => { describe('when unauthenticated error', () => { it('calls addNotification', async () => { const { mockAddToast } = setup({ isUnAuthError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -218,12 +204,9 @@ describe('useSentryToken', () => { it('removes item from local storage', async () => { const { mockRemoveItem } = setup({ isUnAuthError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -238,12 +221,9 @@ describe('useSentryToken', () => { describe('when unknown error', () => { it('calls addNotification', async () => { const { mockAddToast } = setup({ isUnknownError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') @@ -258,12 +238,9 @@ describe('useSentryToken', () => { it('removes item from local storage', async () => { const { mockRemoveItem } = setup({ isUnknownError: true }) - const { result } = renderHook( () => useSentryToken({ provider: '/gh' }), - { - wrapper, - } + { wrapper } ) result.current.mutate('super-cool-token') diff --git a/src/services/account/useUpdateBillingAddress.spec.tsx b/src/services/account/useUpdateBillingAddress.test.tsx similarity index 89% rename from src/services/account/useUpdateBillingAddress.spec.tsx rename to src/services/account/useUpdateBillingAddress.test.tsx index a2b2825f23..ee458f43f6 100644 --- a/src/services/account/useUpdateBillingAddress.spec.tsx +++ b/src/services/account/useUpdateBillingAddress.test.tsx @@ -1,19 +1,19 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useUpdateBillingAddress } from './useUpdateBillingAddress' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( {children} ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -63,33 +63,30 @@ const accountDetails = { } describe('useUpdateBillingAddress', () => { - const mockBody = jest.fn() + const mockBody = vi.fn() function setup() { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/update_billing_address`, - async (req, res, ctx) => { - const body = await req.json() + async (info) => { + const body = await info.request.json() mockBody(body) - return res(ctx.status(200), ctx.json(accountDetails)) + return HttpResponse.json(accountDetails) } ) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) + beforeEach(() => {}) it('calls with the correct body', async () => { + setup() const { result } = renderHook( () => useUpdateBillingAddress({ provider, owner }), - { - wrapper, - } + { wrapper } ) result.current.mutate( diff --git a/src/services/account/useUpdateBillingEmail.spec.tsx b/src/services/account/useUpdateBillingEmail.test.tsx similarity index 82% rename from src/services/account/useUpdateBillingEmail.spec.tsx rename to src/services/account/useUpdateBillingEmail.test.tsx index 8d10002a20..d8b39da039 100644 --- a/src/services/account/useUpdateBillingEmail.spec.tsx +++ b/src/services/account/useUpdateBillingEmail.test.tsx @@ -1,19 +1,19 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useUpdateBillingEmail } from './useUpdateBillingEmail' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( {children} ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -63,40 +63,32 @@ const accountDetails = { } describe('useUpdateBillingEmail', () => { - const mockBody = jest.fn() + const mockBody = vi.fn() function setup() { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/update_email`, - async (req, res, ctx) => { - const body = await req.json() + async (info) => { + const body = await info.request.json() mockBody(body) - return res(ctx.status(200), ctx.json(accountDetails)) + return HttpResponse.json(accountDetails) } ) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('calls with the correct body', async () => { + setup() const { result } = renderHook( () => useUpdateBillingEmail({ provider, owner }), - { - wrapper, - } + { wrapper } ) result.current.mutate({ newEmail: 'test@gmail.com' }) - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - await waitFor(() => expect(mockBody).toHaveBeenCalled()) await waitFor(() => expect(mockBody).toHaveBeenCalledWith({ diff --git a/src/services/account/useUpdateCard.spec.tsx b/src/services/account/useUpdateCard.test.tsx similarity index 71% rename from src/services/account/useUpdateCard.spec.tsx rename to src/services/account/useUpdateCard.test.tsx index 3cf1a3c5a5..bcdf734559 100644 --- a/src/services/account/useUpdateCard.spec.tsx +++ b/src/services/account/useUpdateCard.test.tsx @@ -1,14 +1,23 @@ -import { useStripe } from '@stripe/react-stripe-js' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' import { useUpdateCard } from './useUpdateCard' -jest.mock('@stripe/react-stripe-js') +const mocks = vi.hoisted(() => ({ + useStripe: vi.fn(), +})) + +vi.mock('@stripe/react-stripe-js', async () => { + const original = await vi.importActual('@stripe/react-stripe-js') + return { + ...original, + useStripe: mocks.useStripe, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -41,11 +50,17 @@ const accountDetails = { const server = setupServer() beforeAll(() => { - // console.error = () => {} server.listen() }) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) describe('useUpdateCard', () => { const card = { @@ -57,8 +72,7 @@ describe('useUpdateCard', () => { }: { createPaymentMethod: jest.Mock }) { - const mockedUseStripe = useStripe as jest.Mock - mockedUseStripe.mockReturnValue({ + mocks.useStripe.mockReturnValue({ createPaymentMethod, }) } @@ -70,20 +84,16 @@ describe('useUpdateCard', () => { createPaymentMethod: jest.fn( () => new Promise((resolve) => { - resolve({ - paymentMethod: { - id: 1, - }, - }) + resolve({ paymentMethod: { id: 1 } }) }) ), }) server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/update_payment`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json(accountDetails)) + (info) => { + return HttpResponse.json(accountDetails) } ) ) @@ -92,9 +102,7 @@ describe('useUpdateCard', () => { it('returns the data from the server', async () => { const { result } = renderHook( () => useUpdateCard({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) // @ts-expect-error mutation mock @@ -105,46 +113,45 @@ describe('useUpdateCard', () => { }) describe('when the mutation is not successful', () => { - const error = { - message: 'not good', - } - beforeEach(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + setupStripe({ createPaymentMethod: jest.fn( () => new Promise((resolve) => { - resolve({ - error, - }) + resolve({ error: { message: 'not good' } }) }) ), }) server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/update_payment`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json(accountDetails)) + (info) => { + return HttpResponse.json(accountDetails) } ) ) }) + afterAll(() => { + vi.restoreAllMocks() + }) + it('does something', async () => { const { result } = renderHook( () => useUpdateCard({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) // @ts-expect-error mutation mock result.current.mutate(card) await waitFor(() => result.current.error) - - await waitFor(() => expect(result.current.error).toEqual(error)) + await waitFor(() => + expect(result.current.error).toEqual({ message: 'not good' }) + ) }) }) }) diff --git a/src/services/account/useUpdateSelfHostedSettings.spec.tsx b/src/services/account/useUpdateSelfHostedSettings.test.tsx similarity index 67% rename from src/services/account/useUpdateSelfHostedSettings.spec.tsx rename to src/services/account/useUpdateSelfHostedSettings.test.tsx index 5eab42f374..f1dfaa35a9 100644 --- a/src/services/account/useUpdateSelfHostedSettings.spec.tsx +++ b/src/services/account/useUpdateSelfHostedSettings.test.tsx @@ -1,19 +1,26 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import { useUpdateSelfHostedSettings } from './useUpdateSelfHostedSettings' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const original = await vi.importActual('services/toastNotification') + return { + ...original, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper = (initialEntries = '/gh'): React.FC => @@ -25,6 +32,7 @@ const wrapper = ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -43,46 +51,41 @@ describe('updateSelfHostedSettings', () => { isValidationError = false, isUnauthenticatedError = false, }) { - const mockAddToast = jest.fn() + const mockAddToast = vi.fn() + mocks.useAddNotification.mockReturnValue(mockAddToast) - //@ts-ignore - useAddNotification.mockReturnValue(mockAddToast) server.use( - graphql.mutation('UpdateSelfHostedSettings', (req, res, ctx) => { + graphql.mutation('UpdateSelfHostedSettings', (info) => { if (isValidationError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { updateSelfHostedSettings: { error: { __typename: 'ValidationError', message: 'validation error', }, }, - }) - ) + }, + }) } if (isUnauthenticatedError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { updateSelfHostedSettings: { error: { __typename: 'UnauthenticatedError', message: 'unauthenticated error', }, }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ updateSelfHostedSettings: null }) - ) + return HttpResponse.json({ data: { updateSelfHostedSettings: null } }) }) ) + return { mockAddToast } } @@ -95,39 +98,49 @@ describe('updateSelfHostedSettings', () => { result.current.mutate({ shouldAutoActivate: false }) - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - expect(mockAddToast).not.toHaveBeenCalled() + await waitFor(() => expect(mockAddToast).not.toHaveBeenCalled()) }) }) describe('when user is unauthenticated', () => { + beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + it('returns an unauthenticated response', async () => { const { mockAddToast } = setup({ isUnauthenticatedError: true }) const { result } = renderHook(() => useUpdateSelfHostedSettings(), { wrapper: wrapper(), }) + result.current.mutate({ shouldAutoActivate: false }) - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - expect(mockAddToast).toHaveBeenCalled() + await waitFor(() => expect(mockAddToast).toHaveBeenCalled()) }) }) describe('when there is a validation error', () => { + beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + it('returns a validation error response', async () => { const { mockAddToast } = setup({ isValidationError: true }) - const { result } = renderHook(() => useUpdateSelfHostedSettings(), { wrapper: wrapper(), }) result.current.mutate({ shouldAutoActivate: false }) - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - expect(mockAddToast).toHaveBeenCalled() + await waitFor(() => expect(mockAddToast).toHaveBeenCalled()) }) }) }) diff --git a/src/services/account/useUpgradePlan.spec.tsx b/src/services/account/useUpgradePlan.test.tsx similarity index 64% rename from src/services/account/useUpgradePlan.spec.tsx rename to src/services/account/useUpgradePlan.test.tsx index 49a733f20f..ef23bfaa10 100644 --- a/src/services/account/useUpgradePlan.spec.tsx +++ b/src/services/account/useUpgradePlan.test.tsx @@ -1,13 +1,23 @@ -import { useStripe } from '@stripe/react-stripe-js' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import type { MockInstance } from 'vitest' import { useUpgradePlan } from './useUpgradePlan' -jest.mock('@stripe/react-stripe-js') +const mocks = vi.hoisted(() => ({ + useStripe: vi.fn(), +})) + +vi.mock('@stripe/react-stripe-js', async () => { + const original = await vi.importActual('@stripe/react-stripe-js') + return { + ...original, + useStripe: mocks.useStripe, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -38,55 +48,67 @@ const accountDetails = { } const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) describe('useUpgradePlan', () => { let redirectToCheckout: any function setupStripe() { - redirectToCheckout = jest.fn().mockResolvedValue(undefined) - const mockedUseStripe = useStripe as jest.Mock - mockedUseStripe.mockReturnValue({ + redirectToCheckout = vi.fn().mockResolvedValue(undefined) + mocks.useStripe.mockReturnValue({ redirectToCheckout, }) } + afterEach(() => { + vi.clearAllMocks() + }) + function setup() { setupStripe() } describe('when called', () => { beforeEach(() => { - setup() + server.use( + http.patch( + `/internal/${provider}/${owner}/account-details/`, + (info) => { + return HttpResponse.json({ + ...accountDetails, + checkoutSessionId: '1234', + }) + } + ) + ) }) describe('when calling the mutation, which return a checkoutSessionId', () => { + let consoleSpy: MockInstance beforeEach(() => { - server.use( - rest.patch( - `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ...accountDetails, - checkoutSessionId: '1234', - }) - ) - } - ) - ) + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + consoleSpy.mockRestore() }) it('calls redirectToCheckout on the Stripe client', async () => { + setup() const { result } = renderHook( () => useUpgradePlan({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate({ @@ -105,16 +127,13 @@ describe('useUpgradePlan', () => { describe('when calling the mutation, which does not return a checkoutSessionId', () => { beforeEach(() => { server.use( - rest.patch( + http.patch( `/internal/${provider}/${owner}/account-details/`, - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ...accountDetails, - checkoutSessionId: null, - }) - ) + (info) => { + return HttpResponse.json({ + ...accountDetails, + checkoutSessionId: null, + }) } ) ) @@ -123,9 +142,7 @@ describe('useUpgradePlan', () => { it('does not call redirectToCheckout on the Stripe client', async () => { const { result } = renderHook( () => useUpgradePlan({ provider, owner }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate({ @@ -133,8 +150,6 @@ describe('useUpgradePlan', () => { newPlan: 'users-pr-inappy', }) - await waitFor(() => result.current.isSuccess) - await waitFor(() => expect(redirectToCheckout).not.toHaveBeenCalled()) }) }) From f41d19fe9ffcbd4e53911173990220ae74abd39b Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 09:50:16 -0300 Subject: [PATCH 04/20] chore: Update services/branches tests to Vitest (#3297) --- src/services/branches/{index.js => index.ts} | 0 ...{useBranch.spec.tsx => useBranch.test.tsx} | 35 +++++----- ....spec.tsx => useBranchComponents.test.tsx} | 39 ++++++----- ....spec.tsx => useBranchHasCommits.test.tsx} | 39 +++++------ ...Branches.spec.tsx => useBranches.test.tsx} | 66 ++++++++----------- 5 files changed, 86 insertions(+), 93 deletions(-) rename src/services/branches/{index.js => index.ts} (100%) rename src/services/branches/{useBranch.spec.tsx => useBranch.test.tsx} (85%) rename src/services/branches/{useBranchComponents.spec.tsx => useBranchComponents.test.tsx} (87%) rename src/services/branches/{useBranchHasCommits.spec.tsx => useBranchHasCommits.test.tsx} (86%) rename src/services/branches/{useBranches.spec.tsx => useBranches.test.tsx} (83%) diff --git a/src/services/branches/index.js b/src/services/branches/index.ts similarity index 100% rename from src/services/branches/index.js rename to src/services/branches/index.ts diff --git a/src/services/branches/useBranch.spec.tsx b/src/services/branches/useBranch.test.tsx similarity index 85% rename from src/services/branches/useBranch.spec.tsx rename to src/services/branches/useBranch.test.tsx index b1aab94118..708b79541b 100644 --- a/src/services/branches/useBranch.spec.tsx +++ b/src/services/branches/useBranch.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBranch } from './useBranch' @@ -80,17 +81,17 @@ describe('useBranch', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockBranch)) + return HttpResponse.json({ data: mockBranch }) } }) ) @@ -144,14 +145,14 @@ describe('useBranch', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -180,14 +181,14 @@ describe('useBranch', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -216,14 +217,14 @@ describe('useBranch', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/branches/useBranchComponents.spec.tsx b/src/services/branches/useBranchComponents.test.tsx similarity index 87% rename from src/services/branches/useBranchComponents.spec.tsx rename to src/services/branches/useBranchComponents.test.tsx index ebd8f055c1..413c5bdca0 100644 --- a/src/services/branches/useBranchComponents.spec.tsx +++ b/src/services/branches/useBranchComponents.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBranchComponents } from './useBranchComponents' @@ -87,10 +88,12 @@ const wrapper: React.FC = ({ children }) => ( beforeAll(() => { server.listen() }) + afterEach(() => { queryClient.clear() server.resetHandlers() }) + afterAll(() => { server.close() }) @@ -112,19 +115,19 @@ describe('useBranchComponents', () => { isFiltered = false, }: SetupArgs) { server.use( - graphql.query('GetBranchComponents', (req, res, ctx) => { + graphql.query('GetBranchComponents', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (isFiltered) { - return res(ctx.status(200), ctx.data(mockBranchComponentsFiltered)) + return HttpResponse.json({ data: mockBranchComponentsFiltered }) } else { - return res(ctx.status(200), ctx.data(mockBranchComponents)) + return HttpResponse.json({ data: mockBranchComponents }) } }) ) @@ -221,14 +224,14 @@ describe('useBranchComponents', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -256,14 +259,14 @@ describe('useBranchComponents', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -291,14 +294,14 @@ describe('useBranchComponents', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/branches/useBranchHasCommits.spec.tsx b/src/services/branches/useBranchHasCommits.test.tsx similarity index 86% rename from src/services/branches/useBranchHasCommits.spec.tsx rename to src/services/branches/useBranchHasCommits.test.tsx index 9906eeb40c..eea076580f 100644 --- a/src/services/branches/useBranchHasCommits.spec.tsx +++ b/src/services/branches/useBranchHasCommits.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { Suspense } from 'react' +import { type MockInstance } from 'vitest' import { useBranchHasCommits } from './useBranchHasCommits' @@ -112,21 +113,21 @@ describe('useBranchHasCommits', () => { commitsIsNull = false, }: SetupArgs) { server.use( - graphql.query('GetBranchCommits', (req, res, ctx) => { + graphql.query('GetBranchCommits', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (hasNoCommits) { - return res(ctx.status(200), ctx.data(mockBranchHasNoCommits)) + return HttpResponse.json({ data: mockBranchHasNoCommits }) } else if (commitsIsNull) { - return res(ctx.status(200), ctx.data(mockCommitsIsNull)) + return HttpResponse.json({ data: mockCommitsIsNull }) } else { - return res(ctx.status(200), ctx.data(mockBranchHasCommits)) + return HttpResponse.json({ data: mockBranchHasCommits }) } }) ) @@ -220,14 +221,14 @@ describe('useBranchHasCommits', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -255,14 +256,14 @@ describe('useBranchHasCommits', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -290,14 +291,14 @@ describe('useBranchHasCommits', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/branches/useBranches.spec.tsx b/src/services/branches/useBranches.test.tsx similarity index 83% rename from src/services/branches/useBranches.spec.tsx rename to src/services/branches/useBranches.test.tsx index 0482d5fa87..419c0db533 100644 --- a/src/services/branches/useBranches.spec.tsx +++ b/src/services/branches/useBranches.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBranches } from './useBranches' @@ -85,20 +86,20 @@ describe('GetBranches', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetBranches', (req, res, ctx) => { + graphql.query('GetBranches', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwnerData)) + return HttpResponse.json({ data: mockNullOwnerData }) } - const branchData = !!req.variables?.after ? branch2 : branch1 - const hasNextPage = req.variables?.after ? false : true - const endCursor = req.variables?.after ? 'second' : 'first' + const branchData = !!info.variables?.after ? branch2 : branch1 + const hasNextPage = info.variables?.after ? false : true + const endCursor = info.variables?.after ? 'second' : 'first' const queryData = { owner: { @@ -119,8 +120,7 @@ describe('GetBranches', () => { }, }, } - - return res(ctx.status(200), ctx.data(queryData)) + return HttpResponse.json({ data: queryData }) }) ) } @@ -132,9 +132,7 @@ describe('GetBranches', () => { setup({}) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.isSuccess).toBe(true)) @@ -161,9 +159,7 @@ describe('GetBranches', () => { setup({}) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.status).toBe('success')) @@ -201,9 +197,7 @@ describe('GetBranches', () => { setup({ isNullOwner: true }) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.status).toBe('success')) @@ -222,23 +216,21 @@ describe('GetBranches', () => { }) describe('when __typename is NotFoundError', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { setup({ isNotFoundError: true }) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.isError).toBeTruthy()) @@ -254,23 +246,21 @@ describe('GetBranches', () => { }) describe('when __typename is OwnerNotActivatedError', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { setup({ isOwnerNotActivatedError: true }) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.isError).toBeTruthy()) @@ -286,23 +276,21 @@ describe('GetBranches', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { setup({ isUnsuccessfulParseError: true }) const { result } = renderHook( () => useBranches({ provider, owner, repo }), - { - wrapper, - } + { wrapper } ) await waitFor(() => expect(result.current.isError).toBeTruthy()) From cb68b7b726c31fdb6c7b3a3121fe7d5e80251cf4 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 10:08:04 -0300 Subject: [PATCH 05/20] chore: Update services/commit to Vitest (#3300) --- ...seUploads.spec.tsx => useUploads.test.tsx} | 19 ++- src/services/commit/mocks.ts | 113 ++++++++---------- ...{useCommit.spec.tsx => useCommit.test.tsx} | 55 +++++---- ...sx => useCommitBADropdownSummary.test.tsx} | 16 +-- ....spec.tsx => useCommitBundleList.test.tsx} | 35 +++--- ....spec.tsx => useCommitComponents.test.tsx} | 35 +++--- ...useCommitCoverageDropdownSummary.test.tsx} | 35 +++--- ...itTeam.spec.tsx => useCommitTeam.test.tsx} | 51 ++++---- ...itYaml.spec.tsx => useCommitYaml.test.tsx} | 27 ++--- ...als.spec.tsx => useCompareTotals.test.tsx} | 47 ++++---- ...spec.tsx => useCompareTotalsTeam.test.tsx} | 35 +++--- 11 files changed, 242 insertions(+), 226 deletions(-) rename src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/{useUploads.spec.tsx => useUploads.test.tsx} (96%) rename src/services/commit/{useCommit.spec.tsx => useCommit.test.tsx} (93%) rename src/services/commit/{useCommitBADropdownSummary.spec.tsx => useCommitBADropdownSummary.test.tsx} (92%) rename src/services/commit/{useCommitBundleList.spec.tsx => useCommitBundleList.test.tsx} (88%) rename src/services/commit/{useCommitComponents.spec.tsx => useCommitComponents.test.tsx} (82%) rename src/services/commit/{useCommitCoverageDropdownSummary.spec.tsx => useCommitCoverageDropdownSummary.test.tsx} (85%) rename src/services/commit/{useCommitTeam.spec.tsx => useCommitTeam.test.tsx} (91%) rename src/services/commit/{useCommitYaml.spec.tsx => useCommitYaml.test.tsx} (89%) rename src/services/commit/{useCompareTotals.spec.tsx => useCompareTotals.test.tsx} (84%) rename src/services/commit/{useCompareTotalsTeam.spec.tsx => useCompareTotalsTeam.test.tsx} (85%) diff --git a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.spec.tsx b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.test.tsx similarity index 96% rename from src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.spec.tsx rename to src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.test.tsx index ab5bc46c8c..b4258887a6 100644 --- a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.spec.tsx +++ b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/useUploads/useUploads.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql, RequestHandler } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse, RequestHandler } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -62,16 +62,15 @@ describe('useUploads', () => { server.use(query, compareTotalsEmpty) server.use( - graphql.query('OwnerTier', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ + data: { owner: { plan: { tierName: tierValue } }, - }) - ) + }, + }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockOverview }) }) ) } diff --git a/src/services/commit/mocks.ts b/src/services/commit/mocks.ts index 4fb1a4fd54..a4aaaf66d9 100644 --- a/src/services/commit/mocks.ts +++ b/src/services/commit/mocks.ts @@ -1,29 +1,28 @@ -import { graphql } from 'msw' +import { graphql, HttpResponse } from 'msw2' -export const commitErrored = graphql.query('Commit', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ +export const commitErrored = graphql.query('Commit', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', commit: commitDataError, }, }, - }) - ) + }, + }) }) -export const commitOnePending = graphql.query('Commit', (req, res, ctx) => { +export const commitOnePending = graphql.query('Commit', (info) => { let flags = ['unit'] let provider = 'travis' - if (req.variables.isTeamPlan) { + if (info.variables.isTeamPlan) { flags = [] provider = 'travisTeam' } - return res( - ctx.status(200), - ctx.data({ + + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -54,70 +53,62 @@ export const commitOnePending = graphql.query('Commit', (req, res, ctx) => { }, }, }, - }) - ) + }, + }) }) -export const commitOneCarriedForward = graphql.query( - 'Commit', - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ - owner: { - repository: { - __typename: 'Repository', - commit: { - ...commitDataError, - uploads: { - edges: [ - { - node: { - id: null, - name: null, - errors: null, - state: 'COMPLETE', - provider: 'travis', - createdAt: '2020-08-25T16:36:19.559474+00:00', - updatedAt: '2020-08-25T16:36:19.679868+00:00', - downloadUrl: '/test.txt', - ciUrl: 'https://example.com', - uploadType: 'CARRIEDFORWARD', - jobCode: '1234', - buildCode: '1234', - flags: ['unit'], - }, +export const commitOneCarriedForward = graphql.query('Commit', (info) => { + return HttpResponse.json({ + data: { + owner: { + repository: { + __typename: 'Repository', + commit: { + ...commitDataError, + uploads: { + edges: [ + { + node: { + id: null, + name: null, + errors: null, + state: 'COMPLETE', + provider: 'travis', + createdAt: '2020-08-25T16:36:19.559474+00:00', + updatedAt: '2020-08-25T16:36:19.679868+00:00', + downloadUrl: '/test.txt', + ciUrl: 'https://example.com', + uploadType: 'CARRIEDFORWARD', + jobCode: '1234', + buildCode: '1234', + flags: ['unit'], }, - ], - }, + }, + ], }, }, }, - }) - ) - } -) + }, + }, + }) +}) -export const commitEmptyUploads = graphql.query('Commit', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ +export const commitEmptyUploads = graphql.query('Commit', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', commit: commitDataEmpty, }, }, - }) - ) + }, + }) }) -export const compareTotalsEmpty = graphql.query( - 'CompareTotals', - (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: null })) - } -) +export const compareTotalsEmpty = graphql.query('CompareTotals', (info) => { + return HttpResponse.json({ data: { owner: null } }) +}) const commitDataError = { totals: { diff --git a/src/services/commit/useCommit.spec.tsx b/src/services/commit/useCommit.test.tsx similarity index 93% rename from src/services/commit/useCommit.spec.tsx rename to src/services/commit/useCommit.test.tsx index fe2bf96c90..8be81cf2dc 100644 --- a/src/services/commit/useCommit.spec.tsx +++ b/src/services/commit/useCommit.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { useCommit } from './index' @@ -247,7 +248,7 @@ beforeAll(() => { }) beforeEach(() => { - jest.useRealTimers() + vi.useRealTimers() server.resetHandlers() queryClient.clear() }) @@ -273,27 +274,27 @@ describe('useCommit', () => { skipPolling = false, }: SetupArgs) { server.use( - graphql.query(`Commit`, (req, res, ctx) => { + graphql.query(`Commit`, (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - const dataToReturn = req.variables.isTeamPlan + const dataToReturn = info.variables.isTeamPlan ? dataReturnedTeam : dataReturned - return res(ctx.status(200), ctx.data(dataToReturn)) + return HttpResponse.json({ data: dataToReturn }) } }), - graphql.query(`CompareTotals`, (req, res, ctx) => { + graphql.query(`CompareTotals`, (info) => { if (skipPolling) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - return res(ctx.status(200), ctx.data(compareDoneData)) + return HttpResponse.json({ data: compareDoneData }) }) ) } @@ -496,12 +497,14 @@ describe('useCommit', () => { }) describe('returns NotFoundError __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -531,12 +534,14 @@ describe('useCommit', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -566,12 +571,14 @@ describe('useCommit', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -607,16 +614,16 @@ describe('useCommit polling', () => { function setup() { nbCallCompare = 0 server.use( - graphql.query(`Commit`, (req, res, ctx) => { - return res(ctx.status(200), ctx.data(dataReturned)) + graphql.query(`Commit`, (info) => { + return HttpResponse.json({ data: dataReturned }) }), - graphql.query(`CompareTotals`, (req, res, ctx) => { + graphql.query(`CompareTotals`, (info) => { nbCallCompare++ // after 10 calls, the server returns that the commit is processed if (nbCallCompare < 1) { - return res(ctx.status(200), ctx.data(dataReturned)) + return HttpResponse.json({ data: {} }) } - return res(ctx.status(200), ctx.data(compareDoneData)) + return HttpResponse.json({ data: compareDoneData }) }) ) } diff --git a/src/services/commit/useCommitBADropdownSummary.spec.tsx b/src/services/commit/useCommitBADropdownSummary.test.tsx similarity index 92% rename from src/services/commit/useCommitBADropdownSummary.spec.tsx rename to src/services/commit/useCommitBADropdownSummary.test.tsx index d8beff832a..7e8f828e9e 100644 --- a/src/services/commit/useCommitBADropdownSummary.spec.tsx +++ b/src/services/commit/useCommitBADropdownSummary.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useCommitBADropdownSummary } from './useCommitBADropdownSummary' @@ -91,17 +91,17 @@ describe('useCommitBADropdownSummary', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('CommitBADropdownSummary', (req, res, ctx) => { + graphql.query('CommitBADropdownSummary', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCommitBASummaryData)) + return HttpResponse.json({ data: mockCommitBASummaryData }) } }) ) diff --git a/src/services/commit/useCommitBundleList.spec.tsx b/src/services/commit/useCommitBundleList.test.tsx similarity index 88% rename from src/services/commit/useCommitBundleList.spec.tsx rename to src/services/commit/useCommitBundleList.test.tsx index 8f42bbed57..59379be7db 100644 --- a/src/services/commit/useCommitBundleList.spec.tsx +++ b/src/services/commit/useCommitBundleList.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useCommitBundleList } from './useCommitBundleList' @@ -125,17 +126,17 @@ describe('useCommitBundleList', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('CommitBundleList', (req, res, ctx) => { + graphql.query('CommitBundleList', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCommitBundleListData)) + return HttpResponse.json({ data: mockCommitBundleListData }) } }) ) @@ -232,14 +233,14 @@ describe('useCommitBundleList', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -268,14 +269,14 @@ describe('useCommitBundleList', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -304,14 +305,14 @@ describe('useCommitBundleList', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/commit/useCommitComponents.spec.tsx b/src/services/commit/useCommitComponents.test.tsx similarity index 82% rename from src/services/commit/useCommitComponents.spec.tsx rename to src/services/commit/useCommitComponents.test.tsx index ebd8b55ca3..e4cea9bb35 100644 --- a/src/services/commit/useCommitComponents.spec.tsx +++ b/src/services/commit/useCommitComponents.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { useCommitComponents } from './useCommitComponents' @@ -86,17 +87,17 @@ describe('useCommitComponents', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('CommitComponents', (req, res, ctx) => { + graphql.query('CommitComponents', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCommitComponentData)) + return HttpResponse.json({ data: mockCommitComponentData }) } }) ) @@ -126,14 +127,14 @@ describe('useCommitComponents', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -155,14 +156,14 @@ describe('useCommitComponents', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -186,14 +187,14 @@ describe('useCommitComponents', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/commit/useCommitCoverageDropdownSummary.spec.tsx b/src/services/commit/useCommitCoverageDropdownSummary.test.tsx similarity index 85% rename from src/services/commit/useCommitCoverageDropdownSummary.spec.tsx rename to src/services/commit/useCommitCoverageDropdownSummary.test.tsx index 26cf96864b..43d11215e2 100644 --- a/src/services/commit/useCommitCoverageDropdownSummary.spec.tsx +++ b/src/services/commit/useCommitCoverageDropdownSummary.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useCommitCoverageDropdownSummary } from './useCommitCoverageDropdownSummary' @@ -96,17 +97,17 @@ describe('useCommitCoverageDropdownSummary', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('CommitDropdownSummary', (req, res, ctx) => { + graphql.query('CommitDropdownSummary', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCommitSummaryData)) + return HttpResponse.json({ data: mockCommitSummaryData }) } }) ) @@ -169,14 +170,14 @@ describe('useCommitCoverageDropdownSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -205,14 +206,14 @@ describe('useCommitCoverageDropdownSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -241,14 +242,14 @@ describe('useCommitCoverageDropdownSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/commit/useCommitTeam.spec.tsx b/src/services/commit/useCommitTeam.test.tsx similarity index 91% rename from src/services/commit/useCommitTeam.spec.tsx rename to src/services/commit/useCommitTeam.test.tsx index c5b9a68854..07e8d94dee 100644 --- a/src/services/commit/useCommitTeam.spec.tsx +++ b/src/services/commit/useCommitTeam.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useCommitTeam } from './useCommitTeam' @@ -159,7 +160,7 @@ beforeAll(() => { }) afterEach(() => { - jest.useRealTimers() + vi.useRealTimers() queryClient.clear() server.resetHandlers() }) @@ -183,21 +184,21 @@ describe('useCommitTeam', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetCommitTeam', (req, res, ctx) => { + graphql.query('GetCommitTeam', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCommitData)) + return HttpResponse.json({ data: mockCommitData }) } }), - graphql.query('GetCompareTotalsTeam', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockCompareData)) + graphql.query('GetCompareTotalsTeam', (info) => { + return HttpResponse.json({ data: mockCompareData }) }) ) } @@ -320,12 +321,14 @@ describe('useCommitTeam', () => { }) describe('returns NotFoundError __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -355,12 +358,14 @@ describe('useCommitTeam', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -390,12 +395,14 @@ describe('useCommitTeam', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -429,17 +436,17 @@ describe('useCommitTeam polling', () => { function setup() { let nbCallCompare = 0 server.use( - graphql.query(`GetCommitTeam`, (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockCommitData)) + graphql.query(`GetCommitTeam`, (info) => { + return HttpResponse.json({ data: mockCommitData }) }), - graphql.query(`GetCompareTotalsTeam`, (req, res, ctx) => { + graphql.query(`GetCompareTotalsTeam`, (info) => { nbCallCompare++ if (nbCallCompare < 9) { - return res(ctx.status(200), ctx.data(mockCommitData)) + return HttpResponse.json({ data: mockCompareData }) } - return res(ctx.status(200), ctx.data(mockCompareData)) + return HttpResponse.json({ data: mockCompareData }) }) ) } diff --git a/src/services/commit/useCommitYaml.spec.tsx b/src/services/commit/useCommitYaml.test.tsx similarity index 89% rename from src/services/commit/useCommitYaml.spec.tsx rename to src/services/commit/useCommitYaml.test.tsx index d1c1e76cef..dafcd8ff5a 100644 --- a/src/services/commit/useCommitYaml.spec.tsx +++ b/src/services/commit/useCommitYaml.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useCommitYaml } from './index' @@ -68,7 +68,7 @@ beforeAll(() => { }) beforeEach(() => { - jest.useRealTimers() + vi.useRealTimers() server.resetHandlers() queryClient.clear() }) @@ -93,27 +93,22 @@ describe('useCommitYaml', () => { ownerNotActivatedError = false, }: SetupArgs) { server.use( - graphql.query(`CommitYaml`, (req, res, ctx) => { + graphql.query(`CommitYaml`, (info) => { if (badSchema) { - return res(ctx.status(200), ctx.data(mockCommitYamlBadSchema)) + return HttpResponse.json({ data: mockCommitYamlBadSchema }) + } else if (notFoundError) { + return HttpResponse.json({ data: mockCommitYamlNotFound }) + } else if (ownerNotActivatedError) { + return HttpResponse.json({ data: mockCommitYamlOwnerNotActivated }) } - if (notFoundError) { - return res(ctx.status(200), ctx.data(mockCommitYamlNotFound)) - } - if (ownerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockCommitYamlOwnerNotActivated)) - } - return res(ctx.status(200), ctx.data(mockCommitYaml(yaml))) + return HttpResponse.json({ data: mockCommitYaml(yaml) }) }) ) } describe('when called and user is authenticated', () => { - beforeEach(() => { - setup({}) - }) - it('returns commit info', async () => { + setup({}) const { result } = renderHook( () => useCommitYaml({ diff --git a/src/services/commit/useCompareTotals.spec.tsx b/src/services/commit/useCompareTotals.test.tsx similarity index 84% rename from src/services/commit/useCompareTotals.spec.tsx rename to src/services/commit/useCompareTotals.test.tsx index ef4472cf2a..d0272c3bdc 100644 --- a/src/services/commit/useCompareTotals.spec.tsx +++ b/src/services/commit/useCompareTotals.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useCompareTotals } from './useCompareTotals' @@ -87,17 +88,17 @@ describe('useCompareTotals', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('CompareTotals', (req, res, ctx) => { + graphql.query('CompareTotals', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockResponse)) + return HttpResponse.json({ data: mockResponse }) } }) ) @@ -168,12 +169,14 @@ describe('useCompareTotals', () => { }) describe('returns NotFoundError __typename', () => { - beforeAll(() => { - jest.spyOn(console, 'error') + let consoleSpy: MockInstance + + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) - afterAll(() => { - jest.resetAllMocks() + afterEach(() => { + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -201,12 +204,14 @@ describe('useCompareTotals', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - beforeAll(() => { - jest.spyOn(console, 'error') + let consoleSpy: MockInstance + + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) - afterAll(() => { - jest.resetAllMocks() + afterEach(() => { + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -234,12 +239,14 @@ describe('useCompareTotals', () => { }) describe('unsuccessful parse of zod schema', () => { - beforeAll(() => { - jest.spyOn(console, 'error') + let consoleSpy: MockInstance + + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) - afterAll(() => { - jest.resetAllMocks() + afterEach(() => { + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/commit/useCompareTotalsTeam.spec.tsx b/src/services/commit/useCompareTotalsTeam.test.tsx similarity index 85% rename from src/services/commit/useCompareTotalsTeam.spec.tsx rename to src/services/commit/useCompareTotalsTeam.test.tsx index f745f03ffc..9196b6a948 100644 --- a/src/services/commit/useCompareTotalsTeam.spec.tsx +++ b/src/services/commit/useCompareTotalsTeam.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useCompareTotalsTeam } from './useCompareTotalsTeam' @@ -95,17 +96,17 @@ describe('useCompareTotalsTeam', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetCompareTotalsTeam', (req, res, ctx) => { + graphql.query('GetCompareTotalsTeam', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCompareData)) + return HttpResponse.json({ data: mockCompareData }) } }) ) @@ -173,12 +174,14 @@ describe('useCompareTotalsTeam', () => { }) describe('returns NotFound Error __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -204,12 +207,14 @@ describe('useCompareTotalsTeam', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -235,12 +240,14 @@ describe('useCompareTotalsTeam', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance + beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { From 1f897f3206bc9f919598c4157583a54bd7965cc3 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 10:30:54 -0300 Subject: [PATCH 06/20] chore: Update services/bundleAnalysis tests to Vitest (#3298) --- ...ec.tsx => useBranchBundleSummary.test.tsx} | 47 ++++++++------- ...pec.tsx => useBranchBundlesNames.test.tsx} | 47 ++++++++------- ...pec.tsx => useBundleAssetModules.test.tsx} | 45 +++++++------- ...sets.spec.tsx => useBundleAssets.test.tsx} | 60 +++++++++---------- ...ary.spec.tsx => useBundleSummary.test.tsx} | 49 +++++++-------- ...a.spec.tsx => useBundleTrendData.test.tsx} | 37 ++++++------ 6 files changed, 145 insertions(+), 140 deletions(-) rename src/services/bundleAnalysis/{useBranchBundleSummary.spec.tsx => useBranchBundleSummary.test.tsx} (86%) rename src/services/bundleAnalysis/{useBranchBundlesNames.spec.tsx => useBranchBundlesNames.test.tsx} (84%) rename src/services/bundleAnalysis/{useBundleAssetModules.spec.tsx => useBundleAssetModules.test.tsx} (85%) rename src/services/bundleAnalysis/{useBundleAssets.spec.tsx => useBundleAssets.test.tsx} (88%) rename src/services/bundleAnalysis/{useBundleSummary.spec.tsx => useBundleSummary.test.tsx} (87%) rename src/services/bundleAnalysis/{useBundleTrendData.spec.tsx => useBundleTrendData.test.tsx} (89%) diff --git a/src/services/bundleAnalysis/useBranchBundleSummary.spec.tsx b/src/services/bundleAnalysis/useBranchBundleSummary.test.tsx similarity index 86% rename from src/services/bundleAnalysis/useBranchBundleSummary.spec.tsx rename to src/services/bundleAnalysis/useBranchBundleSummary.test.tsx index c5e25be441..86e20ab856 100644 --- a/src/services/bundleAnalysis/useBranchBundleSummary.spec.tsx +++ b/src/services/bundleAnalysis/useBranchBundleSummary.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBranchBundleSummary } from './useBranchBundleSummary' @@ -90,7 +91,7 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() + vi.resetAllMocks() queryClient.clear() server.resetHandlers() }) @@ -113,28 +114,28 @@ describe('useBranchBundleSummary', () => { isUnsuccessfulParseError = false, isNullOwner = false, }: SetupArgs) { - const passedBranch = jest.fn() + const passedBranch = vi.fn() server.use( - graphql.query('BranchBundleSummaryData', (req, res, ctx) => { - if (req.variables?.branch) { - passedBranch(req.variables?.branch) + graphql.query('BranchBundleSummaryData', (info) => { + if (info.variables?.branch) { + passedBranch(info.variables?.branch) } if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } - return res(ctx.status(200), ctx.data(mockBranchBundleSummary)) + return HttpResponse.json({ data: mockBranchBundleSummary }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) @@ -249,14 +250,14 @@ describe('useBranchBundleSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -283,14 +284,14 @@ describe('useBranchBundleSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -317,14 +318,14 @@ describe('useBranchBundleSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/bundleAnalysis/useBranchBundlesNames.spec.tsx b/src/services/bundleAnalysis/useBranchBundlesNames.test.tsx similarity index 84% rename from src/services/bundleAnalysis/useBranchBundlesNames.spec.tsx rename to src/services/bundleAnalysis/useBranchBundlesNames.test.tsx index 2a0fdcaabb..e5d124130d 100644 --- a/src/services/bundleAnalysis/useBranchBundlesNames.spec.tsx +++ b/src/services/bundleAnalysis/useBranchBundlesNames.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { MockInstance } from 'vitest' import { useBranchBundlesNames } from './useBranchBundlesNames' @@ -77,7 +78,7 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() + vi.clearAllMocks() queryClient.clear() server.resetHandlers() }) @@ -100,28 +101,28 @@ describe('useBranchBundlesNames', () => { isUnsuccessfulParseError = false, isNullOwner = false, }: SetupArgs) { - const passedBranch = jest.fn() + const passedBranch = vi.fn() server.use( - graphql.query('BranchBundlesNames', (req, res, ctx) => { - if (req.variables?.branch) { - passedBranch(req.variables?.branch) + graphql.query('BranchBundlesNames', (info) => { + if (info.variables?.branch) { + passedBranch(info.variables?.branch) } if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } - return res(ctx.status(200), ctx.data(mockBranchBundles)) + return HttpResponse.json({ data: mockBranchBundles }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) @@ -216,14 +217,14 @@ describe('useBranchBundlesNames', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -250,14 +251,14 @@ describe('useBranchBundlesNames', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -284,14 +285,14 @@ describe('useBranchBundlesNames', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/bundleAnalysis/useBundleAssetModules.spec.tsx b/src/services/bundleAnalysis/useBundleAssetModules.test.tsx similarity index 85% rename from src/services/bundleAnalysis/useBundleAssetModules.spec.tsx rename to src/services/bundleAnalysis/useBundleAssetModules.test.tsx index 69d62cb12e..32492bfc58 100644 --- a/src/services/bundleAnalysis/useBundleAssetModules.spec.tsx +++ b/src/services/bundleAnalysis/useBundleAssetModules.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBundleAssetModules } from './useBundleAssetModules' @@ -96,7 +97,7 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() + vi.resetAllMocks() queryClient.clear() server.resetHandlers() }) @@ -121,27 +122,27 @@ describe('useBranchBundleSummary', () => { isNullOwner = false, missingHeadReport = false, }: SetupArgs) { - const passedBranch = jest.fn() + const passedBranch = vi.fn() server.use( - graphql.query('BundleAssetModules', (req, res, ctx) => { - if (req.variables?.branch) { - passedBranch(req.variables?.branch) + graphql.query('BundleAssetModules', (info) => { + if (info.variables?.branch) { + passedBranch(info.variables?.branch) } if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (missingHeadReport) { - return res(ctx.status(200), ctx.data(mockMissingHeadReport)) + return HttpResponse.json({ data: mockMissingHeadReport }) } - return res(ctx.status(200), ctx.data(mockBundleAssetModules)) + return HttpResponse.json({ data: mockBundleAssetModules }) }) ) @@ -218,14 +219,14 @@ describe('useBranchBundleSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -255,14 +256,14 @@ describe('useBranchBundleSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -292,14 +293,14 @@ describe('useBranchBundleSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/bundleAnalysis/useBundleAssets.spec.tsx b/src/services/bundleAnalysis/useBundleAssets.test.tsx similarity index 88% rename from src/services/bundleAnalysis/useBundleAssets.spec.tsx rename to src/services/bundleAnalysis/useBundleAssets.test.tsx index b1b198b059..cd0ced1d15 100644 --- a/src/services/bundleAnalysis/useBundleAssets.spec.tsx +++ b/src/services/bundleAnalysis/useBundleAssets.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBundleAssets } from './useBundleAssets' @@ -130,7 +131,7 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() + vi.clearAllMocks() queryClient.clear() server.resetHandlers() }) @@ -155,31 +156,30 @@ describe('useBundleAssets', () => { isNullOwner = false, missingHeadReport = false, }: SetupArgs) { - const passedBranch = jest.fn() - const madeRequest = jest.fn() + const passedBranch = vi.fn() + const madeRequest = vi.fn() server.use( - graphql.query('BundleAssets', (req, res, ctx) => { + graphql.query('BundleAssets', (info) => { madeRequest() - if (req.variables?.branch) { - passedBranch(req.variables?.branch) + if (info.variables?.branch) { + passedBranch(info.variables?.branch) } if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (missingHeadReport) { - return res(ctx.status(200), ctx.data(mockMissingHeadReport)) + return HttpResponse.json({ data: mockMissingHeadReport }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -194,14 +194,14 @@ describe('useBundleAssets', () => { }, }, assetsPaginated: { - edges: req.variables.assetsAfter + edges: info.variables.assetsAfter ? [{ node: node3 }] : [{ node: node1 }, { node: node2 }], pageInfo: { - hasNextPage: req.variables.assetsAfter + hasNextPage: info.variables.assetsAfter ? false : true, - endCursor: req.variables.assetsAfter + endCursor: info.variables.assetsAfter ? 'cursor-1' : 'cursor-2', }, @@ -212,8 +212,8 @@ describe('useBundleAssets', () => { }, }, }, - }) - ) + }, + }) }) ) @@ -384,14 +384,14 @@ describe('useBundleAssets', () => { }) describe('when __typename is NotFoundError', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -422,14 +422,14 @@ describe('useBundleAssets', () => { }) describe('when __typename is OwnerNotActivatedError', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -460,14 +460,14 @@ describe('useBundleAssets', () => { }) describe('unsuccessful parse error', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/bundleAnalysis/useBundleSummary.spec.tsx b/src/services/bundleAnalysis/useBundleSummary.test.tsx similarity index 87% rename from src/services/bundleAnalysis/useBundleSummary.spec.tsx rename to src/services/bundleAnalysis/useBundleSummary.test.tsx index a1b259bd2f..0a7207c312 100644 --- a/src/services/bundleAnalysis/useBundleSummary.spec.tsx +++ b/src/services/bundleAnalysis/useBundleSummary.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBundleSummary } from './useBundleSummary' @@ -106,7 +107,7 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() + vi.clearAllMocks() queryClient.clear() server.resetHandlers() }) @@ -131,30 +132,30 @@ describe('useBundleSummary', () => { isNullOwner = false, missingHeadReport = false, }: SetupArgs) { - const passedBranch = jest.fn() + const passedBranch = vi.fn() server.use( - graphql.query('BundleSummary', (req, res, ctx) => { - if (req.variables?.branch) { - passedBranch(req.variables?.branch) + graphql.query('BundleSummary', (info) => { + if (info.variables?.branch) { + passedBranch(info.variables?.branch) } if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (missingHeadReport) { - return res(ctx.status(200), ctx.data(mockMissingHeadReport)) + return HttpResponse.json({ data: mockMissingHeadReport }) } - return res(ctx.status(200), ctx.data(mockBundleSummary)) + return HttpResponse.json({ data: mockBundleSummary }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) @@ -293,14 +294,14 @@ describe('useBundleSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -329,14 +330,14 @@ describe('useBundleSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -365,14 +366,14 @@ describe('useBundleSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/bundleAnalysis/useBundleTrendData.spec.tsx b/src/services/bundleAnalysis/useBundleTrendData.test.tsx similarity index 89% rename from src/services/bundleAnalysis/useBundleTrendData.spec.tsx rename to src/services/bundleAnalysis/useBundleTrendData.test.tsx index f306d5a404..76dcf67d56 100644 --- a/src/services/bundleAnalysis/useBundleTrendData.spec.tsx +++ b/src/services/bundleAnalysis/useBundleTrendData.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBundleTrendData } from './useBundleTrendData' @@ -134,20 +135,20 @@ describe('useBundleTrendData', () => { isUnsuccessfulParseError, }: SetupArgs) { server.use( - graphql.query('GetBundleTrend', (req, res, ctx) => { + graphql.query('GetBundleTrend', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else if (isMissingHeadReport) { - return res(ctx.status(200), ctx.data(mockMissingHeadReport)) + return HttpResponse.json({ data: mockMissingHeadReport }) } - return res(ctx.status(200), ctx.data(mockBundleTrendData)) + return HttpResponse.json({ data: mockBundleTrendData }) }) ) } @@ -237,14 +238,14 @@ describe('useBundleTrendData', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -279,14 +280,14 @@ describe('useBundleTrendData', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -321,14 +322,14 @@ describe('useBundleTrendData', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { From 3c70c17d3207f33f687902f2ca2d6bea7015d6d9 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 11:06:58 -0300 Subject: [PATCH 07/20] chore: Update services/repos tests to Vitest (#3306) --- src/services/repos/{config.js => config.ts} | 12 +-- src/services/repos/{index.js => index.ts} | 0 .../{useRepos.spec.tsx => useRepos.test.tsx} | 52 ++++++----- ...posTeam.spec.tsx => useReposTeam.test.tsx} | 91 +++++++------------ 4 files changed, 65 insertions(+), 90 deletions(-) rename src/services/repos/{config.js => config.ts} (88%) rename src/services/repos/{index.js => index.ts} (100%) rename src/services/repos/{useRepos.spec.tsx => useRepos.test.tsx} (80%) rename src/services/repos/{useReposTeam.spec.tsx => useReposTeam.test.tsx} (71%) diff --git a/src/services/repos/config.js b/src/services/repos/config.ts similarity index 88% rename from src/services/repos/config.js rename to src/services/repos/config.ts index 850ba2ae3c..e702e1263c 100644 --- a/src/services/repos/config.js +++ b/src/services/repos/config.ts @@ -29,7 +29,7 @@ export const orderingOptions = [ ordering: 'NAME', direction: 'DESC', }, -] +] as const export const nonActiveOrderingOptions = [ { @@ -42,14 +42,14 @@ export const nonActiveOrderingOptions = [ ordering: 'NAME', direction: 'DESC', }, -] +] as const -export const OrderingDirection = Object.freeze({ +export const OrderingDirection = { DESC: 'DESC', ASC: 'ASC', -}) +} as const -export const TeamOrdering = Object.freeze({ +export const TeamOrdering = { COMMIT_DATE: 'COMMIT_DATE', NAME: 'NAME', -}) +} as const diff --git a/src/services/repos/index.js b/src/services/repos/index.ts similarity index 100% rename from src/services/repos/index.js rename to src/services/repos/index.ts diff --git a/src/services/repos/useRepos.spec.tsx b/src/services/repos/useRepos.test.tsx similarity index 80% rename from src/services/repos/useRepos.spec.tsx rename to src/services/repos/useRepos.test.tsx index 17452ca54d..d0b77d39b5 100644 --- a/src/services/repos/useRepos.spec.tsx +++ b/src/services/repos/useRepos.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { MockInstance } from 'vitest' import { useRepos } from './useRepos' @@ -64,35 +65,32 @@ const repo2 = { } const server = setupServer() - beforeAll(() => { server.listen() - jest.spyOn(global.console, 'error') }) -beforeEach(() => { - server.resetHandlers() +afterEach(() => { queryClient.clear() + server.resetHandlers() }) afterAll(() => { server.close() - jest.resetAllMocks() }) describe('useRepos', () => { function setup({ invalidResponse = false } = {}) { server.use( - graphql.query('ReposForOwner', (req, res, ctx) => { + graphql.query('ReposForOwner', (info) => { if (invalidResponse) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({}) } const data = { owner: { username: 'codecov', repositories: { - edges: req.variables.after + edges: info.variables.after ? [ { node: repo2, @@ -104,8 +102,8 @@ describe('useRepos', () => { }, ], pageInfo: { - hasNextPage: req.variables.after ? false : true, - endCursor: req.variables.after + hasNextPage: info.variables.after ? false : true, + endCursor: info.variables.after ? 'aa' : 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=', }, @@ -113,7 +111,7 @@ describe('useRepos', () => { }, } - return res(ctx.status(200), ctx.data(data)) + return HttpResponse.json({ data }) }) ) } @@ -165,10 +163,7 @@ describe('useRepos', () => { }, }, { - pageInfo: { - endCursor: 'aa', - hasNextPage: false, - }, + pageInfo: { endCursor: 'aa', hasNextPage: false }, repos: [repo2], }, ]) @@ -177,19 +172,28 @@ describe('useRepos', () => { }) describe('error parsing request for owner', () => { + let consoleErrorSpy: MockInstance + beforeAll(() => { + consoleErrorSpy = vi + .spyOn(global.console, 'error') + .mockImplementation(() => {}) + }) + + afterAll(() => { + consoleErrorSpy.mockRestore() + }) + it('throws an error', async () => { setup({ invalidResponse: true }) const { result } = renderHook( () => useRepos({ provider: '', owner: 'owner1' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) - await waitFor(() => expect(result.current.isError).toBeTruthy()) - - expect(result.current.error).toEqual( - expect.objectContaining({ status: 404 }) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ status: 404 }) + ) ) }) }) diff --git a/src/services/repos/useReposTeam.spec.tsx b/src/services/repos/useReposTeam.test.tsx similarity index 71% rename from src/services/repos/useReposTeam.spec.tsx rename to src/services/repos/useReposTeam.test.tsx index a191a53318..40806d6088 100644 --- a/src/services/repos/useReposTeam.spec.tsx +++ b/src/services/repos/useReposTeam.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { MockInstance } from 'vitest' import { useReposTeam } from './useReposTeam' @@ -74,10 +75,8 @@ const repo4 = { } const server = setupServer() - beforeAll(() => { server.listen() - jest.spyOn(global.console, 'error') }) beforeEach(() => { @@ -87,48 +86,33 @@ beforeEach(() => { afterAll(() => { server.close() - jest.resetAllMocks() }) describe('useReposTeam', () => { function setup({ invalidResponse = false } = {}) { server.use( - graphql.query('GetReposTeam', (req, res, ctx) => { + graphql.query('GetReposTeam', (info) => { if (invalidResponse) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({}) } const data = { owner: { isCurrentUserPartOfOrg: true, repositories: { - edges: req.variables.after - ? [ - { - node: repo3, - }, - { - node: repo4, - }, - ] - : [ - { - node: repo1, - }, - { - node: repo2, - }, - ], + edges: info.variables.after + ? [{ node: repo3 }, { node: repo4 }] + : [{ node: repo1 }, { node: repo2 }], pageInfo: { - hasNextPage: req.variables.after ? false : true, - endCursor: req.variables.after + hasNextPage: info.variables.after ? false : true, + endCursor: info.variables.after ? 'aa' : 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=', }, }, }, } - return res(ctx.status(200), ctx.data(data)) + return HttpResponse.json({ data }) }) ) } @@ -137,14 +121,8 @@ describe('useReposTeam', () => { it('returns repositories', async () => { setup() const { result } = renderHook( - () => - useReposTeam({ - activated: true, - owner: 'codecov', - }), - { - wrapper, - } + () => useReposTeam({ activated: true, owner: 'codecov' }), + { wrapper } ) await waitFor(() => @@ -169,15 +147,8 @@ describe('useReposTeam', () => { it('returns repositories of the user', async () => { setup() const { result } = renderHook( - () => - useReposTeam({ - owner: 'codecov', - activated: true, - first: 2, - }), - { - wrapper, - } + () => useReposTeam({ owner: 'codecov', activated: true, first: 2 }), + { wrapper } ) await waitFor(() => result.current.isFetching) @@ -185,9 +156,6 @@ describe('useReposTeam', () => { result.current.fetchNextPage() - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.data).toEqual({ pages: [ @@ -215,24 +183,27 @@ describe('useReposTeam', () => { }) describe('error parsing request for owner', () => { + let consoleSpy: MockInstance + + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + consoleSpy.mockRestore() + }) + it('throws an error', async () => { setup({ invalidResponse: true }) const { result } = renderHook( - () => - useReposTeam({ - owner: 'codecov', - activated: true, - first: 2, - }), - { - wrapper, - } + () => useReposTeam({ owner: 'codecov', activated: true, first: 2 }), + { wrapper } ) - await waitFor(() => expect(result.current.isError).toBeTruthy()) - - expect(result.current.error).toEqual( - expect.objectContaining({ status: 404 }) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ status: 404 }) + ) ) }) }) From 13bed16897a1f8562d1833e0366eb978dde4053d Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 12:22:08 -0300 Subject: [PATCH 08/20] chore: Update pages/RepoPage/CommitsTab tests to Vitest (#3329) --- ...ommitsTab.spec.jsx => CommitsTab.test.jsx} | 306 ++++++------------ ...tsTable.spec.tsx => CommitsTable.test.tsx} | 51 ++- .../Title/{Title.spec.tsx => Title.test.tsx} | 27 +- ...ec.tsx => createCommitsTableData.test.tsx} | 0 ...x => useCommitsTabBranchSelector.test.tsx} | 42 +-- 5 files changed, 145 insertions(+), 281 deletions(-) rename src/pages/RepoPage/CommitsTab/{CommitsTab.spec.jsx => CommitsTab.test.jsx} (70%) rename src/pages/RepoPage/CommitsTab/CommitsTable/{CommitsTable.spec.tsx => CommitsTable.test.tsx} (89%) rename src/pages/RepoPage/CommitsTab/CommitsTable/Title/{Title.spec.tsx => Title.test.tsx} (89%) rename src/pages/RepoPage/CommitsTab/CommitsTable/{createCommitsTableData.spec.tsx => createCommitsTableData.test.tsx} (100%) rename src/pages/RepoPage/CommitsTab/hooks/{useCommitsTabBranchSelector.spec.tsx => useCommitsTabBranchSelector.test.tsx} (87%) diff --git a/src/pages/RepoPage/CommitsTab/CommitsTab.spec.jsx b/src/pages/RepoPage/CommitsTab/CommitsTab.test.jsx similarity index 70% rename from src/pages/RepoPage/CommitsTab/CommitsTab.spec.jsx rename to src/pages/RepoPage/CommitsTab/CommitsTab.test.jsx index 8027410f8f..139024d91e 100644 --- a/src/pages/RepoPage/CommitsTab/CommitsTab.spec.jsx +++ b/src/pages/RepoPage/CommitsTab/CommitsTab.test.jsx @@ -1,19 +1,28 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { within } from '@testing-library/react' +import { render, screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { Suspense } from 'react' -import { Route } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' +import { MemoryRouter, Route } from 'react-router-dom' import { TierNames } from 'services/tier' import CommitsTab from './CommitsTab' -import { repoPageRender, screen, waitFor } from '../repo-jest-setup' +import { RepoBreadcrumbProvider } from '../context' -jest.mock('react-use/lib/useIntersection') +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), +})) + +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, suspense: true } }, @@ -21,16 +30,22 @@ const queryClient = new QueryClient({ const server = setupServer() let testLocation -const Wrapper = ({ children }) => ( +const wrapper = ({ children }) => ( - loading

}>{children}
- { - testLocation = location - return null - }} - /> + + + Loading

}> + {children} +
+
+ { + testLocation = location + return null + }} + /> +
) @@ -54,12 +69,7 @@ const mockBranches = (hasNextPage = false) => ({ branches: { edges: [ { - node: { - name: 'main', - head: { - commitid: '1', - }, - }, + node: { name: 'main', head: { commitid: '1' } }, }, ], pageInfo: { @@ -200,63 +210,62 @@ describe('CommitsTab', () => { isPrivate = false, }) { const user = userEvent.setup() - const fetchNextPage = jest.fn() - const branchSearch = jest.fn() - const commitSearch = jest.fn() - const branchName = jest.fn() + const fetchNextPage = vi.fn() + const branchSearch = vi.fn() + const commitSearch = vi.fn() + const branchName = vi.fn() server.use( - graphql.query('GetBranches', (req, res, ctx) => { - if (!!req?.variables?.after) { - fetchNextPage(req?.variables?.after) + graphql.query('GetBranches', (info) => { + if (!!info?.variables?.after) { + fetchNextPage(info?.variables?.after) } - if (!!req?.variables?.filters?.searchValue) { - branchSearch(req?.variables?.filters?.searchValue) + if (!!info?.variables?.filters?.searchValue) { + branchSearch(info?.variables?.filters?.searchValue) } if (hasBranches) { - return res( - ctx.status(200), - ctx.data({ owner: { repository: { branches: null } } }) - ) + return HttpResponse.json({ + data: { owner: { repository: { branches: null } } }, + }) } - return res(ctx.status(200), ctx.data(mockBranches(hasNextPage))) + return HttpResponse.json({ data: mockBranches(hasNextPage) }) }), - graphql.query('GetCommits', (req, res, ctx) => { - if (!!req?.variables?.filters?.branchName) { - branchName(req?.variables?.filters?.branchName) + graphql.query('GetCommits', (info) => { + if (!!info?.variables?.filters?.branchName) { + branchName(info?.variables?.filters?.branchName) } - if (!!req?.variables?.filters?.search) { - commitSearch(req?.variables?.filters?.search) + if (!!info?.variables?.filters?.search) { + commitSearch(info?.variables?.filters?.search) } - return res(ctx.status(200), ctx.data(mockCommits)) + return HttpResponse.json({ data: mockCommits }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockOverview)) - ), - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockOverview }) + }), + graphql.query('GetBranch', (info) => { if (returnBranch) { - return res(ctx.status(200), ctx.data(mockBranch(returnBranch))) + return HttpResponse.json({ data: mockBranch(returnBranch) }) } - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) + }), + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: { owner: null } }) }), - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data({})) - ), - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoSettings(isPrivate))) + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ data: mockRepoSettings(isPrivate) }) }), - graphql.query('GetBranchCommits', (req, res, ctx) => { + graphql.query('GetBranchCommits', (info) => { if (branchHasCommits) { - return res(ctx.status(200), ctx.data(mockBranchHasCommits)) - } else { - return res(ctx.status(200), ctx.data(mockBranchHasNoCommits)) + return HttpResponse.json({ data: mockBranchHasCommits }) } + + return HttpResponse.json({ data: mockBranchHasNoCommits }) }) ) @@ -264,7 +273,7 @@ describe('CommitsTab', () => { } afterEach(() => { - jest.resetAllMocks() + vi.clearAllMocks() }) describe('when rendered', () => { @@ -272,14 +281,7 @@ describe('CommitsTab', () => { describe('when branch has commits', () => { it('uses default branch', async () => { setup({ hasNextPage: true, returnBranch: 'main' }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const selector = await screen.findByRole('button', { name: 'Select branch', @@ -294,14 +296,7 @@ describe('CommitsTab', () => { describe('when branch has no commits', () => { it('uses returned branch', async () => { setup({ branchHasCommits: false, returnBranch: 'main' }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const selector = await screen.findByRole('button', { name: 'Select branch', @@ -315,16 +310,9 @@ describe('CommitsTab', () => { }) }) - it('renders ci status mutliselect', async () => { + it('renders ci status multiselect', async () => { setup({ hasNextPage: true }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const multiSelect = await screen.findByRole('button', { name: 'Filter by coverage upload status', @@ -336,14 +324,7 @@ describe('CommitsTab', () => { describe('rendering CommitsTable', () => { it('renders with table name heading', async () => { setup({ hasNextPage: true }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const head = await screen.findByText(/Name/) expect(head).toBeInTheDocument() @@ -351,22 +332,19 @@ describe('CommitsTab', () => { describe('when select onLoadMore is triggered', () => { beforeEach(() => { - useIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) }) + afterEach(() => { + vi.clearAllMocks() + }) + describe('when there is not a next page', () => { it('does not call fetchNextPage', async () => { const { user, fetchNextPage } = setup({ hasNextPage: false }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -380,23 +358,11 @@ describe('CommitsTab', () => { describe('when there is a next page', () => { it('calls fetchNextPage', async () => { const { fetchNextPage, user } = setup({ hasNextPage: true }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByText('Select branch') await user.click(select) - await waitFor(() => queryClient.isFetching) - await waitFor(() => !queryClient.isFetching) - - await waitFor(() => expect(fetchNextPage).toHaveBeenCalled()) await waitFor(() => expect(fetchNextPage).toHaveBeenCalledWith('some cursor') ) @@ -408,14 +374,7 @@ describe('CommitsTab', () => { describe('user selects All branches', () => { it('updates the button with the selected branch', async () => { const { user } = setup({ hasNextPage: false, returnBranch: 'main' }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -457,14 +416,7 @@ describe('CommitsTab', () => { describe('user selects a branch', () => { it('updates the button with the selected branch', async () => { const { user } = setup({ hasNextPage: false, returnBranch: 'main' }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -488,14 +440,7 @@ describe('CommitsTab', () => { describe('user selects from the CI states multiselect', () => { it('selects the option', async () => { const { user } = setup({}) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Filter by coverage upload status', @@ -516,15 +461,7 @@ describe('CommitsTab', () => { describe('user searches for branch', () => { it('fetches request with search term', async () => { const { branchSearch, user } = setup({ hasNextPage: false }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByText('Select branch') await user.click(select) @@ -540,15 +477,7 @@ describe('CommitsTab', () => { it('hides All branches from list', async () => { const { branchSearch, user } = setup({ hasNextPage: false }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -568,15 +497,7 @@ describe('CommitsTab', () => { describe('user searches for commit', () => { it('fetches commits request with search term', async () => { const { commitSearch, user } = setup({ hasNextPage: false }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const search = await screen.findByPlaceholderText('Search commits') await user.type(search, 'searching for a commit') @@ -599,14 +520,7 @@ describe('CommitsTab', () => { tierValue: TierNames.TEAM, isPrivate: true, }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -634,14 +548,7 @@ describe('CommitsTab', () => { tierValue: TierNames.TEAM, isPrivate: true, }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -665,14 +572,7 @@ describe('CommitsTab', () => { describe('user selects from the CI states multiselect', () => { it('selects the option', async () => { const { user } = setup({ tierValue: TierNames.TEAM, isPrivate: true }) - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Filter by coverage upload status', @@ -697,15 +597,7 @@ describe('CommitsTab', () => { tierValue: TierNames.TEAM, isPrivate: true, }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByText('Select branch') await user.click(select) @@ -725,15 +617,7 @@ describe('CommitsTab', () => { tierValue: TierNames.TEAM, isPrivate: true, }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const select = await screen.findByRole('button', { name: 'Select branch', @@ -757,15 +641,7 @@ describe('CommitsTab', () => { tierValue: TierNames.TEAM, isPrivate: true, }) - - repoPageRender({ - renderCommits: () => ( - - - - ), - initialEntries: ['/gh/codecov/gazebo/commits'], - }) + render(, { wrapper }) const search = await screen.findByPlaceholderText('Search commits') await user.type(search, 'searching for a commit') diff --git a/src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.spec.tsx b/src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.test.tsx similarity index 89% rename from src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.spec.tsx rename to src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.test.tsx index efa0216cc3..bda31c72ef 100644 --- a/src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.spec.tsx +++ b/src/pages/RepoPage/CommitsTab/CommitsTable/CommitsTable.test.tsx @@ -4,8 +4,8 @@ import { screen, waitForElementToBeRemoved, } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { mockIsIntersecting } from 'react-intersection-observer/test-utils' import { MemoryRouter, Route } from 'react-router-dom' @@ -40,9 +40,7 @@ const node1 = { coverageStatus: 'COMPLETED', compareWithParent: { __typename: 'Comparison', - patchTotals: { - percentCovered: 80, - }, + patchTotals: { percentCovered: 80 }, }, bundleAnalysisCompareWithParent: { __typename: 'MissingHeadReport', @@ -63,17 +61,11 @@ const node2 = { coverageStatus: 'COMPLETED', compareWithParent: { __typename: 'Comparison', - patchTotals: { - percentCovered: 90, - }, + patchTotals: { percentCovered: 90 }, }, bundleAnalysisCompareWithParent: { __typename: 'BundleAnalysisComparison', - bundleChange: { - size: { - uncompress: 1000, - }, - }, + bundleChange: { size: { uncompress: 1000 } }, }, } @@ -140,31 +132,26 @@ describe('CommitsTable', () => { const queryClient = new QueryClient() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepoOverview(bundleAnalysisEnabled)) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview(bundleAnalysisEnabled), + }) }), - graphql.query('GetCommits', (req, res, ctx) => { + graphql.query('GetCommits', (info) => { if (noEntries) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', commits: { edges: [], - pageInfo: { - hasNextPage: false, - endCursor: null, - }, + pageInfo: { hasNextPage: false, endCursor: null }, }, }, }, - }) - ) + }, + }) } const dataReturned = { @@ -172,7 +159,7 @@ describe('CommitsTable', () => { repository: { __typename: 'Repository', commits: { - edges: req.variables.after + edges: info.variables.after ? [ { node: node3, @@ -187,8 +174,8 @@ describe('CommitsTable', () => { }, ], pageInfo: { - hasNextPage: req.variables.after ? false : true, - endCursor: req.variables.after + hasNextPage: info.variables.after ? false : true, + endCursor: info.variables.after ? 'aa' : 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=', }, @@ -196,7 +183,7 @@ describe('CommitsTable', () => { }, }, } - return res(ctx.status(200), ctx.data(dataReturned)) + return HttpResponse.json({ data: dataReturned }) }) ) diff --git a/src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.spec.tsx b/src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.test.tsx similarity index 89% rename from src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.spec.tsx rename to src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.test.tsx index 35fb57d349..884b1affa8 100644 --- a/src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.spec.tsx +++ b/src/pages/RepoPage/CommitsTab/CommitsTable/Title/Title.test.tsx @@ -2,18 +2,23 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' -import { useImage as originalUseImage } from 'services/image' import { formatTimeToNow } from 'shared/utils/dates' -import Title from '.' +import Title from './Title' -jest.mock('services/image') -jest.mock('services/user') -jest.mock('services/repo') +const mocks = vi.hoisted(() => ({ + useImage: vi.fn(), +})) -const useImage = originalUseImage as jest.MockedFunction< - typeof originalUseImage -> +vi.mock('services/image', async () => { + const actual = await vi.importActual('services/image') + return { + ...actual, + useImage: mocks.useImage, + } +}) +vi.mock('services/user') +vi.mock('services/repo') interface setupArgs { author?: { @@ -30,7 +35,11 @@ describe('Title', () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) - useImage.mockReturnValue({ src: 'imageUrl', isLoading: false, error: null }) + mocks.useImage.mockReturnValue({ + src: 'imageUrl', + isLoading: false, + error: null, + }) render( diff --git a/src/pages/RepoPage/CommitsTab/CommitsTable/createCommitsTableData.spec.tsx b/src/pages/RepoPage/CommitsTab/CommitsTable/createCommitsTableData.test.tsx similarity index 100% rename from src/pages/RepoPage/CommitsTab/CommitsTable/createCommitsTableData.spec.tsx rename to src/pages/RepoPage/CommitsTab/CommitsTable/createCommitsTableData.test.tsx diff --git a/src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.spec.tsx b/src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.test.tsx similarity index 87% rename from src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.spec.tsx rename to src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.test.tsx index 6ccf0875e6..9420166684 100644 --- a/src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.spec.tsx +++ b/src/pages/RepoPage/CommitsTab/hooks/useCommitsTabBranchSelector.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -24,9 +24,7 @@ const mockMainBranchSearch = { { node: { name: 'main', - head: { - commitid: '321fdsa', - }, + head: { commitid: '321fdsa' }, }, }, ], @@ -44,17 +42,13 @@ const mockBranches = { { node: { name: 'branch-1', - head: { - commitid: 'asdf123', - }, + head: { commitid: 'asdf123' }, }, }, { node: { name: 'main', - head: { - commitid: '321fdsa', - }, + head: { commitid: '321fdsa' }, }, }, ], @@ -117,29 +111,27 @@ describe('useCommitsTabBranchSelector', () => { hasNoBranches = false ) { server.use( - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { if (returnBranch) { - return res(ctx.status(200), ctx.data(mockBranch(branchName))) + return HttpResponse.json({ data: mockBranch(branchName) }) } - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) }), - graphql.query('GetBranches', (req, res, ctx) => { + graphql.query('GetBranches', (info) => { if (hasNoBranches) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - if (req.variables?.filters?.searchValue === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches } }, + }) }) ) } From 98e61c7f8beb06794438ad1a5ddf0653d2eb824d Mon Sep 17 00:00:00 2001 From: Spencer Murray <159931558+spalmurray-codecov@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:40:57 -0400 Subject: [PATCH 09/20] fix: Spacing on upload (#3330) --- .../CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx index 8c35144abc..abd0b62233 100644 --- a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx +++ b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx @@ -35,7 +35,7 @@ const Upload = ({ return (
-
+
Date: Fri, 27 Sep 2024 13:21:05 -0700 Subject: [PATCH 10/20] feat: Use new coverage analytics graphql schema (#3169) --- .../OverviewTab/OverviewTab.spec.tsx | 38 +++++------ .../hooks/useRepoCoverageTimeseries.spec.js | 60 +++++++++-------- .../CoverageChart/CoverageChart.spec.jsx | 64 +++++++++++-------- .../useBranchCoverageMeasurements.spec.tsx | 38 +++++------ .../charts/useBranchCoverageMeasurements.tsx | 30 +++++---- 5 files changed, 125 insertions(+), 105 deletions(-) diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx index 9956ad1837..9de66c62f7 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx @@ -186,24 +186,26 @@ const mockBranchMeasurements = { owner: { repository: { __typename: 'Repository', - measurements: [ - { - timestamp: '2023-01-01T00:00:00+00:00', - max: 85, - }, - { - timestamp: '2023-01-02T00:00:00+00:00', - max: 80, - }, - { - timestamp: '2023-01-03T00:00:00+00:00', - max: 90, - }, - { - timestamp: '2023-01-04T00:00:00+00:00', - max: 100, - }, - ], + coverageAnalytics: { + measurements: [ + { + timestamp: '2023-01-01T00:00:00+00:00', + max: 85, + }, + { + timestamp: '2023-01-02T00:00:00+00:00', + max: 80, + }, + { + timestamp: '2023-01-03T00:00:00+00:00', + max: 90, + }, + { + timestamp: '2023-01-04T00:00:00+00:00', + max: 100, + }, + ], + }, }, }, } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js index 10b4398b80..549a37299b 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js @@ -28,24 +28,26 @@ const mockBranchMeasurements = { owner: { repository: { __typename: 'Repository', - measurements: [ - { - timestamp: '2023-01-01T00:00:00+00:00', - max: 85, - }, - { - timestamp: '2023-01-02T00:00:00+00:00', - max: 80, - }, - { - timestamp: '2023-01-03T00:00:00+00:00', - max: 90, - }, - { - timestamp: '2023-01-04T00:00:00+00:00', - max: 100, - }, - ], + coverageAnalytics: { + measurements: [ + { + timestamp: '2023-01-01T00:00:00+00:00', + max: 85, + }, + { + timestamp: '2023-01-02T00:00:00+00:00', + max: 80, + }, + { + timestamp: '2023-01-03T00:00:00+00:00', + max: 90, + }, + { + timestamp: '2023-01-04T00:00:00+00:00', + max: 100, + }, + ], + }, }, }, } @@ -54,16 +56,18 @@ const mockNullBranchMeasurements = { owner: { repository: { __typename: 'Repository', - measurements: [ - { - timestamp: '2023-01-01T00:00:00+00:00', - max: null, - }, - { - timestamp: '2023-01-02T00:00:00+00:00', - max: null, - }, - ], + coverageAnalytics: { + measurements: [ + { + timestamp: '2023-01-01T00:00:00+00:00', + max: null, + }, + { + timestamp: '2023-01-02T00:00:00+00:00', + max: null, + }, + ], + }, }, }, } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx index 5dd6cd15c8..2ba093cc64 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx @@ -94,24 +94,26 @@ const branchesMock = { const mockBranchMeasurements = { __typename: 'Repository', - measurements: [ - { - timestamp: '2023-01-01T00:00:00+00:00', - max: 85, - }, - { - timestamp: '2023-01-02T00:00:00+00:00', - max: 80, - }, - { - timestamp: '2023-01-03T00:00:00+00:00', - max: 90, - }, - { - timestamp: '2023-01-04T00:00:00+00:00', - max: 100, - }, - ], + coverageAnalytics: { + measurements: [ + { + timestamp: '2023-01-01T00:00:00+00:00', + max: 85, + }, + { + timestamp: '2023-01-02T00:00:00+00:00', + max: 80, + }, + { + timestamp: '2023-01-03T00:00:00+00:00', + max: 90, + }, + { + timestamp: '2023-01-04T00:00:00+00:00', + max: 100, + }, + ], + }, } const branchMock = { @@ -152,7 +154,11 @@ describe('CoverageChart', () => { return res( ctx.status(200), - ctx.data({ owner: { repository: branchMeasurementsData } }) + ctx.data({ + owner: { + repository: branchMeasurementsData, + }, + }) ) }) ) @@ -165,10 +171,12 @@ describe('CoverageChart', () => { branchesData: branchesMock, branchMeasurementsData: { __typename: 'Repository', - measurements: [ - { timestamp: '2020-01-15T20:18:39.413Z', max: 20 }, - { timestamp: '2020-01-17T20:18:39.413Z', max: 50 }, - ], + coverageAnalytics: { + measurements: [ + { timestamp: '2020-01-15T20:18:39.413Z', max: 20 }, + { timestamp: '2020-01-17T20:18:39.413Z', max: 50 }, + ], + }, }, }) }) @@ -193,10 +201,12 @@ describe('CoverageChart', () => { branchesData: branchesMock, branchMeasurementsData: { __typename: 'Repository', - measurements: [ - { timestamp: '2020-01-15T20:18:39.413Z', max: 20 }, - { timestamp: '2020-01-17T20:18:39.413Z', max: 0 }, - ], + coverageAnalytics: { + measurements: [ + { timestamp: '2020-01-15T20:18:39.413Z', max: 20 }, + { timestamp: '2020-01-17T20:18:39.413Z', max: 0 }, + ], + }, }, }) }) diff --git a/src/services/charts/useBranchCoverageMeasurements.spec.tsx b/src/services/charts/useBranchCoverageMeasurements.spec.tsx index 2e16826e1b..e56e03efb2 100644 --- a/src/services/charts/useBranchCoverageMeasurements.spec.tsx +++ b/src/services/charts/useBranchCoverageMeasurements.spec.tsx @@ -9,24 +9,26 @@ const mockBranchMeasurements = { owner: { repository: { __typename: 'Repository', - measurements: [ - { - timestamp: '2023-01-01T00:00:00+00:00', - max: 85, - }, - { - timestamp: '2023-01-02T00:00:00+00:00', - max: 80, - }, - { - timestamp: '2023-01-03T00:00:00+00:00', - max: 90, - }, - { - timestamp: '2023-01-04T00:00:00+00:00', - max: 100, - }, - ], + coverageAnalytics: { + measurements: [ + { + timestamp: '2023-01-01T00:00:00+00:00', + max: 85, + }, + { + timestamp: '2023-01-02T00:00:00+00:00', + max: 80, + }, + { + timestamp: '2023-01-03T00:00:00+00:00', + max: 90, + }, + { + timestamp: '2023-01-04T00:00:00+00:00', + max: 100, + }, + ], + }, }, }, } diff --git a/src/services/charts/useBranchCoverageMeasurements.tsx b/src/services/charts/useBranchCoverageMeasurements.tsx index 41c6557237..4a829c0280 100644 --- a/src/services/charts/useBranchCoverageMeasurements.tsx +++ b/src/services/charts/useBranchCoverageMeasurements.tsx @@ -33,11 +33,10 @@ const GetBranchCoverageMeasurementsSchema = z.object({ .object({ repository: z .discriminatedUnion('__typename', [ - z - .object({ - __typename: z.literal('Repository'), - }) - .merge(MeasurementsSchema), + z.object({ + __typename: z.literal('Repository'), + coverageAnalytics: MeasurementsSchema.nullable(), + }), RepoNotFoundErrorSchema, RepoOwnerNotActivatedErrorSchema, ]) @@ -59,14 +58,16 @@ query GetBranchCoverageMeasurements( repository: repository(name: $repo) { __typename ... on Repository { - measurements( - interval: $interval - after: $after - before: $before - branch: $branch - ) { - timestamp - max + coverageAnalytics{ + measurements( + interval: $interval + after: $after + before: $before + branch: $branch + ) { + timestamp + max + } } } ... on NotFoundError { @@ -167,7 +168,8 @@ export const useBranchCoverageMeasurements = ({ } return { - measurements: data?.owner?.repository?.measurements ?? [], + measurements: + data?.owner?.repository?.coverageAnalytics?.measurements ?? [], } }), ...opts, From a8ca0266a28c2c507db2948a3096819a0d20086f Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Fri, 27 Sep 2024 15:59:49 -0700 Subject: [PATCH 11/20] chore: Bump vite to resolve vulnerability (#3331) --- package.json | 2 +- yarn.lock | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index cb22525f0f..4e2018afac 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "storybook": "^8.2.6", "tailwindcss": "^3.4.4", "typescript": "^4.9.5", - "vite": "^5.4.1", + "vite": "^5.4.8", "vite-plugin-ejs": "^1.7.0", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^5.0.1", diff --git a/yarn.lock b/yarn.lock index 8f2e044693..adf6083c4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11847,7 +11847,7 @@ __metadata: tailwindcss: "npm:^3.4.4" typescript: "npm:^4.9.5" victory: "npm:^37.0.2" - vite: "npm:^5.4.1" + vite: "npm:^5.4.8" vite-plugin-ejs: "npm:^1.7.0" vite-plugin-svgr: "npm:^4.2.0" vite-tsconfig-paths: "npm:^5.0.1" @@ -16572,6 +16572,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.0": + version: 1.1.0 + resolution: "picocolors@npm:1.1.0" + checksum: 10c0/86946f6032148801ef09c051c6fb13b5cf942eaf147e30ea79edb91dd32d700934edebe782a1078ff859fb2b816792e97ef4dab03d7f0b804f6b01a0df35e023 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -17539,6 +17546,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.4.43": + version: 8.4.47 + resolution: "postcss@npm:8.4.47" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.1.0" + source-map-js: "npm:^1.2.1" + checksum: 10c0/929f68b5081b7202709456532cee2a145c1843d391508c5a09de2517e8c4791638f71dd63b1898dba6712f8839d7a6da046c72a5e44c162e908f5911f57b5f44 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -18875,7 +18893,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.13.0, rollup@npm:^4.20.0": +"rollup@npm:^4.20.0": version: 4.21.0 resolution: "rollup@npm:4.21.0" dependencies: @@ -19535,6 +19553,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + "source-map-loader@npm:^3.0.0": version: 3.0.2 resolution: "source-map-loader@npm:3.0.2" @@ -21966,14 +21991,14 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.4.1": - version: 5.4.1 - resolution: "vite@npm:5.4.1" +"vite@npm:^5.4.8": + version: 5.4.8 + resolution: "vite@npm:5.4.8" dependencies: esbuild: "npm:^0.21.3" fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.41" - rollup: "npm:^4.13.0" + postcss: "npm:^8.4.43" + rollup: "npm:^4.20.0" peerDependencies: "@types/node": ^18.0.0 || >=20.0.0 less: "*" @@ -22005,7 +22030,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/b9ea824f1a946aa494f756e6d9dd88869baa62ae5ba3071b32b6a20958fd622cb624c860bdd7daee201c83ca029feaf8bbe2d2a6e172a5d49308772f8899d86d + checksum: 10c0/af70af6d6316a3af71f44ebe3ab343bd66450d4157af73af3b32239e1b6ec43ff6f651d7cc4193b21ed3bff2e9356a3de9e96aee53857f39922e4a2d9fad75a1 languageName: node linkType: hard From c76f6170cf724eb777982f8249fce9721ec8929e Mon Sep 17 00:00:00 2001 From: Rola Abuhasna Date: Mon, 30 Sep 2024 15:28:12 +0200 Subject: [PATCH 12/20] feat: Tokenless banner for admin/member views (#3287) --- .../GlobalTopBanners.test.tsx | 10 + .../GlobalTopBanners/GlobalTopBanners.tsx | 5 +- .../TokenlessBanner/TokenlessBanner.test.tsx | 261 ++++++++++++++++++ .../TokenlessBanner/TokenlessBanner.tsx | 159 +++++++++++ .../GlobalTopBanners/TokenlessBanner/index.ts | 1 + src/ui/Button/Button.jsx | 1 + 6 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.test.tsx create mode 100644 src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.tsx create mode 100644 src/shared/GlobalTopBanners/TokenlessBanner/index.ts diff --git a/src/shared/GlobalTopBanners/GlobalTopBanners.test.tsx b/src/shared/GlobalTopBanners/GlobalTopBanners.test.tsx index a0dbbff10f..ac74c2e518 100644 --- a/src/shared/GlobalTopBanners/GlobalTopBanners.test.tsx +++ b/src/shared/GlobalTopBanners/GlobalTopBanners.test.tsx @@ -20,6 +20,9 @@ vi.mock('./BundleFeedbackBanner', () => ({ vi.mock('./OktaBanners', () => ({ default: () => 'OktaBanners', })) +vi.mock('./TokenlessBanner', () => ({ + default: () => 'TokenlessBanner', +})) describe('GlobalTopBanners', () => { it('renders sentry trial banner', async () => { @@ -63,4 +66,11 @@ describe('GlobalTopBanners', () => { const banner = await screen.findByText(/OktaBanners/) expect(banner).toBeInTheDocument() }) + + it('renders tokenless banner', async () => { + render() + + const banner = await screen.findByText(/TokenlessBanner/) + expect(banner).toBeInTheDocument() + }) }) diff --git a/src/shared/GlobalTopBanners/GlobalTopBanners.tsx b/src/shared/GlobalTopBanners/GlobalTopBanners.tsx index af023161f3..4d2da6a1ac 100644 --- a/src/shared/GlobalTopBanners/GlobalTopBanners.tsx +++ b/src/shared/GlobalTopBanners/GlobalTopBanners.tsx @@ -8,18 +8,19 @@ const TrialBanner = lazy(() => import('./TrialBanner')) const TeamPlanFeedbackBanner = lazy(() => import('./TeamPlanFeedbackBanner')) const ProPlanFeedbackBanner = lazy(() => import('./ProPlanFeedbackBanner')) const OktaBanners = lazy(() => import('./OktaBanners')) +const TokenlessBanner = lazy(() => import('./TokenlessBanner')) const GlobalTopBanners: React.FC = () => { return ( - {/* These are listed in priority order: if multiple banners are rendering, only the bottommost will display. */} -
+
+
) diff --git a/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.test.tsx b/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.test.tsx new file mode 100644 index 0000000000..17877c5ded --- /dev/null +++ b/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.test.tsx @@ -0,0 +1,261 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen, waitFor, within } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { MemoryRouter, Route } from 'react-router-dom' +import ResizeObserver from 'resize-observer-polyfill' + +import { useFlags } from 'shared/featureFlags' + +import TokenlessBanner from './TokenlessBanner' + +vi.mock('shared/featureFlags') +global.ResizeObserver = ResizeObserver +const mockedUseFlags = useFlags as jest.Mock + +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) + +const server = setupServer() +beforeAll(() => { + console.error = () => {} + server.listen() +}) +beforeEach(() => { + server.resetHandlers() + queryClient.clear() +}) +afterAll(() => server.close()) + +const mockOwner = { + ownerid: 1, + username: 'codecov', + avatarUrl: 'http://127.0.0.1/avatar-url', + isCurrentUserPartOfOrg: true, + isAdmin: true, +} + +const wrapper = + ( + initialEntries = ['/gh/codecov'], + path = '/:provider/:owner' + ): React.FC => + ({ children }) => ( + + + {children} + + + ) + +describe('TokenlessBanner', () => { + function setup({ + isAdmin = true, + orgUploadToken = 'mock-token', + }: { isAdmin?: boolean; orgUploadToken?: string | null } = {}) { + mockedUseFlags.mockReturnValue({ tokenlessSection: true }) + + server.use( + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ + data: { + owner: { + ...mockOwner, + isAdmin: isAdmin, + }, + }, + }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: { + owner: { + orgUploadToken: orgUploadToken, + }, + }, + }) + }) + ) + + return { user: userEvent.setup() } + } + + it('should return null if no owner is provided', () => { + setup() + const { container } = render(, { + wrapper: wrapper(['/gh/'], '/:provider'), + }) + + expect(container).toBeEmptyDOMElement() + }) + + describe('when user is admin', () => { + it('should render content of AdminTokenlessBanner', async () => { + setup({ isAdmin: true }) + render(, { wrapper: wrapper() }) + + const content = await screen.findByText( + /Uploading with the token is now required./ + ) + expect(content).toBeInTheDocument() + }) + + it('should return token copy without tooltip if token is not provided', async () => { + setup({ orgUploadToken: null }) + render(, { wrapper: wrapper() }) + + const token = await screen.findByText(/the token. /) + expect(token).toBeInTheDocument() + }) + + it('should render token tooltip', async () => { + setup({ isAdmin: true }) + render(, { wrapper: wrapper() }) + + const trigger = await screen.findByTestId(/token-trigger/) + expect(trigger).toBeInTheDocument() + }) + + it('should render link to global upload token settings', async () => { + setup({ isAdmin: true }) + render(, { wrapper: wrapper() }) + + const link = await screen.findByRole('link', { + name: /global upload token settings./, + }) + + expect(link).toBeInTheDocument() + expect(link).toHaveAttribute( + 'href', + '/account/gh/codecov/org-upload-token' + ) + }) + }) + + describe('when user is not admin', () => { + it('should render content of MemberTokenlessBanner', async () => { + setup({ isAdmin: false }) + render(, { wrapper: wrapper() }) + + const content = await screen.findByText( + /Uploading with the token is now required./ + ) + expect(content).toBeInTheDocument() + }) + + it('should return token copy without tooltip if token is not provided', async () => { + setup({ isAdmin: false, orgUploadToken: null }) + render(, { wrapper: wrapper() }) + + const token = await screen.findByText(/the token. /) + expect(token).toBeInTheDocument() + }) + + it('should render token tooltip', async () => { + setup({ isAdmin: false }) + render(, { wrapper: wrapper() }) + + const trigger = await screen.findByTestId(/token-trigger/) + expect(trigger).toBeInTheDocument() + }) + + it('should render reach to admin copy', async () => { + setup({ isAdmin: false }) + render(, { wrapper: wrapper() }) + + const copy = await screen.findByText( + /Contact your admins to manage the upload token settings./ + ) + expect(copy).toBeInTheDocument() + }) + }) + + describe('org upload token tooltip', () => { + it('should render the tooltip', async () => { + setup() + render(, { wrapper: wrapper() }) + + const tooltip = await screen.findByText(/the token. /) + expect(tooltip).toBeInTheDocument() + }) + + it('should render the content6 of the tooltip on hover', async () => { + const { user } = setup() + render(, { wrapper: wrapper() }) + + await waitFor(() => screen.findByTestId(/token-trigger/)) + const trigger = screen.getByTestId(/token-trigger/) + await user.hover(trigger) + + const tooltip = await screen.findByRole('tooltip') + const tooltipContent = within(tooltip).getByText(/mock-token/) + expect(tooltipContent).toBeInTheDocument() + }) + + it('should be rendered with eye off icon', async () => { + const { user } = setup() + render(, { wrapper: wrapper() }) + + await waitFor(() => screen.findByTestId(/token-trigger/)) + const trigger = screen.getByTestId(/token-trigger/) + await user.hover(trigger) + + const tooltip = await screen.findByRole('tooltip') + const eyeIcon = within(tooltip).getByTestId('hide-token') + expect(eyeIcon).toBeInTheDocument() + }) + + it('switches to eye on icon on click', async () => { + const { user } = setup() + render(, { wrapper: wrapper() }) + + await waitFor(() => screen.findByTestId(/token-trigger/)) + const trigger = screen.getByTestId(/token-trigger/) + await user.hover(trigger) + + const tooltip = await screen.findByRole('tooltip') + const eyeIcon = within(tooltip).getByTestId('hide-token') + expect(eyeIcon).toBeInTheDocument() + + await user.click(eyeIcon) + + const eyeOnIcon = within(tooltip).getByTestId('show-token') + expect(eyeOnIcon).toBeInTheDocument() + }) + + it('renders endcoded token on eye icon click', async () => { + const { user } = setup() + render(, { wrapper: wrapper() }) + + await waitFor(() => screen.findByTestId(/token-trigger/)) + const trigger = screen.getByTestId(/token-trigger/) + await user.hover(trigger) + + const tooltip = await screen.findByRole('tooltip') + const eyeIcon = within(tooltip).getByTestId('hide-token') + expect(eyeIcon).toBeInTheDocument() + + await user.click(eyeIcon) + + const encodedToken = await screen.findByText(/xxxx-xxxxx/, { + selector: '[role="tooltip"] div', + }) + expect(encodedToken).toBeInTheDocument() + }) + + it('renders copy token to clipboard', async () => { + const { user } = setup() + render(, { wrapper: wrapper() }) + + await waitFor(() => screen.findByTestId(/token-trigger/)) + const trigger = screen.getByTestId(/token-trigger/) + await user.hover(trigger) + + const tooltip = await screen.findByRole('tooltip') + const copyButton = within(tooltip).getByTestId('clipboard-copy-token') + expect(copyButton).toBeInTheDocument() + }) + }) +}) diff --git a/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.tsx b/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.tsx new file mode 100644 index 0000000000..7ef628b2ee --- /dev/null +++ b/src/shared/GlobalTopBanners/TokenlessBanner/TokenlessBanner.tsx @@ -0,0 +1,159 @@ +import { useState } from 'react' +import { useParams } from 'react-router' + +import { useOrgUploadToken } from 'services/orgUploadToken' +import { useOwner } from 'services/user' +import { useFlags } from 'shared/featureFlags' +import A from 'ui/A' +import Button from 'ui/Button' +import { CopyClipboard } from 'ui/CopyClipboard' +import Icon from 'ui/Icon' +import { Tooltip } from 'ui/Tooltip' +import TopBanner from 'ui/TopBanner' + +interface UseParams { + owner: string +} + +interface UseOrgUploadTokenParams { + provider: string + owner: string +} + +function OrgUploadTokenTooltip({ orgUploadToken }: { orgUploadToken: string }) { + const [isTokenVisible, setIsTokenVisible] = useState(true) + const encodedToken = orgUploadToken.replace(/\w|[^-]/g, 'x') + const formattedToken = isTokenVisible ? orgUploadToken : encodedToken + + return ( + + + + the token. + + + +
+ {formattedToken} +
+ + +
+
+ +
+
+
+
+ ) +} + +function AdminTokenlessBanner() { + const { provider, owner } = useParams() + const { data: orgUploadToken } = useOrgUploadToken({ + provider, + owner, + }) + + return ( + + +

+ + + Uploading with the token is now required. + + You must upload with{' '} + {typeof orgUploadToken === 'string' ? ( + + ) : ( + 'the token. ' + )} + Admins can manage the + + global upload token settings. + +

+
+ + Dismiss + +
+ ) +} + +function MemberTokenlessBanner() { + const { provider, owner } = useParams() + const { data: orgUploadToken } = useOrgUploadToken({ + provider, + owner, + }) + + return ( + + +

+ + + Uploading with the token is now required. + + You must upload with + {typeof orgUploadToken === 'string' ? ( + + ) : ( + 'the token. ' + )} + Contact your admins to manage the upload token settings. +

+
+ + Dismiss + +
+ ) +} + +function TokenlessBanner() { + const { tokenlessSection } = useFlags({ + tokenlessSection: false, + }) + const { owner } = useParams() + + const { data } = useOwner({ + username: owner, + opts: { enabled: !!owner }, + }) + + if (!owner || !tokenlessSection) return null // TODO: check for token if required for owner + + return !!data?.isAdmin ? : +} + +export default TokenlessBanner diff --git a/src/shared/GlobalTopBanners/TokenlessBanner/index.ts b/src/shared/GlobalTopBanners/TokenlessBanner/index.ts new file mode 100644 index 0000000000..acc5773d33 --- /dev/null +++ b/src/shared/GlobalTopBanners/TokenlessBanner/index.ts @@ -0,0 +1 @@ +export { default } from './TokenlessBanner' diff --git a/src/ui/Button/Button.jsx b/src/ui/Button/Button.jsx index 59f04a6cda..a5368d0ad2 100644 --- a/src/ui/Button/Button.jsx +++ b/src/ui/Button/Button.jsx @@ -51,6 +51,7 @@ const variantClasses = { text-ds-gray-quaternary hover:text-ds-gray-octonary + focus:ring-0 `, listbox: ` justify-start From ac3911268e1571b9b0e1afe8e8d3f537cee0cf7f Mon Sep 17 00:00:00 2001 From: ajay-sentry <159853603+ajay-sentry@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:02:20 -0700 Subject: [PATCH 13/20] chore: Update sentry version (#3337) --- package.json | 2 +- yarn.lock | 130 +++++++++++++++++++++++++-------------------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/package.json b/package.json index 4e2018afac..eecf2c66ab 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@radix-ui/react-popover": "^1.0.6", "@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.2", - "@sentry/react": "^8.24.0", + "@sentry/react": "^8.32.0", "@stripe/react-stripe-js": "^2.7.1", "@stripe/stripe-js": "^3.4.0", "@tanstack/react-query": "^4.29.5", diff --git a/yarn.lock b/yarn.lock index adf6083c4a..77783671aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4417,49 +4417,49 @@ __metadata: languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry-internal/browser-utils@npm:8.24.0" +"@sentry-internal/browser-utils@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry-internal/browser-utils@npm:8.32.0" dependencies: - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/e0b974a82e9b73361ab0e0f049004ccd2609ec0d9b5325cc1fa475c2ea236ec6c59eae6950660a973b8f6efd716ce9534d69c67193e19f94f7d67825b822a8aa + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/accaf5af1c44761e1bcceedd4b91c1707fcc082081378c987a2b375407d175c9542d255bb29613d87bc3b288be2d967ff2d690193f610bec79bbcc708b51b911 languageName: node linkType: hard -"@sentry-internal/feedback@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry-internal/feedback@npm:8.24.0" +"@sentry-internal/feedback@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry-internal/feedback@npm:8.32.0" dependencies: - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/8ad68ba0002d16871c9d3dc6d6dbd8eb9270a43cf187584b1810bfbb849b4380a1edb4e3a8d5b7521848b99911bf8399dae8964dbc1848a5407b2b147bc1fa4c + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/8b2191230d8bb2ff42696ef4e1266e76c70966b0cd74802cc754623c970a5c7b03458fa4ef0a758435236061a61566c4ff1e65a06afdb173887948278eb6f383 languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry-internal/replay-canvas@npm:8.24.0" +"@sentry-internal/replay-canvas@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry-internal/replay-canvas@npm:8.32.0" dependencies: - "@sentry-internal/replay": "npm:8.24.0" - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/579bf4cfe03ccdf562977196b547e2ba5f91fa9942dd3f7278daca978fb85bb036fa61671ae774643e173da65ac18ee1ffe617ed9417ea80635afba2b5c472b0 + "@sentry-internal/replay": "npm:8.32.0" + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/2974fa21fcd8947c7cedb265419273eec9bf31b331c0309c4eccdc43563882b6f098e93481e21908fea5d712138a6115aff93bf900f4a27c3f4b512c880a4964 languageName: node linkType: hard -"@sentry-internal/replay@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry-internal/replay@npm:8.24.0" +"@sentry-internal/replay@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry-internal/replay@npm:8.32.0" dependencies: - "@sentry-internal/browser-utils": "npm:8.24.0" - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/109854d434b3867bbe0d4b51886009ed213e8af3790ebd702ceb04a0be5b7542cdb8d0e1fca1c231f7fb50fd16799b4ee6150e18b9a64e3ed7d1c4dd2964a716 + "@sentry-internal/browser-utils": "npm:8.32.0" + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/2278920e42b939588ce2d4b70c1a14f85ab3e03ba3e141acd89060df02c5794c560b132cad0d47f8d1a3ac2e62e6b14a7d7deacc4d5c038ac2851cc7b2346849 languageName: node linkType: hard @@ -4477,18 +4477,18 @@ __metadata: languageName: node linkType: hard -"@sentry/browser@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry/browser@npm:8.24.0" +"@sentry/browser@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry/browser@npm:8.32.0" dependencies: - "@sentry-internal/browser-utils": "npm:8.24.0" - "@sentry-internal/feedback": "npm:8.24.0" - "@sentry-internal/replay": "npm:8.24.0" - "@sentry-internal/replay-canvas": "npm:8.24.0" - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/99ab8b4840b49aa9909484b848d6c5027484b9738a8722375118d3b3f2a6eda6eafe113a7fc37189fed0a49c8dde8ce12db5ba15db6fc25b2a1c566165434091 + "@sentry-internal/browser-utils": "npm:8.32.0" + "@sentry-internal/feedback": "npm:8.32.0" + "@sentry-internal/replay": "npm:8.32.0" + "@sentry-internal/replay-canvas": "npm:8.32.0" + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/21990eb0857dd77ab76ea162dbf532af611ff8b16a6ae7dd9d51ecb31092a0a6d385bcb237d727f5ca7f913a9763f1ca83cbf3b0f224f7e518cb6a053e9a46af languageName: node linkType: hard @@ -4610,44 +4610,44 @@ __metadata: languageName: node linkType: hard -"@sentry/core@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry/core@npm:8.24.0" +"@sentry/core@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry/core@npm:8.32.0" dependencies: - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" - checksum: 10c0/a0b4146c2b37976e4a29ef708efad856fb497497a973fe954d4c09903507315e372d67c31bb1279a1882af8f3c9025f11dceef8886770b211e58c81de7fdb86f + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" + checksum: 10c0/11de3a4810c9f33548577356afda93081daf925663dd01c89778f82f5e74a7c46dc4b84f2983291c91ba8d040b01ad0b881b627ddcff2fc5e5354dfe66ff0cdb languageName: node linkType: hard -"@sentry/react@npm:^8.24.0": - version: 8.24.0 - resolution: "@sentry/react@npm:8.24.0" +"@sentry/react@npm:^8.32.0": + version: 8.32.0 + resolution: "@sentry/react@npm:8.32.0" dependencies: - "@sentry/browser": "npm:8.24.0" - "@sentry/core": "npm:8.24.0" - "@sentry/types": "npm:8.24.0" - "@sentry/utils": "npm:8.24.0" + "@sentry/browser": "npm:8.32.0" + "@sentry/core": "npm:8.32.0" + "@sentry/types": "npm:8.32.0" + "@sentry/utils": "npm:8.32.0" hoist-non-react-statics: "npm:^3.3.2" peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - checksum: 10c0/6d304a4cf08cdeccf85c7c420a11516da8e37fe57906ffd3327c88080d4ea8db0dc21d1b48b973fdb44f9d61aeedc230d37cefdaf8b95f93cd51f82e5f24f3ee + checksum: 10c0/7e4a1e7693a12bb2b85fce59f5665bd276f15adfe543f144b7f5fc54c73a6046e7069427c3b00530042e9d4f385de9e53524be0b18fa92456a133cd89245de51 languageName: node linkType: hard -"@sentry/types@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry/types@npm:8.24.0" - checksum: 10c0/3a9713ad71f240ef707245a460a01d821d9f0308bc215ca967d0427b6b86d24d22ffc48235f81c059aa835e40b0969eef5568f6e03ffaeff4b6c608156b70acb +"@sentry/types@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry/types@npm:8.32.0" + checksum: 10c0/386f5c8fa126c5ce8adf7740b1203b9833a78dcc23ebbe43a5e48a76093779596d35c4e58564d32b3a358a81e696f31706c870fa7ce43d3616018bb6b25c872a languageName: node linkType: hard -"@sentry/utils@npm:8.24.0": - version: 8.24.0 - resolution: "@sentry/utils@npm:8.24.0" +"@sentry/utils@npm:8.32.0": + version: 8.32.0 + resolution: "@sentry/utils@npm:8.32.0" dependencies: - "@sentry/types": "npm:8.24.0" - checksum: 10c0/5a9da3c5fbfac886a365fc48d467954a63c0d15bd049cc2a61d24d0146c8f6e8c88f1e57e2666384d834b440d6cc4abdc986d3dda57f7418a310e2032bdbecdc + "@sentry/types": "npm:8.32.0" + checksum: 10c0/cfff34eaa411dd913861d1734f02111aaebbf8d7078a0e1931a3c3ed06f332abbcbe4ec0022505c625ee296b28692f4ae5cee1c66d592ddf87fd798784d5382a languageName: node linkType: hard @@ -11737,7 +11737,7 @@ __metadata: "@radix-ui/react-popover": "npm:^1.0.6" "@radix-ui/react-radio-group": "npm:^1.1.3" "@radix-ui/react-tooltip": "npm:^1.1.2" - "@sentry/react": "npm:^8.24.0" + "@sentry/react": "npm:^8.32.0" "@sentry/vite-plugin": "npm:^2.22.4" "@sentry/webpack-plugin": "npm:^2.22.2" "@storybook/addon-a11y": "npm:^8.2.6" From 280795b1803fc2adb397b9f6b2dafb6b53641c11 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Mon, 30 Sep 2024 10:56:36 -0700 Subject: [PATCH 14/20] chore: Resolve vulnerability vite (#3336) --- yarn.lock | 56 +------------------------------------------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/yarn.lock b/yarn.lock index 77783671aa..403cc0f64c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17535,17 +17535,6 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.41": - version: 8.4.41 - resolution: "postcss@npm:8.4.41" - dependencies: - nanoid: "npm:^3.3.7" - picocolors: "npm:^1.0.1" - source-map-js: "npm:^1.2.0" - checksum: 10c0/c1828fc59e7ec1a3bf52b3a42f615dba53c67960ed82a81df6441b485fe43c20aba7f4e7c55425762fd99c594ecabbaaba8cf5b30fd79dfec5b52a9f63a2d690 - languageName: node - linkType: hard - "postcss@npm:^8.4.43": version: 8.4.47 resolution: "postcss@npm:8.4.47" @@ -21948,50 +21937,7 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.0.0": - version: 5.4.2 - resolution: "vite@npm:5.4.2" - dependencies: - esbuild: "npm:^0.21.3" - fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.41" - rollup: "npm:^4.20.0" - peerDependencies: - "@types/node": ^18.0.0 || >=20.0.0 - less: "*" - lightningcss: ^1.21.0 - sass: "*" - sass-embedded: "*" - stylus: "*" - sugarss: "*" - terser: ^5.4.0 - dependenciesMeta: - fsevents: - optional: true - peerDependenciesMeta: - "@types/node": - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - bin: - vite: bin/vite.js - checksum: 10c0/23e347ca8aa6f0a774227e4eb7abae228f12c6806a727b046aa75e7ee37ffc2d68cff74360e12a42c347f79adc294e2363bc723b957bf4b382b5a8fb39e4df9d - languageName: node - linkType: hard - -"vite@npm:^5.4.8": +"vite@npm:^5.0.0, vite@npm:^5.4.8": version: 5.4.8 resolution: "vite@npm:5.4.8" dependencies: From d3c5b23a25cd811838456cd0ab17253d4dd5b17c Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Mon, 30 Sep 2024 13:53:11 -0700 Subject: [PATCH 15/20] chore: Resolve vulnerabilities - express, path-to-regexp (#3338) --- package.json | 5 ++- yarn.lock | 112 +++++++++++++++++++++++++-------------------------- 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index eecf2c66ab..d249ec9d18 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,10 @@ "resolutions": { "react-refresh": "^0.14.0", "resolve-url-loader/postcss": "8.4.31", - "micromatch": "^4.0.8" + "micromatch": "^4.0.8", + "express": "^4.21.0", + "path-to-regexp@^1.7.0": "^1.9.0", + "path-to-regexp@^6.2.0": "^6.3.0" }, "packageManager": "yarn@4.5.0", "engineStrict": false diff --git a/yarn.lock b/yarn.lock index 403cc0f64c..d8b9f203c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8081,9 +8081,9 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.2": - version: 1.20.2 - resolution: "body-parser@npm:1.20.2" +"body-parser@npm:1.20.3": + version: 1.20.3 + resolution: "body-parser@npm:1.20.3" dependencies: bytes: "npm:3.1.2" content-type: "npm:~1.0.5" @@ -8093,11 +8093,11 @@ __metadata: http-errors: "npm:2.0.0" iconv-lite: "npm:0.4.24" on-finished: "npm:2.4.1" - qs: "npm:6.11.0" + qs: "npm:6.13.0" raw-body: "npm:2.5.2" type-is: "npm:~1.6.18" unpipe: "npm:1.0.0" - checksum: 10c0/06f1438fff388a2e2354c96aa3ea8147b79bfcb1262dfcc2aae68ec13723d01d5781680657b74e9f83c808266d5baf52804032fbde2b7382b89bd8cdb273ace9 + checksum: 10c0/0a9a93b7518f222885498dcecaad528cf010dd109b071bf471c93def4bfe30958b83e03496eb9c1ad4896db543d999bb62be1a3087294162a88cfa1b42c16310 languageName: node linkType: hard @@ -10182,6 +10182,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:~2.0.0": + version: 2.0.0 + resolution: "encodeurl@npm:2.0.0" + checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -11132,42 +11139,42 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.17.3, express@npm:^4.19.2": - version: 4.19.2 - resolution: "express@npm:4.19.2" +"express@npm:^4.21.0": + version: 4.21.0 + resolution: "express@npm:4.21.0" dependencies: accepts: "npm:~1.3.8" array-flatten: "npm:1.1.1" - body-parser: "npm:1.20.2" + body-parser: "npm:1.20.3" content-disposition: "npm:0.5.4" content-type: "npm:~1.0.4" cookie: "npm:0.6.0" cookie-signature: "npm:1.0.6" debug: "npm:2.6.9" depd: "npm:2.0.0" - encodeurl: "npm:~1.0.2" + encodeurl: "npm:~2.0.0" escape-html: "npm:~1.0.3" etag: "npm:~1.8.1" - finalhandler: "npm:1.2.0" + finalhandler: "npm:1.3.1" fresh: "npm:0.5.2" http-errors: "npm:2.0.0" - merge-descriptors: "npm:1.0.1" + merge-descriptors: "npm:1.0.3" methods: "npm:~1.1.2" on-finished: "npm:2.4.1" parseurl: "npm:~1.3.3" - path-to-regexp: "npm:0.1.7" + path-to-regexp: "npm:0.1.10" proxy-addr: "npm:~2.0.7" - qs: "npm:6.11.0" + qs: "npm:6.13.0" range-parser: "npm:~1.2.1" safe-buffer: "npm:5.2.1" - send: "npm:0.18.0" - serve-static: "npm:1.15.0" + send: "npm:0.19.0" + serve-static: "npm:1.16.2" setprototypeof: "npm:1.2.0" statuses: "npm:2.0.1" type-is: "npm:~1.6.18" utils-merge: "npm:1.0.1" vary: "npm:~1.1.2" - checksum: 10c0/e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb + checksum: 10c0/4cf7ca328f3fdeb720f30ccb2ea7708bfa7d345f9cc460b64a82bf1b2c91e5b5852ba15a9a11b2a165d6089acf83457fc477dc904d59cd71ed34c7a91762c6cc languageName: node linkType: hard @@ -11382,18 +11389,18 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" +"finalhandler@npm:1.3.1": + version: 1.3.1 + resolution: "finalhandler@npm:1.3.1" dependencies: debug: "npm:2.6.9" - encodeurl: "npm:~1.0.2" + encodeurl: "npm:~2.0.0" escape-html: "npm:~1.0.3" on-finished: "npm:2.4.1" parseurl: "npm:~1.3.3" statuses: "npm:2.0.1" unpipe: "npm:~1.0.0" - checksum: 10c0/64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7 + checksum: 10c0/d38035831865a49b5610206a3a9a9aae4e8523cbbcd01175d0480ffbf1278c47f11d89be3ca7f617ae6d94f29cf797546a4619cd84dd109009ef33f12f69019f languageName: node linkType: hard @@ -15051,10 +15058,10 @@ __metadata: languageName: node linkType: hard -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 10c0/b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec +"merge-descriptors@npm:1.0.3": + version: 1.0.3 + resolution: "merge-descriptors@npm:1.0.3" + checksum: 10c0/866b7094afd9293b5ea5dcd82d71f80e51514bed33b4c4e9f516795dc366612a4cbb4dc94356e943a8a6914889a914530badff27f397191b9b75cda20b6bae93 languageName: node linkType: hard @@ -16500,26 +16507,19 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 10c0/50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905 +"path-to-regexp@npm:0.1.10": + version: 0.1.10 + resolution: "path-to-regexp@npm:0.1.10" + checksum: 10c0/34196775b9113ca6df88e94c8d83ba82c0e1a2063dd33bfe2803a980da8d49b91db8104f49d5191b44ea780d46b8670ce2b7f4a5e349b0c48c6779b653f1afe4 languageName: node linkType: hard -"path-to-regexp@npm:^1.7.0": - version: 1.8.0 - resolution: "path-to-regexp@npm:1.8.0" +"path-to-regexp@npm:^1.9.0": + version: 1.9.0 + resolution: "path-to-regexp@npm:1.9.0" dependencies: isarray: "npm:0.0.1" - checksum: 10c0/7b25d6f27a8de03f49406d16195450f5ced694398adea1510b0f949d9660600d1769c5c6c83668583b7e6b503f3caf1ede8ffc08135dbe3e982f034f356fbb5c - languageName: node - linkType: hard - -"path-to-regexp@npm:^6.2.0": - version: 6.2.2 - resolution: "path-to-regexp@npm:6.2.2" - checksum: 10c0/4b60852d3501fd05ca9dd08c70033d73844e5eca14e41f499f069afa8364f780f15c5098002f93bd42af8b3514de62ac6e82a53b5662de881d2b08c9ef21ea6b + checksum: 10c0/de9ddb01b84d9c2c8e2bed18630d8d039e2d6f60a6538595750fa08c7a6482512257464c8da50616f266ab2cdd2428387e85f3b089e4c3f25d0c537e898a0751 languageName: node linkType: hard @@ -17756,12 +17756,12 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" +"qs@npm:6.13.0": + version: 6.13.0 + resolution: "qs@npm:6.13.0" dependencies: - side-channel: "npm:^1.0.4" - checksum: 10c0/4e4875e4d7c7c31c233d07a448e7e4650f456178b9dd3766b7cfa13158fdb24ecb8c4f059fa91e820dc6ab9f2d243721d071c9c0378892dcdad86e9e9a27c68f + side-channel: "npm:^1.0.6" + checksum: 10c0/62372cdeec24dc83a9fb240b7533c0fdcf0c5f7e0b83343edd7310f0ab4c8205a5e7c56406531f2e47e1b4878a3821d652be4192c841de5b032ca83619d8f860 languageName: node linkType: hard @@ -19212,9 +19212,9 @@ __metadata: languageName: node linkType: hard -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" +"send@npm:0.19.0": + version: 0.19.0 + resolution: "send@npm:0.19.0" dependencies: debug: "npm:2.6.9" depd: "npm:2.0.0" @@ -19229,7 +19229,7 @@ __metadata: on-finished: "npm:2.4.1" range-parser: "npm:~1.2.1" statuses: "npm:2.0.1" - checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a + checksum: 10c0/ea3f8a67a8f0be3d6bf9080f0baed6d2c51d11d4f7b4470de96a5029c598a7011c497511ccc28968b70ef05508675cebff27da9151dd2ceadd60be4e6cf845e3 languageName: node linkType: hard @@ -19266,15 +19266,15 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" +"serve-static@npm:1.16.2": + version: 1.16.2 + resolution: "serve-static@npm:1.16.2" dependencies: - encodeurl: "npm:~1.0.2" + encodeurl: "npm:~2.0.0" escape-html: "npm:~1.0.3" parseurl: "npm:~1.3.3" - send: "npm:0.18.0" - checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba + send: "npm:0.19.0" + checksum: 10c0/528fff6f5e12d0c5a391229ad893910709bc51b5705962b09404a1d813857578149b8815f35d3ee5752f44cd378d0f31669d4b1d7e2d11f41e08283d5134bd1f languageName: node linkType: hard From 51d074b4405bce09fb58ea751e32158b4f36dfd4 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 06:48:29 -0400 Subject: [PATCH 16/20] chore: Update pages/RepoPage/PullsTab tests to Vitest (#3334) --- .../{PullsTab.spec.tsx => PullsTab.test.tsx} | 2 +- src/pages/RepoPage/PullsTab/PullsTab.tsx | 29 ++++++++------ ...ullsTable.spec.tsx => PullsTable.test.tsx} | 39 +++++++++---------- .../Title/{Title.spec.tsx => Title.test.tsx} | 0 ...spec.tsx => createPullsTableData.test.tsx} | 0 .../RepoPage/PullsTab/{enums.js => enums.ts} | 15 ++++--- .../RepoPage/PullsTab/{index.js => index.ts} | 0 7 files changed, 46 insertions(+), 39 deletions(-) rename src/pages/RepoPage/PullsTab/{PullsTab.spec.tsx => PullsTab.test.tsx} (98%) rename src/pages/RepoPage/PullsTab/PullsTable/{PullsTable.spec.tsx => PullsTable.test.tsx} (92%) rename src/pages/RepoPage/PullsTab/PullsTable/Title/{Title.spec.tsx => Title.test.tsx} (100%) rename src/pages/RepoPage/PullsTab/PullsTable/{createPullsTableData.spec.tsx => createPullsTableData.test.tsx} (100%) rename src/pages/RepoPage/PullsTab/{enums.js => enums.ts} (80%) rename src/pages/RepoPage/PullsTab/{index.js => index.ts} (100%) diff --git a/src/pages/RepoPage/PullsTab/PullsTab.spec.tsx b/src/pages/RepoPage/PullsTab/PullsTab.test.tsx similarity index 98% rename from src/pages/RepoPage/PullsTab/PullsTab.spec.tsx rename to src/pages/RepoPage/PullsTab/PullsTab.test.tsx index 2a6d7dfb0e..9de98fa0e1 100644 --- a/src/pages/RepoPage/PullsTab/PullsTab.spec.tsx +++ b/src/pages/RepoPage/PullsTab/PullsTab.test.tsx @@ -4,7 +4,7 @@ import PullsTab from './PullsTab' import { repoPageRender, screen } from '../repo-jest-setup' -jest.mock('./PullsTable', () => () => 'PullsTable') +vi.mock('./PullsTable', () => ({ default: () => 'PullsTable' })) describe('Pulls Tab', () => { function setup() { diff --git a/src/pages/RepoPage/PullsTab/PullsTab.tsx b/src/pages/RepoPage/PullsTab/PullsTab.tsx index e116e356ea..e8108ba3c0 100644 --- a/src/pages/RepoPage/PullsTab/PullsTab.tsx +++ b/src/pages/RepoPage/PullsTab/PullsTab.tsx @@ -25,8 +25,10 @@ const Loader = () => ( ) type Order = keyof typeof orderNames -type SelectedStatesNames = Array -type SelectedStatesEnum = Array +type SelectedStatesNames = Array<(typeof stateNames)[keyof typeof stateNames]> +type SelectedStatesEnum = Array< + (typeof stateEnum)[keyof typeof stateEnum]['state'] +> const defaultParams = { order: orderingEnum.Newest.order, @@ -37,7 +39,7 @@ function useControlParams() { const { params, updateParams } = useLocationParams(defaultParams) const { order, prStates } = params as { order: Order - prStates: SelectedStatesNames + prStates: SelectedStatesEnum } const paramOrderName = orderNames[order] @@ -47,7 +49,8 @@ function useControlParams() { }) const [selectedOrder, setSelectedOrder] = useState(paramOrderName) - const [selectedStates, setSelectedStates] = useState(paramStatesNames) + const [selectedStates, setSelectedStates] = + useState(paramStatesNames) return { updateParams, @@ -83,13 +86,17 @@ function PullsTab() { ) const handleStatesChange = useCallback( - (selectedStates: SelectedStatesEnum) => { - const prStates = selectedStates.map((filter) => { - const { state } = stateEnum[filter] - return state - }) - setSelectedStates(prStates) - updateParams({ prStates }) + (selectedStates: SelectedStatesNames) => { + const states: SelectedStatesEnum = [] + const names: SelectedStatesNames = [] + + for (const filter of selectedStates) { + states.push(stateEnum[filter].state) + names.push(stateEnum[filter].name) + } + + setSelectedStates(names) + updateParams({ prStates: states }) }, [setSelectedStates, updateParams] ) diff --git a/src/pages/RepoPage/PullsTab/PullsTable/PullsTable.spec.tsx b/src/pages/RepoPage/PullsTab/PullsTable/PullsTable.test.tsx similarity index 92% rename from src/pages/RepoPage/PullsTab/PullsTable/PullsTable.spec.tsx rename to src/pages/RepoPage/PullsTab/PullsTable/PullsTable.test.tsx index a70573a720..bf8e4355b0 100644 --- a/src/pages/RepoPage/PullsTab/PullsTable/PullsTable.spec.tsx +++ b/src/pages/RepoPage/PullsTab/PullsTable/PullsTable.test.tsx @@ -4,8 +4,8 @@ import { screen, waitForElementToBeRemoved, } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { mockIsIntersecting } from 'react-intersection-observer/test-utils' import { MemoryRouter, Route } from 'react-router-dom' @@ -138,17 +138,15 @@ describe('PullsTable', () => { const queryClient = new QueryClient() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepoOverview(bundleAnalysisEnabled)) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview(bundleAnalysisEnabled), + }) }), - graphql.query('GetPulls', (req, res, ctx) => { + graphql.query('GetPulls', (info) => { if (noEntries) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -161,18 +159,17 @@ describe('PullsTable', () => { }, }, }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', pulls: { - edges: req.variables.after + edges: info.variables.after ? [ { node: node3, @@ -187,16 +184,16 @@ describe('PullsTable', () => { }, ], pageInfo: { - hasNextPage: req.variables.after ? false : true, - endCursor: req.variables.after + hasNextPage: info.variables.after ? false : true, + endCursor: info.variables.after ? 'aa' : 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=', }, }, }, }, - }) - ) + }, + }) }) ) diff --git a/src/pages/RepoPage/PullsTab/PullsTable/Title/Title.spec.tsx b/src/pages/RepoPage/PullsTab/PullsTable/Title/Title.test.tsx similarity index 100% rename from src/pages/RepoPage/PullsTab/PullsTable/Title/Title.spec.tsx rename to src/pages/RepoPage/PullsTab/PullsTable/Title/Title.test.tsx diff --git a/src/pages/RepoPage/PullsTab/PullsTable/createPullsTableData.spec.tsx b/src/pages/RepoPage/PullsTab/PullsTable/createPullsTableData.test.tsx similarity index 100% rename from src/pages/RepoPage/PullsTab/PullsTable/createPullsTableData.spec.tsx rename to src/pages/RepoPage/PullsTab/PullsTable/createPullsTableData.test.tsx diff --git a/src/pages/RepoPage/PullsTab/enums.js b/src/pages/RepoPage/PullsTab/enums.ts similarity index 80% rename from src/pages/RepoPage/PullsTab/enums.js rename to src/pages/RepoPage/PullsTab/enums.ts index 96a9317d6d..7d8a36d34e 100644 --- a/src/pages/RepoPage/PullsTab/enums.js +++ b/src/pages/RepoPage/PullsTab/enums.ts @@ -2,28 +2,31 @@ export const stateEnum = { Merged: { state: 'MERGED', name: 'Merged' }, Closed: { state: 'CLOSED', name: 'Closed' }, Open: { state: 'OPEN', name: 'Open' }, -} +} as const export const orderingEnum = { Oldest: { order: 'ASC', name: 'Oldest' }, Newest: { order: 'DESC', name: 'Newest' }, -} +} as const export const filterItems = [ stateEnum.Open.name, stateEnum.Merged.name, stateEnum.Closed.name, -] +] as const -export const orderItems = [orderingEnum.Newest.name, orderingEnum.Oldest.name] +export const orderItems = [ + orderingEnum.Newest.name, + orderingEnum.Oldest.name, +] as const export const orderNames = { ASC: orderingEnum.Oldest.name, DESC: orderingEnum.Newest.name, -} +} as const export const stateNames = { MERGED: stateEnum.Merged.name, CLOSED: stateEnum.Closed.name, OPEN: stateEnum.Open.name, -} +} as const diff --git a/src/pages/RepoPage/PullsTab/index.js b/src/pages/RepoPage/PullsTab/index.ts similarity index 100% rename from src/pages/RepoPage/PullsTab/index.js rename to src/pages/RepoPage/PullsTab/index.ts From 5eeab639d1134e3577d163f26052068dd0f56348 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 08:21:09 -0400 Subject: [PATCH 17/20] chore: Update services/pull tests to Vitest (#3304) --- src/services/pull/hooks.spec.js | 728 ------------------ src/services/pull/{index.js => index.ts} | 0 ...tsx => usePrefetchSingleFileComp.test.tsx} | 30 +- src/services/pull/usePull.test.tsx | 394 ++++++++++ src/services/pull/usePull.tsx | 2 +- ....tsx => usePullBADropdownSummary.test.tsx} | 38 +- ...x => usePullBundleComparisonList.test.tsx} | 38 +- ...pec.tsx => usePullBundleHeadList.test.tsx} | 43 +- ....tsx => usePullCompareTotalsTeam.test.tsx} | 32 +- ...ts.spec.tsx => usePullComponents.test.tsx} | 36 +- ...> usePullCoverageDropdownSummary.test.tsx} | 38 +- ...PullTeam.spec.tsx => usePullTeam.test.tsx} | 47 +- ...seSingularImpactedFileComparison.test.tsx} | 16 +- .../pull/utils/{index.js => index.ts} | 0 src/services/pull/utils/setFileLabel.js | 6 - ...FileLabel.spec.js => setFileLabel.test.ts} | 0 src/services/pull/utils/setFileLabel.ts | 16 + ...c.js => transformImpactedFileData.test.js} | 0 18 files changed, 569 insertions(+), 895 deletions(-) delete mode 100644 src/services/pull/hooks.spec.js rename src/services/pull/{index.js => index.ts} (100%) rename src/services/pull/{usePrefetchSingleFileComp.spec.tsx => usePrefetchSingleFileComp.test.tsx} (93%) create mode 100644 src/services/pull/usePull.test.tsx rename src/services/pull/{usePullBADropdownSummary.spec.tsx => usePullBADropdownSummary.test.tsx} (85%) rename src/services/pull/{usePullBundleComparisonList.spec.tsx => usePullBundleComparisonList.test.tsx} (88%) rename src/services/pull/{usePullBundleHeadList.spec.tsx => usePullBundleHeadList.test.tsx} (85%) rename src/services/pull/{usePullCompareTotalsTeam.spec.tsx => usePullCompareTotalsTeam.test.tsx} (86%) rename src/services/pull/{usePullComponents.spec.tsx => usePullComponents.test.tsx} (83%) rename src/services/pull/{usePullCoverageDropdownSummary.spec.tsx => usePullCoverageDropdownSummary.test.tsx} (84%) rename src/services/pull/{usePullTeam.spec.tsx => usePullTeam.test.tsx} (86%) rename src/services/pull/{useSingularImpactedFileComparison.spec.tsx => useSingularImpactedFileComparison.test.tsx} (93%) rename src/services/pull/utils/{index.js => index.ts} (100%) delete mode 100644 src/services/pull/utils/setFileLabel.js rename src/services/pull/utils/{setFileLabel.spec.js => setFileLabel.test.ts} (100%) create mode 100644 src/services/pull/utils/setFileLabel.ts rename src/services/pull/utils/{transformImpactedFileData.spec.js => transformImpactedFileData.test.js} (100%) diff --git a/src/services/pull/hooks.spec.js b/src/services/pull/hooks.spec.js deleted file mode 100644 index 814faace84..0000000000 --- a/src/services/pull/hooks.spec.js +++ /dev/null @@ -1,728 +0,0 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' - -import { usePull, useSingularImpactedFileComparison } from './index' - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: false, - }, - }, -}) - -const wrapper = ({ children }) => ( - {children} -) - -const server = setupServer() - -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) - -const mockImpactedFiles = [ - { - isCriticalFile: true, - missesCount: 3, - fileName: 'mafs.js', - headName: 'flag1/mafs.js', - baseCoverage: { - percentCovered: 45.38, - }, - headCoverage: { - percentCovered: 90.23, - }, - patchCoverage: { - percentCovered: 27.43, - }, - changeCoverage: 41, - }, -] - -const pull = { - owner: { - isCurrentUserPartOfOrg: true, - repository: { - __typename: 'Repository', - defaultBranch: 'main', - private: false, - pull: { - commits: { - edges: [ - { - node: { - state: 'complete', - commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', - message: - 'create component to hold bundle list table for a given pull 2', - author: { - username: 'nicholas-codecov', - }, - }, - }, - ], - }, - compareWithBase: { - state: 'complete', - __typename: 'Comparison', - flagComparisons: [], - patchTotals: { - percentCovered: 92.12, - }, - baseTotals: { - percentCovered: 98.25, - }, - headTotals: { - percentCovered: 78.33, - }, - impactedFiles: { - __typename: 'ImpactedFiles', - results: mockImpactedFiles, - }, - changeCoverage: 38.94, - hasDifferentNumberOfHeadAndBaseReports: true, - }, - pullId: 2510, - title: 'feat: Create bundle analysis table for a given pull', - state: 'OPEN', - author: { - username: 'nicholas-codecov', - }, - head: { - ciPassed: true, - branchName: - 'gh-eng-994-create-bundle-analysis-table-for-a-given-pull', - state: 'complete', - commitid: 'fc43199b07c52cf3d6c19b7cdb368f74387c38ab', - totals: { - percentCovered: 78.33, - }, - uploads: { - totalCount: 4, - edges: [], - }, - }, - updatestamp: '2024-01-12T12:56:18.912860', - behindBy: 82367894, - behindByCommit: '1798hvs8ofhn', - comparedTo: { - commitid: '2d6c42fe217c61b007b2c17544a9d85840381857', - uploads: { - totalCount: 1, - edges: [], - }, - }, - }, - }, - }, -} - -const provider = 'gh' -const owner = 'codecov' -const repo = 'gazebo' - -describe('usePull', () => { - afterEach(() => queryClient.clear()) - - function setup(data) { - server.use( - graphql.query('Pull', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(data)) - }) - ) - } - - describe('when called', () => { - beforeEach(() => { - setup(pull) - }) - - describe('when data is loaded', () => { - it('returns the data', async () => { - const { result } = renderHook( - () => usePull({ provider, owner, repo }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => - expect(result.current.data).toEqual({ - defaultBranch: 'main', - hasAccess: true, - pull: { - behindBy: 82367894, - behindByCommit: '1798hvs8ofhn', - pullId: 2510, - title: 'feat: Create bundle analysis table for a given pull', - state: 'OPEN', - updatestamp: '2024-01-12T12:56:18.912860', - author: { username: 'nicholas-codecov' }, - comparedTo: { - commitid: '2d6c42fe217c61b007b2c17544a9d85840381857', - uploads: { totalCount: 1, edges: [] }, - }, - head: { - state: 'complete', - ciPassed: true, - branchName: - 'gh-eng-994-create-bundle-analysis-table-for-a-given-pull', - commitid: 'fc43199b07c52cf3d6c19b7cdb368f74387c38ab', - totals: { percentCovered: 78.33 }, - uploads: { totalCount: 4, edges: [] }, - }, - commits: { - edges: [ - { - node: { - state: 'complete', - commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', - message: - 'create component to hold bundle list table for a given pull 2', - author: { username: 'nicholas-codecov' }, - }, - }, - ], - }, - compareWithBase: { - __typename: 'Comparison', - state: 'complete', - patchTotals: { percentCovered: 92.12 }, - baseTotals: { percentCovered: 98.25 }, - headTotals: { percentCovered: 78.33 }, - impactedFiles: { - __typename: 'ImpactedFiles', - results: [ - { - isCriticalFile: true, - missesCount: 3, - fileName: 'mafs.js', - headName: 'flag1/mafs.js', - baseCoverage: { percentCovered: 45.38 }, - headCoverage: { percentCovered: 90.23 }, - patchCoverage: { percentCovered: 27.43 }, - changeCoverage: 41, - }, - ], - }, - flagComparisons: [], - changeCoverage: 38.94, - hasDifferentNumberOfHeadAndBaseReports: true, - }, - }, - }) - ) - }) - }) - - describe('when it is of OwnerNotActivatedError type', () => { - it('returns the error', async () => { - setup({ - owner: { - isCurrentUserPartOfOrg: false, - repository: { - __typename: 'OwnerNotActivatedError', - message: 'owner not activated', - }, - }, - }) - - const { result } = renderHook( - () => usePull({ provider, owner, repo }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => expect(result.current.error.status).toEqual(403)) - }) - }) - - describe('when it is of NotFoundError type', () => { - it('returns the error', async () => { - setup({ - owner: { - isCurrentUserPartOfOrg: false, - repository: { - __typename: 'NotFoundError', - message: 'not found', - }, - }, - }) - - const { result } = renderHook( - () => usePull({ provider, owner, repo }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => expect(result.current.error.status).toEqual(404)) - }) - }) - - describe('when there is no pull returned', () => { - it('returns pull null', async () => { - setup({ - owner: { - isCurrentUserPartOfOrg: true, - repository: { - __typename: 'Repository', - defaultBranch: 'main', - private: false, - pull: null, - }, - }, - }) - - const { result } = renderHook( - () => usePull({ provider, owner, repo }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => expect(result.current.data.pull).toEqual(null)) - }) - }) - - describe('when schema is not valid', () => { - it('throws an error', async () => { - setup({ - owner: { - isCurrentUserPartOfOrg: true, - repository: { - __typename: 'Repository', - defaultBranch: 'main', - private: false, - pull: { - commits: { - edges: [ - { - node: { - state: 'complete', - commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', - message: - 'create component to hold bundle list table for a given pull 2', - }, - }, - ], - }, - }, - }, - }, - }) - - const { result } = renderHook( - () => usePull({ provider, owner, repo }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => expect(result.current.error.status).toEqual(404)) - }) - }) - }) -}) - -const mockSingularImpactedFilesData = { - headName: 'file A', - hashedPath: 'hashedFilePath', - isRenamedFile: false, - isDeletedFile: false, - isCriticalFile: false, - isNewFile: true, - headCoverage: { - percentCovered: 90.23, - }, - baseCoverage: { - percentCovered: 23.42, - }, - patchCoverage: { - percentCovered: 27.43, - }, - changeCoverage: 58.333333333333336, - segments: { - __typename: 'SegmentComparisons', - results: [ - { - header: '@@ -0,0 +1,45 @@', - hasUnintendedChanges: false, - lines: [ - { - baseNumber: null, - headNumber: '1', - baseCoverage: null, - headCoverage: 'H', - content: '+export default class Calculator {', - }, - { - baseNumber: null, - headNumber: '2', - baseCoverage: null, - headCoverage: 'H', - content: '+ private value = 0;', - }, - { - baseNumber: null, - headNumber: '3', - baseCoverage: null, - headCoverage: 'H', - content: '+ private calcMode = ""', - }, - ], - }, - ], - }, -} - -describe('useSingularImpactedFileComparison', () => { - afterEach(() => queryClient.clear()) - - function setup(data) { - server.use( - graphql.query('ImpactedFileComparison', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(data)) - }) - ) - } - - describe('when called', () => { - beforeEach(() => { - setup({ - owner: { - repository: { - __typename: 'Repository', - pull: { - compareWithBase: { - __typename: 'Comparison', - impactedFile: mockSingularImpactedFilesData, - }, - }, - }, - }, - }) - }) - - describe('when data is loaded', () => { - it('returns the data', async () => { - const { result } = renderHook( - () => - useSingularImpactedFileComparison({ - provider, - owner, - repo, - pullId: 10, - path: 'someFile.js', - }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => - expect(result.current.data).toEqual({ - fileLabel: 'New', - hashedPath: 'hashedFilePath', - headName: 'file A', - isCriticalFile: false, - segments: [ - { - hasUnintendedChanges: false, - header: '@@ -0,0 +1,45 @@', - lines: [ - { - baseCoverage: null, - baseNumber: null, - content: '+export default class Calculator {', - headCoverage: 'H', - headNumber: '1', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private value = 0;', - headCoverage: 'H', - headNumber: '2', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private calcMode = ""', - headCoverage: 'H', - headNumber: '3', - }, - ], - }, - ], - }) - ) - }) - }) - }) - - describe('when called with renamed file', () => { - beforeEach(() => { - setup({ - owner: { - repository: { - __typename: 'Repository', - pull: { - compareWithBase: { - __typename: 'Comparison', - impactedFile: { - ...mockSingularImpactedFilesData, - isRenamedFile: true, - isNewFile: false, - }, - }, - }, - }, - }, - }) - }) - - describe('when data is loaded', () => { - it('returns the data', async () => { - const { result } = renderHook( - () => - useSingularImpactedFileComparison({ - provider, - owner, - repo, - pullId: 10, - path: 'someFile.js', - }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => - expect(result.current.data).toEqual({ - fileLabel: 'Renamed', - headName: 'file A', - isCriticalFile: false, - hashedPath: 'hashedFilePath', - segments: [ - { - hasUnintendedChanges: false, - header: '@@ -0,0 +1,45 @@', - lines: [ - { - baseCoverage: null, - baseNumber: null, - content: '+export default class Calculator {', - headCoverage: 'H', - headNumber: '1', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private value = 0;', - headCoverage: 'H', - headNumber: '2', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private calcMode = ""', - headCoverage: 'H', - headNumber: '3', - }, - ], - }, - ], - }) - ) - }) - }) - }) - - describe('when called with deleted file', () => { - beforeEach(() => { - setup({ - owner: { - repository: { - __typename: 'Repository', - pull: { - compareWithBase: { - __typename: 'Comparison', - impactedFile: { - ...mockSingularImpactedFilesData, - isDeletedFile: true, - }, - }, - }, - }, - }, - }) - }) - - describe('when data is loaded', () => { - it('returns the data', async () => { - const { result } = renderHook( - () => - useSingularImpactedFileComparison({ - provider, - owner, - repo, - pullId: 10, - path: 'someFile.js', - }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => - expect(result.current.data).toEqual({ - fileLabel: 'New', - headName: 'file A', - isCriticalFile: false, - hashedPath: 'hashedFilePath', - segments: [ - { - hasUnintendedChanges: false, - header: '@@ -0,0 +1,45 @@', - lines: [ - { - baseCoverage: null, - baseNumber: null, - content: '+export default class Calculator {', - headCoverage: 'H', - headNumber: '1', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private value = 0;', - headCoverage: 'H', - headNumber: '2', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private calcMode = ""', - headCoverage: 'H', - headNumber: '3', - }, - ], - }, - ], - }) - ) - }) - }) - }) - - describe('when called with an unchanged file label', () => { - beforeEach(() => { - setup({ - owner: { - repository: { - __typename: 'Repository', - pull: { - compareWithBase: { - __typename: 'Comparison', - impactedFile: { - ...mockSingularImpactedFilesData, - isNewFile: false, - isRenamedFile: false, - isDeletedFile: false, - }, - }, - }, - }, - }, - }) - }) - - describe('when data is loaded', () => { - it('returns the data', async () => { - const { result } = renderHook( - () => - useSingularImpactedFileComparison({ - provider, - owner, - repo, - pullId: 10, - path: 'someFile.js', - }), - { - wrapper, - } - ) - - await waitFor(() => result.current.isLoading) - await waitFor(() => !result.current.isLoading) - - await waitFor(() => - expect(result.current.data).toEqual({ - fileLabel: null, - headName: 'file A', - isCriticalFile: false, - hashedPath: 'hashedFilePath', - segments: [ - { - hasUnintendedChanges: false, - header: '@@ -0,0 +1,45 @@', - lines: [ - { - baseCoverage: null, - baseNumber: null, - content: '+export default class Calculator {', - headCoverage: 'H', - headNumber: '1', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private value = 0;', - headCoverage: 'H', - headNumber: '2', - }, - { - baseCoverage: null, - baseNumber: null, - content: '+ private calcMode = ""', - headCoverage: 'H', - headNumber: '3', - }, - ], - }, - ], - }) - ) - }) - }) - }) -}) diff --git a/src/services/pull/index.js b/src/services/pull/index.ts similarity index 100% rename from src/services/pull/index.js rename to src/services/pull/index.ts diff --git a/src/services/pull/usePrefetchSingleFileComp.spec.tsx b/src/services/pull/usePrefetchSingleFileComp.test.tsx similarity index 93% rename from src/services/pull/usePrefetchSingleFileComp.spec.tsx rename to src/services/pull/usePrefetchSingleFileComp.test.tsx index 9d7008daa4..d6bb9ced2c 100644 --- a/src/services/pull/usePrefetchSingleFileComp.spec.tsx +++ b/src/services/pull/usePrefetchSingleFileComp.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePrefetchSingleFileComp } from './usePrefetchSingleFileComp' @@ -181,24 +182,24 @@ describe('usePrefetchSingleFileComp', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('ImpactedFileComparison', (req, res, ctx) => { + graphql.query('ImpactedFileComparison', (info) => { if (isRenamed) { - return res(ctx.status(200), ctx.data(mockRenamedFile)) + return HttpResponse.json({ data: mockRenamedFile }) } else if (isDeleted) { - return res(ctx.status(200), ctx.data(mockDeletedFile)) + return HttpResponse.json({ data: mockDeletedFile }) } else if (isUnchanged) { - return res(ctx.status(200), ctx.data(mockUnchangedFile)) + return HttpResponse.json({ data: mockUnchangedFile }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) + return HttpResponse.json({ data: mockDataOwnerNotActivated }) } else if (isRepositoryNotFoundError) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) + return HttpResponse.json({ data: mockDataRepositoryNotFound }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } @@ -398,14 +399,13 @@ describe('usePrefetchSingleFileComp', () => { }) describe('rejecting request', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('fails to parse bad schema', async () => { diff --git a/src/services/pull/usePull.test.tsx b/src/services/pull/usePull.test.tsx new file mode 100644 index 0000000000..92134c9388 --- /dev/null +++ b/src/services/pull/usePull.test.tsx @@ -0,0 +1,394 @@ +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 { type MockInstance } from 'vitest' + +import { usePull } from './usePull' + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, +}) + +const wrapper: React.FC = ({ children }) => ( + {children} +) + +const server = setupServer() +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +const mockImpactedFiles = [ + { + isCriticalFile: true, + missesCount: 3, + fileName: 'mafs.js', + headName: 'flag1/mafs.js', + baseCoverage: { + percentCovered: 45.38, + }, + headCoverage: { + percentCovered: 90.23, + }, + patchCoverage: { + percentCovered: 27.43, + }, + changeCoverage: 41, + }, +] + +const pull = { + owner: { + isCurrentUserPartOfOrg: true, + repository: { + __typename: 'Repository', + defaultBranch: 'main', + private: false, + pull: { + commits: { + edges: [ + { + node: { + state: 'complete', + commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', + message: + 'create component to hold bundle list table for a given pull 2', + author: { + username: 'nicholas-codecov', + }, + }, + }, + ], + }, + compareWithBase: { + state: 'complete', + __typename: 'Comparison', + flagComparisons: [], + patchTotals: { + percentCovered: 92.12, + }, + baseTotals: { + percentCovered: 98.25, + }, + headTotals: { + percentCovered: 78.33, + }, + impactedFiles: { + __typename: 'ImpactedFiles', + results: mockImpactedFiles, + }, + changeCoverage: 38.94, + hasDifferentNumberOfHeadAndBaseReports: true, + }, + pullId: 2510, + title: 'feat: Create bundle analysis table for a given pull', + state: 'OPEN', + author: { + username: 'nicholas-codecov', + }, + head: { + ciPassed: true, + branchName: + 'gh-eng-994-create-bundle-analysis-table-for-a-given-pull', + state: 'complete', + commitid: 'fc43199b07c52cf3d6c19b7cdb368f74387c38ab', + totals: { + percentCovered: 78.33, + }, + uploads: { + totalCount: 4, + edges: [], + }, + }, + updatestamp: '2024-01-12T12:56:18.912860', + behindBy: 82367894, + behindByCommit: '1798hvs8ofhn', + comparedTo: { + commitid: '2d6c42fe217c61b007b2c17544a9d85840381857', + uploads: { + totalCount: 1, + edges: [], + }, + }, + }, + }, + }, +} + +const provider = 'gh' +const owner = 'codecov' +const repo = 'gazebo' + +describe('usePull', () => { + afterEach(() => queryClient.clear()) + + function setup(data: {}) { + server.use( + graphql.query('Pull', (info) => { + return HttpResponse.json({ data }) + }) + ) + } + + describe('when called', () => { + beforeEach(() => { + setup(pull) + }) + + describe('when data is loaded', () => { + it('returns the data', async () => { + const { result } = renderHook( + () => usePull({ provider, owner, repo, pullId: '2510' }), + { wrapper } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.data).toEqual({ + defaultBranch: 'main', + hasAccess: true, + pull: { + behindBy: 82367894, + behindByCommit: '1798hvs8ofhn', + pullId: 2510, + title: 'feat: Create bundle analysis table for a given pull', + state: 'OPEN', + updatestamp: '2024-01-12T12:56:18.912860', + author: { username: 'nicholas-codecov' }, + comparedTo: { + commitid: '2d6c42fe217c61b007b2c17544a9d85840381857', + uploads: { totalCount: 1, edges: [] }, + }, + head: { + state: 'complete', + ciPassed: true, + branchName: + 'gh-eng-994-create-bundle-analysis-table-for-a-given-pull', + commitid: 'fc43199b07c52cf3d6c19b7cdb368f74387c38ab', + totals: { percentCovered: 78.33 }, + uploads: { totalCount: 4, edges: [] }, + }, + commits: { + edges: [ + { + node: { + state: 'complete', + commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', + message: + 'create component to hold bundle list table for a given pull 2', + author: { username: 'nicholas-codecov' }, + }, + }, + ], + }, + compareWithBase: { + __typename: 'Comparison', + state: 'complete', + patchTotals: { percentCovered: 92.12 }, + baseTotals: { percentCovered: 98.25 }, + headTotals: { percentCovered: 78.33 }, + impactedFiles: { + __typename: 'ImpactedFiles', + results: [ + { + isCriticalFile: true, + missesCount: 3, + fileName: 'mafs.js', + headName: 'flag1/mafs.js', + baseCoverage: { percentCovered: 45.38 }, + headCoverage: { percentCovered: 90.23 }, + patchCoverage: { percentCovered: 27.43 }, + changeCoverage: 41, + }, + ], + }, + flagComparisons: [], + changeCoverage: 38.94, + hasDifferentNumberOfHeadAndBaseReports: true, + }, + }, + }) + ) + }) + }) + + describe('when it is of OwnerNotActivatedError type', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + + it('returns the error', async () => { + setup({ + owner: { + isCurrentUserPartOfOrg: false, + repository: { + __typename: 'OwnerNotActivatedError', + message: 'owner not activated', + }, + }, + }) + + const { result } = renderHook( + () => usePull({ provider, owner, repo, pullId: '2510' }), + { wrapper } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ status: 403 }) + ) + ) + }) + }) + + describe('when it is of NotFoundError type', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + + it('returns the error', async () => { + setup({ + owner: { + isCurrentUserPartOfOrg: false, + repository: { + __typename: 'NotFoundError', + message: 'not found', + }, + }, + }) + + const { result } = renderHook( + () => usePull({ provider, owner, repo, pullId: '2510' }), + { wrapper } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ status: 404, data: {} }) + ) + ) + }) + }) + + describe('when there is no pull returned', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + + it('returns pull null', async () => { + setup({ + owner: { + isCurrentUserPartOfOrg: true, + repository: { + __typename: 'Repository', + defaultBranch: 'main', + private: false, + pull: null, + }, + }, + }) + + const { result } = renderHook( + () => usePull({ provider, owner, repo, pullId: '2510' }), + { wrapper } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => expect(result.current.data?.pull).toEqual(null)) + }) + }) + + describe('when schema is not valid', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + + it('throws an error', async () => { + setup({ + owner: { + isCurrentUserPartOfOrg: true, + repository: { + __typename: 'Repository', + defaultBranch: 'main', + private: false, + pull: { + commits: { + edges: [ + { + node: { + state: 'complete', + commitid: 'fc43199ccde1f21a940aa3d596c711c1c420651f', + message: + 'create component to hold bundle list table for a given pull 2', + }, + }, + ], + }, + }, + }, + }, + }) + + const { result } = renderHook( + () => usePull({ provider, owner, repo, pullId: '2510' }), + { + wrapper, + } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ status: 404, data: {} }) + ) + ) + }) + }) + }) +}) diff --git a/src/services/pull/usePull.tsx b/src/services/pull/usePull.tsx index 4dc85c082a..7e9ace8991 100644 --- a/src/services/pull/usePull.tsx +++ b/src/services/pull/usePull.tsx @@ -322,7 +322,7 @@ export function usePull({ if (!parsedRes.success) { return Promise.reject({ status: 404, - data: null, + data: {}, }) } diff --git a/src/services/pull/usePullBADropdownSummary.spec.tsx b/src/services/pull/usePullBADropdownSummary.test.tsx similarity index 85% rename from src/services/pull/usePullBADropdownSummary.spec.tsx rename to src/services/pull/usePullBADropdownSummary.test.tsx index 5ae8a2bbde..89e7090592 100644 --- a/src/services/pull/usePullBADropdownSummary.spec.tsx +++ b/src/services/pull/usePullBADropdownSummary.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullBADropdownSummary } from './usePullBADropdownSummary' @@ -94,17 +95,17 @@ describe('usePullBADropdownSummary', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('PullBADropdownSummary', (req, res, ctx) => { + graphql.query('PullBADropdownSummary', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockPullBASummaryData)) + return HttpResponse.json({ data: mockPullBASummaryData }) } }) ) @@ -170,14 +171,13 @@ describe('usePullBADropdownSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -206,14 +206,13 @@ describe('usePullBADropdownSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -242,14 +241,13 @@ describe('usePullBADropdownSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/pull/usePullBundleComparisonList.spec.tsx b/src/services/pull/usePullBundleComparisonList.test.tsx similarity index 88% rename from src/services/pull/usePullBundleComparisonList.spec.tsx rename to src/services/pull/usePullBundleComparisonList.test.tsx index 815cf7a2a8..55af431606 100644 --- a/src/services/pull/usePullBundleComparisonList.spec.tsx +++ b/src/services/pull/usePullBundleComparisonList.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullBundleComparisonList } from './usePullBundleComparisonList' @@ -125,17 +126,17 @@ describe('usePullBundleComparisonList', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('PullBundleComparisonList', (req, res, ctx) => { + graphql.query('PullBundleComparisonList', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockPullBundleListData)) + return HttpResponse.json({ data: mockPullBundleListData }) } }) ) @@ -232,14 +233,13 @@ describe('usePullBundleComparisonList', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -268,14 +268,13 @@ describe('usePullBundleComparisonList', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -304,14 +303,13 @@ describe('usePullBundleComparisonList', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/pull/usePullBundleHeadList.spec.tsx b/src/services/pull/usePullBundleHeadList.test.tsx similarity index 85% rename from src/services/pull/usePullBundleHeadList.spec.tsx rename to src/services/pull/usePullBundleHeadList.test.tsx index 77dcec23df..8e759c06e2 100644 --- a/src/services/pull/usePullBundleHeadList.spec.tsx +++ b/src/services/pull/usePullBundleHeadList.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullBundleHeadList } from './usePullBundleHeadList' @@ -86,7 +87,6 @@ beforeAll(() => { }) afterEach(() => { - jest.resetAllMocks() queryClient.clear() server.resetHandlers() }) @@ -110,21 +110,21 @@ describe('usePullBundleHeadList', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('PullBundleHeadList', (req, res, ctx) => { + graphql.query('PullBundleHeadList', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } - return res(ctx.status(200), ctx.data(mockPullBundleList)) + return HttpResponse.json({ data: mockPullBundleList }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) } @@ -195,14 +195,13 @@ describe('usePullBundleHeadList', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -230,14 +229,13 @@ describe('usePullBundleHeadList', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -265,14 +263,13 @@ describe('usePullBundleHeadList', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/pull/usePullCompareTotalsTeam.spec.tsx b/src/services/pull/usePullCompareTotalsTeam.test.tsx similarity index 86% rename from src/services/pull/usePullCompareTotalsTeam.spec.tsx rename to src/services/pull/usePullCompareTotalsTeam.test.tsx index af3e441113..ead0ad0782 100644 --- a/src/services/pull/usePullCompareTotalsTeam.spec.tsx +++ b/src/services/pull/usePullCompareTotalsTeam.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullCompareTotalsTeam } from './usePullCompareTotalsTeam' @@ -100,17 +101,17 @@ describe('usePullCompareTotalsTeam', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetPullCompareTotalsTeam', (req, res, ctx) => { + graphql.query('GetPullCompareTotalsTeam', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCompareData)) + return HttpResponse.json({ data: mockCompareData }) } }) ) @@ -180,12 +181,13 @@ describe('usePullCompareTotalsTeam', () => { }) describe('returns NotFound Error __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -211,12 +213,13 @@ describe('usePullCompareTotalsTeam', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -242,12 +245,13 @@ describe('usePullCompareTotalsTeam', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/pull/usePullComponents.spec.tsx b/src/services/pull/usePullComponents.test.tsx similarity index 83% rename from src/services/pull/usePullComponents.spec.tsx rename to src/services/pull/usePullComponents.test.tsx index 6ee5c735c7..5bcdd9fd9b 100644 --- a/src/services/pull/usePullComponents.spec.tsx +++ b/src/services/pull/usePullComponents.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { usePullComponents } from './usePullComponents' @@ -96,17 +97,17 @@ describe('usePullComponents', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('PullComponentsSelector', (req, res, ctx) => { + graphql.query('PullComponentsSelector', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockCompareData)) + return HttpResponse.json({ data: mockCompareData }) } }) ) @@ -150,12 +151,13 @@ describe('usePullComponents', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -177,14 +179,13 @@ describe('usePullComponents', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -208,14 +209,13 @@ describe('usePullComponents', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/pull/usePullCoverageDropdownSummary.spec.tsx b/src/services/pull/usePullCoverageDropdownSummary.test.tsx similarity index 84% rename from src/services/pull/usePullCoverageDropdownSummary.spec.tsx rename to src/services/pull/usePullCoverageDropdownSummary.test.tsx index b943d41a6e..024a822870 100644 --- a/src/services/pull/usePullCoverageDropdownSummary.spec.tsx +++ b/src/services/pull/usePullCoverageDropdownSummary.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullCoverageDropdownSummary } from './usePullCoverageDropdownSummary' @@ -87,17 +88,17 @@ describe('usePullCoverageDropdownSummary', () => { isOwnerNotActivatedError = false, }: SetupArgs = {}) { server.use( - graphql.query('PullCoverageDropdownSummary', (req, res, ctx) => { + graphql.query('PullCoverageDropdownSummary', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockPullSummaryData)) + return HttpResponse.json({ data: mockPullSummaryData }) } }) ) @@ -156,14 +157,13 @@ describe('usePullCoverageDropdownSummary', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -192,14 +192,13 @@ describe('usePullCoverageDropdownSummary', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -228,14 +227,13 @@ describe('usePullCoverageDropdownSummary', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { diff --git a/src/services/pull/usePullTeam.spec.tsx b/src/services/pull/usePullTeam.test.tsx similarity index 86% rename from src/services/pull/usePullTeam.spec.tsx rename to src/services/pull/usePullTeam.test.tsx index 54854f36bd..79f781b9db 100644 --- a/src/services/pull/usePullTeam.spec.tsx +++ b/src/services/pull/usePullTeam.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { usePullTeam } from './usePullTeam' @@ -108,7 +109,6 @@ beforeAll(() => { }) afterEach(() => { - jest.useRealTimers() queryClient.clear() server.resetHandlers() }) @@ -132,21 +132,21 @@ describe('usePullTeam', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetPullTeam', (req, res, ctx) => { + graphql.query('GetPullTeam', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockPullData)) + return HttpResponse.json({ data: mockPullData }) } }), - graphql.query('GetPullCompareTotalsTeam', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockCompareData)) + graphql.query('GetPullCompareTotalsTeam', (info) => { + return HttpResponse.json({ data: mockCompareData }) }) ) } @@ -228,12 +228,13 @@ describe('usePullTeam', () => { }) describe('returns NotFoundError __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -263,12 +264,13 @@ describe('usePullTeam', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -298,12 +300,13 @@ describe('usePullTeam', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.resetAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -337,17 +340,17 @@ describe('usePullTeam polling', () => { function setup() { let nbCallCompare = 0 server.use( - graphql.query(`GetPullTeam`, (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockPullData)) + graphql.query(`GetPullTeam`, (info) => { + return HttpResponse.json({ data: mockPullData }) }), - graphql.query(`GetPullCompareTotalsTeam`, (req, res, ctx) => { + graphql.query(`GetPullCompareTotalsTeam`, (info) => { nbCallCompare++ if (nbCallCompare < 9) { - return res(ctx.status(200), ctx.data(mockPullData)) + return HttpResponse.json({ data: mockPullData }) } - return res(ctx.status(200), ctx.data(mockCompareData)) + return HttpResponse.json({ data: mockCompareData }) }) ) } diff --git a/src/services/pull/useSingularImpactedFileComparison.spec.tsx b/src/services/pull/useSingularImpactedFileComparison.test.tsx similarity index 93% rename from src/services/pull/useSingularImpactedFileComparison.spec.tsx rename to src/services/pull/useSingularImpactedFileComparison.test.tsx index 8156d132fb..b0bd3bd141 100644 --- a/src/services/pull/useSingularImpactedFileComparison.spec.tsx +++ b/src/services/pull/useSingularImpactedFileComparison.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useSingularImpactedFileComparison } from './useSingularImpactedFileComparison' import { transformImpactedFileData } from './utils' @@ -123,17 +123,17 @@ describe('useSingularImpactedFileComparison', () => { isMissingBaseCommit = false, }) { server.use( - graphql.query('ImpactedFileComparison', (req, res, ctx) => { + graphql.query('ImpactedFileComparison', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockIncorrectResponse)) + return HttpResponse.json({ data: mockIncorrectResponse }) } else if (isMissingBaseCommit) { - return res(ctx.status(200), ctx.data(mockMissingBaseCommitResponse)) + return HttpResponse.json({ data: mockMissingBaseCommitResponse }) } - return res(ctx.status(200), ctx.data(mockResponse)) + return HttpResponse.json({ data: mockResponse }) }) ) } diff --git a/src/services/pull/utils/index.js b/src/services/pull/utils/index.ts similarity index 100% rename from src/services/pull/utils/index.js rename to src/services/pull/utils/index.ts diff --git a/src/services/pull/utils/setFileLabel.js b/src/services/pull/utils/setFileLabel.js deleted file mode 100644 index e2e91e49c0..0000000000 --- a/src/services/pull/utils/setFileLabel.js +++ /dev/null @@ -1,6 +0,0 @@ -export function setFileLabel({ isNewFile, isRenamedFile, isDeletedFile }) { - if (isNewFile) return 'New' - if (isRenamedFile) return 'Renamed' - if (isDeletedFile) return 'Deleted' - return null -} diff --git a/src/services/pull/utils/setFileLabel.spec.js b/src/services/pull/utils/setFileLabel.test.ts similarity index 100% rename from src/services/pull/utils/setFileLabel.spec.js rename to src/services/pull/utils/setFileLabel.test.ts diff --git a/src/services/pull/utils/setFileLabel.ts b/src/services/pull/utils/setFileLabel.ts new file mode 100644 index 0000000000..49bc7b70ed --- /dev/null +++ b/src/services/pull/utils/setFileLabel.ts @@ -0,0 +1,16 @@ +interface SetFileLabel { + isNewFile?: boolean + isRenamedFile?: boolean + isDeletedFile?: boolean +} + +export function setFileLabel({ + isNewFile, + isRenamedFile, + isDeletedFile, +}: SetFileLabel) { + if (isNewFile) return 'New' + if (isRenamedFile) return 'Renamed' + if (isDeletedFile) return 'Deleted' + return null +} diff --git a/src/services/pull/utils/transformImpactedFileData.spec.js b/src/services/pull/utils/transformImpactedFileData.test.js similarity index 100% rename from src/services/pull/utils/transformImpactedFileData.spec.js rename to src/services/pull/utils/transformImpactedFileData.test.js From 9d3c84baa8c51cc468e4c810077abb8b1befb0b4 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 08:25:31 -0400 Subject: [PATCH 18/20] chore: Update services/pathContents to Vitest (#3302) --- ...tsx => usePrefetchBranchDirEntry.test.tsx} | 18 +++--- ...pec.tsx => useRepoBranchContents.test.tsx} | 18 +++--- ...js => usePrefetchBranchFileEntry.test.jsx} | 10 ++-- .../commit/dir/{index.js => index.ts} | 0 ...tsx => usePrefetchCommitDirEntry.test.tsx} | 30 +++++----- ...pec.tsx => useRepoCommitContents.test.tsx} | 18 +++--- .../commit/file/{index.js => index.ts} | 0 ...sx => usePrefetchCommitFileEntry.test.tsx} | 34 ++++++----- ...c.tsx => usePrefetchPullDirEntry.test.tsx} | 20 +++---- ....spec.tsx => useRepoPullContents.test.tsx} | 58 +++++++++++++------ ....tsx => usePrefetchPullFileEntry.test.tsx} | 40 ++++++------- ...c.tsx => useFileWithMainCoverage.test.tsx} | 38 ++++++------ 12 files changed, 151 insertions(+), 133 deletions(-) rename src/services/pathContents/branch/dir/{usePrefetchBranchDirEntry.spec.tsx => usePrefetchBranchDirEntry.test.tsx} (93%) rename src/services/pathContents/branch/dir/{useRepoBranchContents.spec.tsx => useRepoBranchContents.test.tsx} (94%) rename src/services/pathContents/branch/file/{usePrefetchBranchFileEntry.spec.js => usePrefetchBranchFileEntry.test.jsx} (94%) rename src/services/pathContents/commit/dir/{index.js => index.ts} (100%) rename src/services/pathContents/commit/dir/{usePrefetchCommitDirEntry.spec.tsx => usePrefetchCommitDirEntry.test.tsx} (91%) rename src/services/pathContents/commit/dir/{useRepoCommitContents.spec.tsx => useRepoCommitContents.test.tsx} (94%) rename src/services/pathContents/commit/file/{index.js => index.ts} (100%) rename src/services/pathContents/commit/file/{usePrefetchCommitFileEntry.spec.tsx => usePrefetchCommitFileEntry.test.tsx} (90%) rename src/services/pathContents/pull/dir/{usePrefetchPullDirEntry.spec.tsx => usePrefetchPullDirEntry.test.tsx} (92%) rename src/services/pathContents/pull/dir/{useRepoPullContents.spec.tsx => useRepoPullContents.test.tsx} (85%) rename src/services/pathContents/pull/file/{usePrefetchPullFileEntry.spec.tsx => usePrefetchPullFileEntry.test.tsx} (90%) rename src/services/pathContents/{useFileWithMainCoverage.spec.tsx => useFileWithMainCoverage.test.tsx} (89%) diff --git a/src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.spec.tsx b/src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.test.tsx similarity index 93% rename from src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.spec.tsx rename to src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.test.tsx index 3d692590a5..9ab7ab4f2e 100644 --- a/src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.spec.tsx +++ b/src/services/pathContents/branch/dir/usePrefetchBranchDirEntry.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { usePrefetchBranchDirEntry } from './usePrefetchBranchDirEntry' @@ -151,20 +151,20 @@ describe('usePrefetchBranchDirEntry', () => { isUnsuccessfulParseError = false, }: SetupArgs) { server.use( - graphql.query('BranchContents', (req, res, ctx) => { + graphql.query('BranchContents', (info) => { if (isMissingCoverage) { - return res(ctx.status(200), ctx.data(mockDataMissingCoverage)) + return HttpResponse.json({ data: mockDataMissingCoverage }) } else if (isUnknownPath) { - return res(ctx.status(200), ctx.data(mockDataUnknownPath)) + return HttpResponse.json({ data: mockDataUnknownPath }) } else if (isRepositoryNotFoundError) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) + return HttpResponse.json({ data: mockDataRepositoryNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) + return HttpResponse.json({ data: mockDataOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/branch/dir/useRepoBranchContents.spec.tsx b/src/services/pathContents/branch/dir/useRepoBranchContents.test.tsx similarity index 94% rename from src/services/pathContents/branch/dir/useRepoBranchContents.spec.tsx rename to src/services/pathContents/branch/dir/useRepoBranchContents.test.tsx index 1c7e73ff86..25bfd530f7 100644 --- a/src/services/pathContents/branch/dir/useRepoBranchContents.spec.tsx +++ b/src/services/pathContents/branch/dir/useRepoBranchContents.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useRepoBranchContents } from './useRepoBranchContents' @@ -150,20 +150,20 @@ describe('useRepoBranchContents', () => { isUnsuccessfulParseError = false, }: SetupArgs) { server.use( - graphql.query('BranchContents', (req, res, ctx) => { + graphql.query('BranchContents', (info) => { if (isMissingCoverage) { - return res(ctx.status(200), ctx.data(mockDataMissingCoverage)) + return HttpResponse.json({ data: mockDataMissingCoverage }) } else if (isUnknownPath) { - return res(ctx.status(200), ctx.data(mockDataUnknownPath)) + return HttpResponse.json({ data: mockDataUnknownPath }) } else if (isRepositoryNotFoundError) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) + return HttpResponse.json({ data: mockDataRepositoryNotFound }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) + return HttpResponse.json({ data: mockDataOwnerNotActivated }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/branch/file/usePrefetchBranchFileEntry.spec.js b/src/services/pathContents/branch/file/usePrefetchBranchFileEntry.test.jsx similarity index 94% rename from src/services/pathContents/branch/file/usePrefetchBranchFileEntry.spec.js rename to src/services/pathContents/branch/file/usePrefetchBranchFileEntry.test.jsx index 81ce97659c..2887e99295 100644 --- a/src/services/pathContents/branch/file/usePrefetchBranchFileEntry.spec.js +++ b/src/services/pathContents/branch/file/usePrefetchBranchFileEntry.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { usePrefetchBranchFileEntry } from './usePrefetchBranchFileEntry' @@ -90,9 +90,9 @@ const mockData = { describe('usePrefetchBranchFileEntry', () => { function setup() { server.use( - graphql.query('CoverageForFile', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockData)) - ) + graphql.query('CoverageForFile', (info) => { + return HttpResponse.json({ data: mockData }) + }) ) } diff --git a/src/services/pathContents/commit/dir/index.js b/src/services/pathContents/commit/dir/index.ts similarity index 100% rename from src/services/pathContents/commit/dir/index.js rename to src/services/pathContents/commit/dir/index.ts diff --git a/src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.spec.tsx b/src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.test.tsx similarity index 91% rename from src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.spec.tsx rename to src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.test.tsx index 89223177fe..f779fa3192 100644 --- a/src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.spec.tsx +++ b/src/services/pathContents/commit/dir/usePrefetchCommitDirEntry.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { usePrefetchCommitDirEntry } from './usePrefetchCommitDirEntry' @@ -141,23 +141,19 @@ describe('usePrefetchCommitDirEntry', () => { isUnsuccessfulParse = false, }: SetupArgs) { server.use( - graphql.query('CommitPathContents', (req, res, ctx) => { + graphql.query('CommitPathContents', (info) => { if (isMissingCoverage) { - return res(ctx.status(200), ctx.data(mockDataMissingCoverage)) + return HttpResponse.json({ data: mockDataMissingCoverage }) + } else if (isUnknownPath) { + return HttpResponse.json({ data: mockDataUnknownPath }) + } else if (isNotFoundError) { + return HttpResponse.json({ data: mockNotFoundError }) + } else if (isOwnerNotActivatedError) { + return HttpResponse.json({ data: mockOwnerNotActivatedError }) + } else if (isUnsuccessfulParse) { + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } - if (isUnknownPath) { - return res(ctx.status(200), ctx.data(mockDataUnknownPath)) - } - if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) - } - if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) - } - if (isUnsuccessfulParse) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) - } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/commit/dir/useRepoCommitContents.spec.tsx b/src/services/pathContents/commit/dir/useRepoCommitContents.test.tsx similarity index 94% rename from src/services/pathContents/commit/dir/useRepoCommitContents.spec.tsx rename to src/services/pathContents/commit/dir/useRepoCommitContents.test.tsx index 49c0a4c804..edd6d5912f 100644 --- a/src/services/pathContents/commit/dir/useRepoCommitContents.spec.tsx +++ b/src/services/pathContents/commit/dir/useRepoCommitContents.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useRepoCommitContents } from './useRepoCommitContents' @@ -144,19 +144,19 @@ describe('useRepoCommitContents', () => { isUnsuccessfulParseError = false, }: SetupArgs) { server.use( - graphql.query('CommitPathContents', (req, res, ctx) => { + graphql.query('CommitPathContents', (info) => { if (isMissingCoverage) { - return res(ctx.status(200), ctx.data(mockDataMissingCoverage)) + return HttpResponse.json({ data: mockDataMissingCoverage }) } else if (isUnknownPath) { - return res(ctx.status(200), ctx.data(mockDataUnknownPath)) + return HttpResponse.json({ data: mockDataUnknownPath }) } else if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/commit/file/index.js b/src/services/pathContents/commit/file/index.ts similarity index 100% rename from src/services/pathContents/commit/file/index.js rename to src/services/pathContents/commit/file/index.ts diff --git a/src/services/pathContents/commit/file/usePrefetchCommitFileEntry.spec.tsx b/src/services/pathContents/commit/file/usePrefetchCommitFileEntry.test.tsx similarity index 90% rename from src/services/pathContents/commit/file/usePrefetchCommitFileEntry.spec.tsx rename to src/services/pathContents/commit/file/usePrefetchCommitFileEntry.test.tsx index a3d86276a2..d58b441514 100644 --- a/src/services/pathContents/commit/file/usePrefetchCommitFileEntry.spec.tsx +++ b/src/services/pathContents/commit/file/usePrefetchCommitFileEntry.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { usePrefetchCommitFileEntry } from './usePrefetchCommitFileEntry' @@ -116,19 +117,19 @@ describe('usePrefetchCommitFileEntry', () => { const mockVars = jest.fn() server.use( - graphql.query('CoverageForFile', (req, res, ctx) => { - mockVars(req.variables) + graphql.query('CoverageForFile', (info) => { + mockVars(info.variables) if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) } }) ) @@ -277,12 +278,13 @@ describe('usePrefetchCommitFileEntry', () => { }) describe('returns NotFoundError __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.restoreAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -314,12 +316,13 @@ describe('usePrefetchCommitFileEntry', () => { }) describe('returns OwnerNotActivatedError __typename', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.restoreAllMocks() + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -351,12 +354,13 @@ describe('usePrefetchCommitFileEntry', () => { }) describe('unsuccessful parse of zod schema', () => { + let consoleSpy: MockInstance beforeEach(() => { - jest.spyOn(console, 'error') + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - jest.restoreAllMocks() + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/pathContents/pull/dir/usePrefetchPullDirEntry.spec.tsx b/src/services/pathContents/pull/dir/usePrefetchPullDirEntry.test.tsx similarity index 92% rename from src/services/pathContents/pull/dir/usePrefetchPullDirEntry.spec.tsx rename to src/services/pathContents/pull/dir/usePrefetchPullDirEntry.test.tsx index 4f48b8e1ca..9ffac58a96 100644 --- a/src/services/pathContents/pull/dir/usePrefetchPullDirEntry.spec.tsx +++ b/src/services/pathContents/pull/dir/usePrefetchPullDirEntry.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { usePrefetchPullDirEntry } from './usePrefetchPullDirEntry' @@ -95,17 +95,15 @@ describe('usePrefetchPullDirEntry', () => { ownerNotActivated = false, }) { server.use( - graphql.query('PullPathContents', (req, res, ctx) => { + graphql.query('PullPathContents', (info) => { if (invalidSchema) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) + } else if (repositoryNotFound) { + return HttpResponse.json({ data: mockDataRepositoryNotFound }) + } else if (ownerNotActivated) { + return HttpResponse.json({ data: mockDataOwnerNotActivated }) } - if (repositoryNotFound) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) - } - if (ownerNotActivated) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) - } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/pull/dir/useRepoPullContents.spec.tsx b/src/services/pathContents/pull/dir/useRepoPullContents.test.tsx similarity index 85% rename from src/services/pathContents/pull/dir/useRepoPullContents.spec.tsx rename to src/services/pathContents/pull/dir/useRepoPullContents.test.tsx index 188f827df3..7abc719cc8 100644 --- a/src/services/pathContents/pull/dir/useRepoPullContents.spec.tsx +++ b/src/services/pathContents/pull/dir/useRepoPullContents.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { useRepoPullContents } from './useRepoPullContents' @@ -140,23 +141,19 @@ describe('useRepoPullContents', () => { isUnknownPath = false, }) { server.use( - graphql.query('PullPathContents', (req, res, ctx) => { + graphql.query('PullPathContents', (info) => { if (invalidSchema) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) + } else if (repositoryNotFound) { + return HttpResponse.json({ data: mockDataRepositoryNotFound }) + } else if (ownerNotActivated) { + return HttpResponse.json({ data: mockDataOwnerNotActivated }) + } else if (isMissingCoverage) { + return HttpResponse.json({ data: mockDataMissingCoverage }) + } else if (isUnknownPath) { + return HttpResponse.json({ data: mockDataUnknownPath }) } - if (repositoryNotFound) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) - } - if (ownerNotActivated) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) - } - if (isMissingCoverage) { - return res(ctx.status(200), ctx.data(mockDataMissingCoverage)) - } - if (isUnknownPath) { - return res(ctx.status(200), ctx.data(mockDataUnknownPath)) - } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } @@ -272,6 +269,15 @@ describe('useRepoPullContents', () => { }) describe('on invalid schema', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + it('returns 404', async () => { setup({ invalidSchema: true }) const { result } = renderHook( @@ -300,6 +306,15 @@ describe('useRepoPullContents', () => { }) describe('on repository not found', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + it('returns 404', async () => { setup({ repositoryNotFound: true }) const { result } = renderHook( @@ -328,6 +343,15 @@ describe('useRepoPullContents', () => { }) describe('on owner not activated', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + it('returns 403', async () => { setup({ ownerNotActivated: true }) const { result } = renderHook( diff --git a/src/services/pathContents/pull/file/usePrefetchPullFileEntry.spec.tsx b/src/services/pathContents/pull/file/usePrefetchPullFileEntry.test.tsx similarity index 90% rename from src/services/pathContents/pull/file/usePrefetchPullFileEntry.spec.tsx rename to src/services/pathContents/pull/file/usePrefetchPullFileEntry.test.tsx index b53b169093..c8238d3043 100644 --- a/src/services/pathContents/pull/file/usePrefetchPullFileEntry.spec.tsx +++ b/src/services/pathContents/pull/file/usePrefetchPullFileEntry.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { usePrefetchPullFileEntry } from './usePrefetchPullFileEntry' @@ -31,12 +31,18 @@ const wrapper: React.FC = ({ children }) => ( ) const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) const mockData = { owner: { @@ -95,25 +101,17 @@ describe('usePrefetchPullFileEntry', () => { nullOwner = false, }) { server.use( - graphql.query('CoverageForFile', (req, res, ctx) => { + graphql.query('CoverageForFile', (info) => { if (invalidSchema) { - return res(ctx.status(200), ctx.data({})) - } - if (repositoryNotFound) { - return res(ctx.status(200), ctx.data(mockDataRepositoryNotFound)) - } - if (ownerNotActivated) { - return res(ctx.status(200), ctx.data(mockDataOwnerNotActivated)) - } - if (nullOwner) { - return res( - ctx.status(200), - ctx.data({ - owner: null, - }) - ) + return HttpResponse.json({}) + } else if (repositoryNotFound) { + return HttpResponse.json({ data: mockDataRepositoryNotFound }) + } else if (ownerNotActivated) { + return HttpResponse.json({ data: mockDataOwnerNotActivated }) + } else if (nullOwner) { + return HttpResponse.json({ data: { owner: null } }) } - return res(ctx.status(200), ctx.data(mockData)) + return HttpResponse.json({ data: mockData }) }) ) } diff --git a/src/services/pathContents/useFileWithMainCoverage.spec.tsx b/src/services/pathContents/useFileWithMainCoverage.test.tsx similarity index 89% rename from src/services/pathContents/useFileWithMainCoverage.spec.tsx rename to src/services/pathContents/useFileWithMainCoverage.test.tsx index 698a4e5bac..501ce71b0a 100644 --- a/src/services/pathContents/useFileWithMainCoverage.spec.tsx +++ b/src/services/pathContents/useFileWithMainCoverage.test.tsx @@ -2,9 +2,10 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' // eslint-disable-next-line no-restricted-imports import _ from 'lodash' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { useFileWithMainCoverage } from 'services/pathContents' @@ -112,15 +113,15 @@ describe('useFileWithMainCoverage', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('CoverageForFile', (req, res, ctx) => { + graphql.query('CoverageForFile', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { const mockCoverage = { owner: { @@ -132,7 +133,7 @@ describe('useFileWithMainCoverage', () => { }, } - return res(ctx.status(200), ctx.data(mockCoverage)) + return HttpResponse.json({ data: mockCoverage }) } }) ) @@ -234,14 +235,13 @@ describe('useFileWithMainCoverage', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -273,14 +273,13 @@ describe('useFileWithMainCoverage', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -312,14 +311,13 @@ describe('useFileWithMainCoverage', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { From 93330a5de2c0c7234e592bd7dcbe805a8426e804 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 08:31:00 -0400 Subject: [PATCH 19/20] chore: Update second group of services tests (#3301) --- ... useComparisonForCommitAndParent.test.tsx} | 27 +++- .../{normalize.spec.js => normalize.test.js} | 0 ...ams.spec.js => useLocationParams.test.jsx} | 0 ...eNavLinks.spec.js => useNavLinks.test.jsx} | 0 ...nks.spec.js => useStaticNavLinks.test.jsx} | 12 +- ...rrorToast.spec.tsx => ErrorToast.test.tsx} | 0 ...icToast.spec.tsx => GenericToast.test.tsx} | 0 ...derToast.spec.tsx => renderToast.test.tsx} | 0 .../{context.spec.js => context.test.jsx} | 0 ...ureFlags.spec.js => featureFlags.test.jsx} | 38 ++++-- src/services/tracking/pendo.spec.js | 92 ------------- src/services/tracking/pendo.test.jsx | 125 ++++++++++++++++++ .../{hooks.spec.js => useTracking.test.jsx} | 24 ++-- src/services/users/mocks.js | 6 +- ...User.spec.tsx => useInfiniteUser.test.tsx} | 26 ++-- ...ateUser.spec.js => useUpdateUser.test.jsx} | 15 +-- .../{useUsers.spec.js => useUsers.test.jsx} | 27 ++-- 17 files changed, 234 insertions(+), 158 deletions(-) rename src/services/comparison/useComparisonForCommitAndParent/{useComparisonForCommitAndParent.spec.tsx => useComparisonForCommitAndParent.test.tsx} (89%) rename src/services/navigation/{normalize.spec.js => normalize.test.js} (100%) rename src/services/navigation/{useLocationParams.spec.js => useLocationParams.test.jsx} (100%) rename src/services/navigation/useNavLinks/{useNavLinks.spec.js => useNavLinks.test.jsx} (100%) rename src/services/navigation/useNavLinks/{useStaticNavLinks.spec.js => useStaticNavLinks.test.jsx} (98%) rename src/services/toast/ErrorToast/{ErrorToast.spec.tsx => ErrorToast.test.tsx} (100%) rename src/services/toast/GenericToast/{GenericToast.spec.tsx => GenericToast.test.tsx} (100%) rename src/services/toast/{renderToast.spec.tsx => renderToast.test.tsx} (100%) rename src/services/toastNotification/{context.spec.js => context.test.jsx} (100%) rename src/services/tracking/{featureFlags.spec.js => featureFlags.test.jsx} (88%) delete mode 100644 src/services/tracking/pendo.spec.js create mode 100644 src/services/tracking/pendo.test.jsx rename src/services/tracking/{hooks.spec.js => useTracking.test.jsx} (90%) rename src/services/users/{useInfiniteUser.spec.tsx => useInfiniteUser.test.tsx} (87%) rename src/services/users/{useUpdateUser.spec.js => useUpdateUser.test.jsx} (91%) rename src/services/users/{useUsers.spec.js => useUsers.test.jsx} (88%) diff --git a/src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.spec.tsx b/src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.test.tsx similarity index 89% rename from src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.spec.tsx rename to src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.test.tsx index e88f841ee7..873f50feee 100644 --- a/src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.spec.tsx +++ b/src/services/comparison/useComparisonForCommitAndParent/useComparisonForCommitAndParent.test.tsx @@ -1,8 +1,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React from 'react' +import { type MockInstance } from 'vitest' import { useComparisonForCommitAndParent } from './useComparisonForCommitAndParent' @@ -143,15 +144,15 @@ describe('useComparisonForCommitAndParent', () => { isUnsuccessfulParseError = false, }: SetupArgs) { server.use( - graphql.query('ImpactedFileComparedWithParent', (req, res, ctx) => { + graphql.query('ImpactedFileComparedWithParent', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else { - return res(ctx.status(200), ctx.data(baseMock)) + return HttpResponse.json({ data: baseMock }) } }) ) @@ -179,6 +180,16 @@ describe('useComparisonForCommitAndParent', () => { }) describe('when called and error', () => { + let consoleSpy: MockInstance + + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) + }) + + afterEach(() => { + consoleSpy.mockRestore() + }) + it('can return unsuccessful parse error', async () => { setup({ isUnsuccessfulParseError: true }) const { result } = renderHook( @@ -204,6 +215,7 @@ describe('useComparisonForCommitAndParent', () => { ) ) }) + it('can return not found error', async () => { setup({ isNotFoundError: true }) const { result } = renderHook( @@ -229,6 +241,7 @@ describe('useComparisonForCommitAndParent', () => { ) ) }) + it('can return owner not activated error', async () => { setup({ isOwnerNotActivatedError: true }) const { result } = renderHook( diff --git a/src/services/navigation/normalize.spec.js b/src/services/navigation/normalize.test.js similarity index 100% rename from src/services/navigation/normalize.spec.js rename to src/services/navigation/normalize.test.js diff --git a/src/services/navigation/useLocationParams.spec.js b/src/services/navigation/useLocationParams.test.jsx similarity index 100% rename from src/services/navigation/useLocationParams.spec.js rename to src/services/navigation/useLocationParams.test.jsx diff --git a/src/services/navigation/useNavLinks/useNavLinks.spec.js b/src/services/navigation/useNavLinks/useNavLinks.test.jsx similarity index 100% rename from src/services/navigation/useNavLinks/useNavLinks.spec.js rename to src/services/navigation/useNavLinks/useNavLinks.test.jsx diff --git a/src/services/navigation/useNavLinks/useStaticNavLinks.spec.js b/src/services/navigation/useNavLinks/useStaticNavLinks.test.jsx similarity index 98% rename from src/services/navigation/useNavLinks/useStaticNavLinks.spec.js rename to src/services/navigation/useNavLinks/useStaticNavLinks.test.jsx index 1c1e22051e..bc620f6c56 100644 --- a/src/services/navigation/useNavLinks/useStaticNavLinks.spec.js +++ b/src/services/navigation/useNavLinks/useStaticNavLinks.test.jsx @@ -5,7 +5,7 @@ import config from 'config' import { useStaticNavLinks } from './useStaticNavLinks' -jest.mock('config') +vi.mock('config') describe('useStaticNavLinks', () => { const view = renderHook(() => useStaticNavLinks(), { @@ -16,8 +16,14 @@ describe('useStaticNavLinks', () => { ), }) describe('cloud', () => { - beforeAll(() => jest.requireActual('config')) - afterAll(() => jest.mock('config')) + beforeAll(async () => { + await vi.importActual('config') + }) + + afterAll(() => { + vi.mock('config') + }) + const links = view.result.current describe.each` diff --git a/src/services/toast/ErrorToast/ErrorToast.spec.tsx b/src/services/toast/ErrorToast/ErrorToast.test.tsx similarity index 100% rename from src/services/toast/ErrorToast/ErrorToast.spec.tsx rename to src/services/toast/ErrorToast/ErrorToast.test.tsx diff --git a/src/services/toast/GenericToast/GenericToast.spec.tsx b/src/services/toast/GenericToast/GenericToast.test.tsx similarity index 100% rename from src/services/toast/GenericToast/GenericToast.spec.tsx rename to src/services/toast/GenericToast/GenericToast.test.tsx diff --git a/src/services/toast/renderToast.spec.tsx b/src/services/toast/renderToast.test.tsx similarity index 100% rename from src/services/toast/renderToast.spec.tsx rename to src/services/toast/renderToast.test.tsx diff --git a/src/services/toastNotification/context.spec.js b/src/services/toastNotification/context.test.jsx similarity index 100% rename from src/services/toastNotification/context.spec.js rename to src/services/toastNotification/context.test.jsx diff --git a/src/services/tracking/featureFlags.spec.js b/src/services/tracking/featureFlags.test.jsx similarity index 88% rename from src/services/tracking/featureFlags.spec.js rename to src/services/tracking/featureFlags.test.jsx index c5af8c67c0..c9356eb475 100644 --- a/src/services/tracking/featureFlags.spec.js +++ b/src/services/tracking/featureFlags.test.jsx @@ -1,23 +1,30 @@ import { renderHook } from '@testing-library/react' import Cookie from 'js-cookie' -import { useIdentifyUser } from 'shared/featureFlags' - import { useTrackFeatureFlags } from './featureFlags' -jest.mock('shared/featureFlags', () => ({ - useIdentifyUser: jest.fn(), +const mocks = vi.hoisted(() => ({ + useIdentifyUser: vi.fn(), })) +vi.mock('shared/featureFlags', async () => { + const actual = await vi.importActual('shared/featureFlags') + return { + ...actual, + useIdentifyUser: mocks.useIdentifyUser, + } +}) + describe('useTrackFeatureFlags', () => { - const mockIdentifyUser = jest.fn() + const mockIdentifyUser = vi.fn() describe('normal use', () => { beforeEach(() => { - useIdentifyUser.mockImplementation(mockIdentifyUser) + mocks.useIdentifyUser.mockImplementation(mockIdentifyUser) }) + afterEach(() => { - jest.clearAllMocks() + vi.clearAllMocks() }) it('Creates the expected user and key identified', () => { @@ -63,13 +70,15 @@ describe('useTrackFeatureFlags', () => { describe('impersonating on github', () => { beforeEach(() => { - useIdentifyUser.mockImplementation(mockIdentifyUser) + mocks.useIdentifyUser.mockImplementation(mockIdentifyUser) Cookie.set('staff_user', 'doggo') }) + afterEach(() => { - jest.clearAllMocks() + vi.clearAllMocks() Cookie.remove('staff_user') }) + it('Creates the expected user and key identified', () => { renderHook(() => useTrackFeatureFlags({ @@ -113,11 +122,12 @@ describe('useTrackFeatureFlags', () => { describe('impersonating on bitbucket', () => { beforeEach(() => { - useIdentifyUser.mockImplementation(mockIdentifyUser) + mocks.useIdentifyUser.mockImplementation(mockIdentifyUser) Cookie.set('staff_user', 'doggo') }) + afterEach(() => { - jest.clearAllMocks() + vi.clearAllMocks() Cookie.remove('staff_user') }) @@ -164,13 +174,15 @@ describe('useTrackFeatureFlags', () => { describe('impersonating on gitlab', () => { beforeEach(() => { - useIdentifyUser.mockImplementation(mockIdentifyUser) + mocks.useIdentifyUser.mockImplementation(mockIdentifyUser) Cookie.set('staff_user', 'doggo') }) + afterEach(() => { - jest.clearAllMocks() + vi.clearAllMocks() Cookie.remove('staff_user') }) + it('Creates the expected user and key identified', () => { renderHook(() => useTrackFeatureFlags({ diff --git a/src/services/tracking/pendo.spec.js b/src/services/tracking/pendo.spec.js deleted file mode 100644 index da13148143..0000000000 --- a/src/services/tracking/pendo.spec.js +++ /dev/null @@ -1,92 +0,0 @@ -import { renderHook } from '@testing-library/react' -import React from 'react' -import { useParams } from 'react-router-dom' - -import { useOwner } from 'services/user' - -import { firePendo, useUpdatePendoWithOwner } from './pendo' - -jest.mock('services/user') -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), // import and retain the original functionalities - useParams: jest.fn(() => {}), - useLocation: jest.fn(() => {}), -})) - -const curUser = { - businessEmail: 'userbzemail@gmail.com', - email: 'user@gmail.com', - onboardingCompleted: true, - user: { - username: 'random', - }, - trackingMetadata: { - ownerid: 1999, - plan: 'users-free', - service: 'github', - staff: false, - }, -} - -const ownerData = { - ownerid: 123, - username: 'codecov', - isCurrentUserPartOfOrg: true, -} - -describe('initialize pendo', () => { - function setup() { - window.pendo = { - initialize: jest.fn(), - } - } - - it('fires pendo initialization with expected params', () => { - setup() - firePendo(curUser) - - expect(window.pendo.initialize).toHaveBeenCalledTimes(1) - }) -}) - -describe('update pendo on owner change', () => { - function setup() { - window.pendo = { - updateOptions: jest.fn(), - } - jest - .spyOn(React, 'useRef') - .mockReturnValueOnce({ current: { ...ownerData, ownerid: 456 } }) - - useParams.mockReturnValue({ owner: 'codecov' }) - useOwner.mockReturnValue({ data: ownerData }) - } - - it('fires pendo update options when pathname is different', () => { - setup() - - renderHook(() => useUpdatePendoWithOwner(curUser)) - - expect(window.pendo.updateOptions).toHaveBeenCalledTimes(1) - }) -}) - -describe('update pendo when owner is not changed', () => { - function setup() { - window.pendo = { - updateOptions: jest.fn(), - } - jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: 'codecov' }) - - useParams.mockReturnValue({ owner: 'codecov' }) - useOwner.mockReturnValue({ data: ownerData }) - } - - it('does not fire pendo update', () => { - setup() - - renderHook(() => useUpdatePendoWithOwner(curUser)) - - expect(window.pendo.updateOptions).toHaveBeenCalledTimes(0) - }) -}) diff --git a/src/services/tracking/pendo.test.jsx b/src/services/tracking/pendo.test.jsx new file mode 100644 index 0000000000..d4a4671e3d --- /dev/null +++ b/src/services/tracking/pendo.test.jsx @@ -0,0 +1,125 @@ +import { renderHook } from '@testing-library/react' + +import { firePendo, useUpdatePendoWithOwner } from './pendo' + +const mocks = vi.hoisted(() => ({ + useParams: vi.fn(), + useLocation: vi.fn(), + useOwner: vi.fn(), + useRef: vi.fn(), +})) + +vi.mock('react', async () => { + const original = await vi.importActual('react') + return { + ...original, + useRef: mocks.useRef, + } +}) + +vi.mock('services/user', async () => { + const original = await vi.importActual('services/user') + return { + ...original, + useOwner: mocks.useOwner, + } +}) + +vi.mock('react-router-dom', async () => { + // import and retain the original functionalities + const original = await vi.importActual('react-router-dom') + return { + ...original, + useParams: mocks.useParams, + useLocation: mocks.useLocation, + } +}) + +const curUser = { + businessEmail: 'userbzemail@gmail.com', + email: 'user@gmail.com', + onboardingCompleted: true, + user: { + username: 'random', + }, + trackingMetadata: { + ownerid: 1999, + plan: 'users-free', + service: 'github', + staff: false, + }, +} + +const ownerData = { + ownerid: 123, + username: 'codecov', + isCurrentUserPartOfOrg: true, +} + +afterEach(() => { + vi.clearAllMocks() +}) + +describe('initialize pendo', () => { + function setup() { + const mockInitialize = vi.fn() + window.pendo = { + initialize: mockInitialize, + } + + return { mockInitialize } + } + + it('fires pendo initialization with expected params', () => { + const { mockInitialize } = setup() + firePendo(curUser) + + expect(mockInitialize).toHaveBeenCalledTimes(1) + }) +}) + +describe('update pendo on owner change', () => { + function setup() { + const mockUpdateOptions = vi.fn() + window.pendo = { + updateOptions: mockUpdateOptions, + } + + mocks.useRef.mockReturnValueOnce({ + current: { ...ownerData, ownerid: 456 }, + }) + mocks.useParams.mockReturnValue({ owner: 'codecov' }) + mocks.useOwner.mockReturnValue({ data: ownerData }) + + return { mockUpdateOptions } + } + + it('fires pendo update options when pathname is different', () => { + const { mockUpdateOptions } = setup() + renderHook(() => useUpdatePendoWithOwner(curUser)) + + expect(mockUpdateOptions).toHaveBeenCalledTimes(1) + }) +}) + +describe('update pendo when owner is not changed', () => { + function setup() { + const mockUpdateOptions = vi.fn() + window.pendo = { + updateOptions: mockUpdateOptions, + } + + mocks.useRef.mockReturnValueOnce({ current: 'codecov' }) + mocks.useParams.mockReturnValue({ owner: 'codecov' }) + mocks.useOwner.mockReturnValue({ data: ownerData }) + + return { mockUpdateOptions } + } + + it('does not fire pendo update', () => { + const { mockUpdateOptions } = setup() + renderHook(() => useUpdatePendoWithOwner(curUser)) + + expect(mockUpdateOptions).toHaveBeenCalledTimes(0) + }) +}) diff --git a/src/services/tracking/hooks.spec.js b/src/services/tracking/useTracking.test.jsx similarity index 90% rename from src/services/tracking/hooks.spec.js rename to src/services/tracking/useTracking.test.jsx index beea873269..e01edc7559 100644 --- a/src/services/tracking/hooks.spec.js +++ b/src/services/tracking/useTracking.test.jsx @@ -1,8 +1,8 @@ import * as Sentry from '@sentry/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useTracking } from './useTracking' @@ -44,16 +44,16 @@ describe('useTracking', () => { function setup(user) { window.pendo = { - initialize: jest.fn(), - updateOptions: jest.fn(), + initialize: vi.fn(), + updateOptions: vi.fn(), } server.use( - graphql.query('CurrentUser', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(user)) + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ data: user }) }), - graphql.query('DetailOwner', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: 'codecov' })) + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ data: { owner: 'codecov' } }) }) ) } @@ -182,13 +182,17 @@ describe('useTracking', () => { }) describe('when user is not logged in', () => { + let consoleSpy beforeEach(() => { - const spy = jest.spyOn(console, 'error') - spy.mockImplementation(jest.fn()) + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) setup({ me: null }) }) + afterEach(() => { + consoleSpy.mockRestore() + }) + it('sets null user in sentry', async () => { renderHook(() => useTracking(), { wrapper }) diff --git a/src/services/users/mocks.js b/src/services/users/mocks.js index 9bc65f0e27..eab5e08c9a 100644 --- a/src/services/users/mocks.js +++ b/src/services/users/mocks.js @@ -1,11 +1,11 @@ /* eslint-disable camelcase */ -import { rest } from 'msw' +import { http, HttpResponse } from 'msw2' const usersUri = '/internal/:provider/:owner/users/?activated=&is_admin=&ordering=name&search=&page=1&page_size=50' -export const randomUsersHandler = rest.get(usersUri, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(usersObject)) +export const randomUsersHandler = http.get(usersUri, (info) => { + return HttpResponse.json(usersObject) }) const usersObject = { diff --git a/src/services/users/useInfiniteUser.spec.tsx b/src/services/users/useInfiniteUser.test.tsx similarity index 87% rename from src/services/users/useInfiniteUser.spec.tsx rename to src/services/users/useInfiniteUser.test.tsx index 89ba8f17f3..ac5d16a78b 100644 --- a/src/services/users/useInfiniteUser.spec.tsx +++ b/src/services/users/useInfiniteUser.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useInfiniteUsers } from './useInfiniteUser' @@ -61,17 +62,15 @@ afterAll(() => server.close()) describe('useInfiniteUser', () => { function setup(options = {}) { server.use( - rest.get('/internal/gh/codecov/users', (req, res, ctx) => { - const { - url: { searchParams }, - } = req + http.get('/internal/gh/codecov/users', (info) => { + const searchParams = new URL(info.request.url).searchParams const pageNumber = Number(searchParams.get('page')) if (pageNumber > 1) { - return res(ctx.status(200), ctx.json(mockSecondResponse)) + return HttpResponse.json(mockSecondResponse) } - return res(ctx.status(200), ctx.json(mockFirstResponse)) + return HttpResponse.json(mockFirstResponse) }) ) } @@ -158,14 +157,21 @@ describe('useInfiniteUser', () => { }) describe('when the schema is invalid', () => { + let consoleSpy: MockInstance + beforeEach(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) server.use( - rest.get('/internal/gh/codecov/users', (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ count: 2 })) + http.get('/internal/gh/codecov/users', (info) => { + return HttpResponse.json({ count: 2 }) }) ) }) + afterEach(() => { + consoleSpy.mockRestore() + }) + it('throws an error', async () => { const { result } = renderHook( () => diff --git a/src/services/users/useUpdateUser.spec.js b/src/services/users/useUpdateUser.test.jsx similarity index 91% rename from src/services/users/useUpdateUser.spec.js rename to src/services/users/useUpdateUser.test.jsx index c1ea621f61..99671663c8 100644 --- a/src/services/users/useUpdateUser.spec.js +++ b/src/services/users/useUpdateUser.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useUpdateUser } from './useUpdateUser' @@ -45,12 +45,9 @@ afterAll(() => server.close()) describe('useUpdateUser', () => { function setup({ ownerid, body, opts = {} }) { server.use( - rest.patch( - `/internal/:provider/:owner/users/:ownerid`, - (req, res, ctx) => { - return res(ctx.status(200), ctx.json(body)) - } - ) + http.patch(`/internal/:provider/:owner/users/:ownerid`, (info) => { + return HttpResponse.json(body) + }) ) } @@ -84,7 +81,7 @@ describe('useUpdateUser', () => { }) describe('onSuccess handler', () => { - const mockSuccess = jest.fn() + const mockSuccess = vi.fn() beforeEach(() => { // pass mock response const mockRes = 'new account details data' diff --git a/src/services/users/useUsers.spec.js b/src/services/users/useUsers.test.jsx similarity index 88% rename from src/services/users/useUsers.spec.js rename to src/services/users/useUsers.test.jsx index b8750a7f9c..2cc34c2aa4 100644 --- a/src/services/users/useUsers.spec.js +++ b/src/services/users/useUsers.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useUsers } from './useUsers' @@ -55,26 +55,31 @@ const wrapper = ) const server = setupServer() +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +afterAll(() => { + server.close() +}) describe('useUsers', () => { function setup() { server.use( - rest.get(`/internal/:provider/:owner/users`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(users)) + http.get(`/internal/:provider/:owner/users`, (info) => { + return HttpResponse.json(users) }) ) } describe('when data is loaded', () => { - beforeEach(() => { - setup() - }) - it('returns the users data', async () => { + setup() const { result } = renderHook( () => useUsers({ provider, owner, query }), { From 2b5e4a789f1aa044dd0317c13649237559cebdd6 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 08:52:55 -0400 Subject: [PATCH 20/20] chore: Update services/charts tests to Vitest (#3299) --- codecov.yml | 2 ++ src/services/charts/{index.js => index.ts} | 0 src/services/charts/{mocks.js => mocks.ts} | 18 +++++----- ...=> useBranchCoverageMeasurements.test.tsx} | 35 ++++++++++--------- ...spec.js => useLegacyRepoCoverage.test.jsx} | 12 +++++-- ... => useReposCoverageMeasurements.test.tsx} | 10 +++--- ....spec.tsx => useSunburstCoverage.test.tsx} | 35 ++++++++++--------- vitest.config.mjs | 1 + 8 files changed, 63 insertions(+), 50 deletions(-) rename src/services/charts/{index.js => index.ts} (100%) rename src/services/charts/{mocks.js => mocks.ts} (78%) rename src/services/charts/{useBranchCoverageMeasurements.spec.tsx => useBranchCoverageMeasurements.test.tsx} (87%) rename src/services/charts/{useLegacyRepoCoverage.spec.js => useLegacyRepoCoverage.test.jsx} (92%) rename src/services/charts/{useReposCoverageMeasurements.spec.tsx => useReposCoverageMeasurements.test.tsx} (91%) rename src/services/charts/{useSunburtsCoverage.spec.tsx => useSunburstCoverage.test.tsx} (87%) diff --git a/codecov.yml b/codecov.yml index 48617e04e2..e78ce70e70 100644 --- a/codecov.yml +++ b/codecov.yml @@ -49,6 +49,8 @@ ignore: - './src/**/*.svg' - './src/**/*.png' - './src/**/*.jpg' + - ./src/**/*.mocks.js + - ./src/**/*.mocks.ts component_management: default_rules: diff --git a/src/services/charts/index.js b/src/services/charts/index.ts similarity index 100% rename from src/services/charts/index.js rename to src/services/charts/index.ts diff --git a/src/services/charts/mocks.js b/src/services/charts/mocks.ts similarity index 78% rename from src/services/charts/mocks.js rename to src/services/charts/mocks.ts index 53d90646e4..82046461eb 100644 --- a/src/services/charts/mocks.js +++ b/src/services/charts/mocks.ts @@ -1,25 +1,25 @@ /* eslint-disable camelcase */ -import { rest } from 'msw' +import { http, HttpResponse } from 'msw2' const repoUri = '/internal/charts/:provider/:owner/coverage/repository' -export const repoCoverageHandler = rest.post(repoUri, (req, res, ctx) => { - return res(ctx.status(200), ctx.json(exampleYearlyRes)) +export const repoCoverageHandler = http.post(repoUri, (info) => { + return HttpResponse.json(exampleYearlyRes) }) -export const repoCoverageHandler404 = rest.post(repoUri, (req, res, ctx) => { - return res(ctx.status(404), ctx.json({})) +export const repoCoverageHandler404 = http.post(repoUri, (info) => { + return HttpResponse.json({}, { status: 404 }) }) const orgUri = '/internal/charts/:provider/:owner/coverage/organization' -export const orgCoverageHandler = rest.get(orgUri, (req, res, ctx) => { +export const orgCoverageHandler = http.get(orgUri, (info) => { // This is maybe a bit redundant atm but I would like to test some data mutation utils later - const query = req.url.searchParams + const query = new URL(info.request.url).searchParams if (query.get('grouping_unit') === 'yearly') { - return res(ctx.status(200), ctx.json(exampleYearlyRes)) + return HttpResponse.json(exampleYearlyRes) } else if (query.get('grouping_unit') === 'quarterly') { - return res(ctx.status(200), ctx.json(exampleQuarterRes)) + return HttpResponse.json(exampleQuarterRes) } }) diff --git a/src/services/charts/useBranchCoverageMeasurements.spec.tsx b/src/services/charts/useBranchCoverageMeasurements.test.tsx similarity index 87% rename from src/services/charts/useBranchCoverageMeasurements.spec.tsx rename to src/services/charts/useBranchCoverageMeasurements.test.tsx index e56e03efb2..4b39b60a6d 100644 --- a/src/services/charts/useBranchCoverageMeasurements.spec.tsx +++ b/src/services/charts/useBranchCoverageMeasurements.test.tsx @@ -1,7 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' +import { type MockInstance } from 'vitest' import { useBranchCoverageMeasurements } from './useBranchCoverageMeasurements' @@ -96,17 +97,17 @@ describe('useBranchCoverageMeasurements', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetBranchCoverageMeasurements', (req, res, ctx) => { + graphql.query('GetBranchCoverageMeasurements', (info) => { if (isNotFoundError) { - return res(ctx.status(200), ctx.data(mockNotFoundError)) + return HttpResponse.json({ data: mockNotFoundError }) } else if (isOwnerNotActivatedError) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + return HttpResponse.json({ data: mockOwnerNotActivatedError }) } else if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else if (isNullOwner) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } else { - return res(ctx.status(200), ctx.data(mockBranchMeasurements)) + return HttpResponse.json({ data: mockBranchMeasurements }) } }) ) @@ -184,14 +185,14 @@ describe('useBranchCoverageMeasurements', () => { }) describe('returns NotFoundError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { @@ -222,14 +223,14 @@ describe('useBranchCoverageMeasurements', () => { }) describe('returns OwnerNotActivatedError __typename', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 403', async () => { @@ -260,14 +261,14 @@ describe('useBranchCoverageMeasurements', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error + let consoleSpy: MockInstance beforeEach(() => { - console.error = () => null + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => null) }) afterEach(() => { - console.error = oldConsoleError + consoleSpy.mockRestore() }) it('throws a 404', async () => { diff --git a/src/services/charts/useLegacyRepoCoverage.spec.js b/src/services/charts/useLegacyRepoCoverage.test.jsx similarity index 92% rename from src/services/charts/useLegacyRepoCoverage.spec.js rename to src/services/charts/useLegacyRepoCoverage.test.jsx index e391ee2bd8..5dd88d9869 100644 --- a/src/services/charts/useLegacyRepoCoverage.spec.js +++ b/src/services/charts/useLegacyRepoCoverage.test.jsx @@ -1,6 +1,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { setupServer } from 'msw/node' +import { setupServer } from 'msw2/node' import { repoCoverageHandler } from './mocks' @@ -16,12 +16,18 @@ const wrapper = ({ children }) => ( const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + afterEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) const exampleYearlyHookData = { coverage: [ diff --git a/src/services/charts/useReposCoverageMeasurements.spec.tsx b/src/services/charts/useReposCoverageMeasurements.test.tsx similarity index 91% rename from src/services/charts/useReposCoverageMeasurements.spec.tsx rename to src/services/charts/useReposCoverageMeasurements.test.tsx index 0f36895138..1d82254bdb 100644 --- a/src/services/charts/useReposCoverageMeasurements.spec.tsx +++ b/src/services/charts/useReposCoverageMeasurements.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { useReposCoverageMeasurements } from './useReposCoverageMeasurements' @@ -51,12 +51,12 @@ afterAll(() => { describe('useReposCoverageMeasurements', () => { function setup({ hasNoData = false }: { hasNoData: boolean }) { server.use( - graphql.query('GetReposCoverageMeasurements', (req, res, ctx) => { + graphql.query('GetReposCoverageMeasurements', (info) => { if (hasNoData) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({ data: {} }) } - return res(ctx.status(200), ctx.data(mockReposMeasurements)) + return HttpResponse.json({ data: mockReposMeasurements }) }) ) } diff --git a/src/services/charts/useSunburtsCoverage.spec.tsx b/src/services/charts/useSunburstCoverage.test.tsx similarity index 87% rename from src/services/charts/useSunburtsCoverage.spec.tsx rename to src/services/charts/useSunburstCoverage.test.tsx index d532b4e91d..589656a016 100644 --- a/src/services/charts/useSunburtsCoverage.spec.tsx +++ b/src/services/charts/useSunburstCoverage.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { rest } from 'msw' -import { setupServer } from 'msw/node' +import { http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { useSunburstCoverage } from './index' @@ -21,13 +21,18 @@ const wrapper = ) const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) afterEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) const exampleResponse = [ { @@ -87,19 +92,17 @@ const filteredResponse = [ describe('useSunburstCoverage', () => { beforeEach(() => { server.use( - rest.get( - '/internal/:provider/:owner/:repo/coverage/tree', - (req, res, ctx) => { - const flags = req.url.searchParams.getAll('flags') - const components = req.url.searchParams.getAll('components') - - if (flags.length > 0 || components.length > 0) { - return res(ctx.status(200), ctx.json(filteredResponse)) - } else { - return res(ctx.status(200), ctx.json(exampleResponse)) - } + http.get('/internal/:provider/:owner/:repo/coverage/tree', (info) => { + const searchParams = new URL(info.request.url).searchParams + const flags = searchParams.getAll('flags') + const components = searchParams.getAll('components') + + if (flags.length > 0 || components.length > 0) { + return HttpResponse.json(filteredResponse) + } else { + return HttpResponse.json(exampleResponse) } - ) + }) ) }) diff --git a/vitest.config.mjs b/vitest.config.mjs index 35e591886f..9ed0d9abc3 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -14,6 +14,7 @@ const EXCLUDE_FROM_TESTING = [ // Custom exclude patterns 'src/**/*.spec.*', 'src/**/*.stories.*', + 'src/**/*.mocks.*', ] const EXCLUDE_FROM_COVERAGE = [