From e57c88f476bddb195d69c814164859c37cc3e329 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 16:23:51 -0300 Subject: [PATCH 01/44] chore: Update ui/Dropdown tests to Vitest (#3256) --- src/ui/Dropdown/{Dropdown.spec.tsx => Dropdown.test.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ui/Dropdown/{Dropdown.spec.tsx => Dropdown.test.tsx} (100%) diff --git a/src/ui/Dropdown/Dropdown.spec.tsx b/src/ui/Dropdown/Dropdown.test.tsx similarity index 100% rename from src/ui/Dropdown/Dropdown.spec.tsx rename to src/ui/Dropdown/Dropdown.test.tsx From 6fe837bc549da43aa029f88192ecceaa6143d7ae Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 16:33:51 -0300 Subject: [PATCH 02/44] chore: Update ui/DateRangePicker to Vitest (#3257) --- ...cker.spec.tsx => DateRangePicker.test.tsx} | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) rename src/ui/DateRangePicker/{DateRangePicker.spec.tsx => DateRangePicker.test.tsx} (85%) diff --git a/src/ui/DateRangePicker/DateRangePicker.spec.tsx b/src/ui/DateRangePicker/DateRangePicker.test.tsx similarity index 85% rename from src/ui/DateRangePicker/DateRangePicker.spec.tsx rename to src/ui/DateRangePicker/DateRangePicker.test.tsx index 0f23269eeb..7c222fcad7 100644 --- a/src/ui/DateRangePicker/DateRangePicker.spec.tsx +++ b/src/ui/DateRangePicker/DateRangePicker.test.tsx @@ -2,23 +2,28 @@ import { render, screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import DateRangePicker from './DateRangePicker' -;(() => { - return (global.ResizeObserver = class ResizeObserver { - [x: string]: any - constructor(cb: any) { - this.cb = cb - } - observe() { - this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]) - } - unobserve() {} - disconnect() {} - } as any) -})() + +class ResizeObserverMock { + [x: string]: any + constructor(cb: any) { + this.cb = cb + } + observe() { + this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]) + } + unobserve() { + // do nothing + } + disconnect() { + // do nothing + } +} + +global.window.ResizeObserver = ResizeObserverMock describe('DateRangePicker', () => { function setup(addedProps?: {}) { - const mockOnChange = jest.fn() + const mockOnChange = vi.fn() const user = userEvent.setup() const props = { From 6f8da5679b5b470670fac34bc3af3b9e2c6fc1f2 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 16:41:48 -0300 Subject: [PATCH 03/44] chore: Update ui/CoverageProgress to Vitest (#3258) --- .../{CoverageProgress.spec.tsx => CoverageProgress.test.tsx} | 0 src/ui/CoverageProgress/{index.js => index.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/ui/CoverageProgress/{CoverageProgress.spec.tsx => CoverageProgress.test.tsx} (100%) rename src/ui/CoverageProgress/{index.js => index.ts} (100%) diff --git a/src/ui/CoverageProgress/CoverageProgress.spec.tsx b/src/ui/CoverageProgress/CoverageProgress.test.tsx similarity index 100% rename from src/ui/CoverageProgress/CoverageProgress.spec.tsx rename to src/ui/CoverageProgress/CoverageProgress.test.tsx diff --git a/src/ui/CoverageProgress/index.js b/src/ui/CoverageProgress/index.ts similarity index 100% rename from src/ui/CoverageProgress/index.js rename to src/ui/CoverageProgress/index.ts From 2721c762c24d72b44f8d049af49197b222956389 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 16:50:31 -0300 Subject: [PATCH 04/44] chore: Update ui/CoverageAreaChart to Vitest (#3259) --- ...reaChart.spec.jsx => CoverageAreaChart.test.jsx} | 13 +++++++------ src/ui/CoverageAreaChart/{index.js => index.ts} | 0 2 files changed, 7 insertions(+), 6 deletions(-) rename src/ui/CoverageAreaChart/{CoverageAreaChart.spec.jsx => CoverageAreaChart.test.jsx} (91%) rename src/ui/CoverageAreaChart/{index.js => index.ts} (100%) diff --git a/src/ui/CoverageAreaChart/CoverageAreaChart.spec.jsx b/src/ui/CoverageAreaChart/CoverageAreaChart.test.jsx similarity index 91% rename from src/ui/CoverageAreaChart/CoverageAreaChart.spec.jsx rename to src/ui/CoverageAreaChart/CoverageAreaChart.test.jsx index 720d61a320..8c3e0274b7 100644 --- a/src/ui/CoverageAreaChart/CoverageAreaChart.spec.jsx +++ b/src/ui/CoverageAreaChart/CoverageAreaChart.test.jsx @@ -5,10 +5,11 @@ import CoverageAreaChart from './CoverageAreaChart' describe('Coverage Area Chart', () => { describe('No coverage data exists', () => { beforeEach(() => { - jest.useFakeTimers().setSystemTime(new Date('2020-04-01')) + vi.useFakeTimers().setSystemTime(new Date('2020-04-01')) }) + afterAll(() => { - jest.useRealTimers() + vi.useRealTimers() }) it('renders no chart', () => { @@ -21,10 +22,10 @@ describe('Coverage Area Chart', () => { describe('Chart with data', () => { beforeEach(() => { - jest.useFakeTimers().setSystemTime(new Date('2020-04-01')) + vi.useFakeTimers().setSystemTime(new Date('2020-04-01')) }) afterAll(() => { - jest.useRealTimers() + vi.useRealTimers() }) it('renders victory', () => { @@ -81,10 +82,10 @@ describe('Coverage Area Chart', () => { describe('Not enough data to render', () => { beforeEach(() => { - jest.useFakeTimers().setSystemTime(new Date('2020-04-01')) + vi.useFakeTimers().setSystemTime(new Date('2020-04-01')) }) afterAll(() => { - jest.useRealTimers() + vi.useRealTimers() }) it('renders victory', () => { diff --git a/src/ui/CoverageAreaChart/index.js b/src/ui/CoverageAreaChart/index.ts similarity index 100% rename from src/ui/CoverageAreaChart/index.js rename to src/ui/CoverageAreaChart/index.ts From 63111c74e2f14ed83002f1bc344c562d9a4f9916 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 16:54:58 -0300 Subject: [PATCH 05/44] chore: Update ui/CopyClipboard to Vitest (#3260) --- ...pboard.spec.tsx => CopyClipboard.test.tsx} | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) rename src/ui/CopyClipboard/{CopyClipboard.spec.tsx => CopyClipboard.test.tsx} (67%) diff --git a/src/ui/CopyClipboard/CopyClipboard.spec.tsx b/src/ui/CopyClipboard/CopyClipboard.test.tsx similarity index 67% rename from src/ui/CopyClipboard/CopyClipboard.spec.tsx rename to src/ui/CopyClipboard/CopyClipboard.test.tsx index 4c20f40993..90fbca7208 100644 --- a/src/ui/CopyClipboard/CopyClipboard.spec.tsx +++ b/src/ui/CopyClipboard/CopyClipboard.test.tsx @@ -1,17 +1,30 @@ -import { act, render, screen, waitFor } from 'custom-testing-library' - +import { act, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { CopyClipboard } from './CopyClipboard' -jest.mock('copy-to-clipboard', () => () => true) +vi.mock('copy-to-clipboard', () => ({ default: () => true })) describe('CopyClipboard', () => { - beforeAll(() => jest.useFakeTimers()) - afterAll(() => jest.useRealTimers()) + beforeAll(() => { + vi.useFakeTimers() + }) + + afterAll(() => { + vi.restoreAllMocks() + }) function setup() { - const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }) + // This is a bit of a hack to get Vitest fake timers setup with userEvents properly + // GH Issue: https://github.com/testing-library/react-testing-library/issues/1197#issuecomment-1693824628 + globalThis.jest = { + ...globalThis.jest, + advanceTimersByTime: vi.advanceTimersByTime.bind(vi), + } + + const user = userEvent.setup({ + advanceTimers: globalThis.jest.advanceTimersByTime, + }) return { user } } @@ -19,7 +32,7 @@ describe('CopyClipboard', () => { it('renders the button with clipboard icon', () => { render() - const clipboard = screen.getByText(/clipboard-copy/, { exact: true }) + const clipboard = screen.getByLabelText('Copy to be copied') expect(clipboard).toBeInTheDocument() }) @@ -29,11 +42,11 @@ describe('CopyClipboard', () => { render() const button = screen.getByRole('button', { - name: /copy/i, + name: 'Copy to be copied', }) await user.click(button) - const success = screen.getByText(/check/, { exact: true }) + const success = screen.getByTestId('check') expect(success).toBeInTheDocument() }) @@ -43,18 +56,16 @@ describe('CopyClipboard', () => { render() const button = screen.getByRole('button', { - name: /copy/i, + name: 'Copy to be copied', }) await user.click(button) - const success = await screen.findByText(/check/, { exact: true }) + const success = await screen.findByTestId('check') expect(success).toBeInTheDocument() - act(() => jest.advanceTimersByTime(1500)) + act(() => vi.advanceTimersByTime(1500)) - const clipboard = await screen.findByText(/clipboard-copy/, { - exact: true, - }) + const clipboard = await screen.findByTestId('clipboardCopy') expect(clipboard).toBeInTheDocument() }) @@ -81,7 +92,7 @@ describe('CopyClipboard', () => { describe('when onClick prop is set', () => { it('calls the function when button is clicked', async () => { const { user } = setup() - const callback = jest.fn() + const callback = vi.fn() render() const button = screen.getByRole('button', { From 1d2a9da97b2c0abe65d6159161b2146e7e9dbc1e Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 17:09:36 -0300 Subject: [PATCH 06/44] chore: Update ui/ContextSwitcher tests to Vitest (#3261) --- ...cher.spec.jsx => ContextSwitcher.test.jsx} | 79 +++++++++++++------ 1 file changed, 57 insertions(+), 22 deletions(-) rename src/ui/ContextSwitcher/{ContextSwitcher.spec.jsx => ContextSwitcher.test.jsx} (93%) diff --git a/src/ui/ContextSwitcher/ContextSwitcher.spec.jsx b/src/ui/ContextSwitcher/ContextSwitcher.test.jsx similarity index 93% rename from src/ui/ContextSwitcher/ContextSwitcher.spec.jsx rename to src/ui/ContextSwitcher/ContextSwitcher.test.jsx index f7bdce7edb..2e0d59e25e 100644 --- a/src/ui/ContextSwitcher/ContextSwitcher.spec.jsx +++ b/src/ui/ContextSwitcher/ContextSwitcher.test.jsx @@ -1,17 +1,27 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, render, screen, waitFor } 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 { MemoryRouter, Route, Switch } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import { useImage } from 'services/image' import ContextSwitcher from './ContextSwitcher' -jest.mock('react-use/lib/useIntersection') -jest.mock('services/image') +vi.mock('services/image') +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), +})) + +vi.mock('react-use', async () => { + const original = await vi.importActual('react-use') + + return { + ...original, + useIntersection: mocks.useIntersection, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -48,22 +58,27 @@ const wrapper = describe('ContextSwitcher', () => { function setup() { const user = userEvent.setup() - const mutate = jest.fn() + const mutate = vi.fn() useImage.mockReturnValue({ src: 'imageUrl', isLoading: false, error: null }) server.use( - graphql.mutation('updateDefaultOrganization', (req, res, ctx) => { - mutate(req.variables) + graphql.mutation('updateDefaultOrganization', (info) => { + mutate(info.variables) - return res(ctx.status(200), ctx.json({ username: 'spotify' })) + return HttpResponse.json({ data: { username: 'spotify' } }) }) ) return { user, mutate } } describe('when rendered', () => { - beforeEach(() => setup()) - afterEach(() => jest.restoreAllMocks()) + beforeEach(() => { + setup() + }) + + afterEach(() => { + vi.clearAllMocks() + }) it('does not render the listed items initially', () => { render( @@ -112,7 +127,9 @@ describe('ContextSwitcher', () => { }) describe('when the button is clicked', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('renders the menu', async () => { const { user } = setup() @@ -234,8 +251,13 @@ describe('ContextSwitcher', () => { }) describe('when rendered with no active context', () => { - beforeEach(() => setup()) - afterEach(() => jest.restoreAllMocks()) + beforeEach(() => { + setup() + }) + + afterEach(() => { + vi.clearAllMocks() + }) it('renders manage access restrictions', async () => { render( @@ -290,7 +312,9 @@ describe('ContextSwitcher', () => { describe('when isLoading is passed', () => { describe('isLoading set to true', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('renders spinner', async () => { const { user } = setup() @@ -343,7 +367,9 @@ describe('ContextSwitcher', () => { }) }) describe('isLoading set to false', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('does not render spinner', async () => { const { user } = setup() @@ -399,13 +425,16 @@ describe('ContextSwitcher', () => { describe('when onLoadMore is passed and is intersecting', () => { beforeEach(() => { - useIntersection.mockReturnValue({ isIntersecting: true }) + mocks.useIntersection.mockReturnValue({ isIntersecting: true }) + }) + + afterEach(() => { + vi.clearAllMocks() }) - afterEach(() => jest.restoreAllMocks()) it('calls onLoadMore', async () => { const { user } = setup() - const onLoadMoreFunc = jest.fn() + const onLoadMoreFunc = vi.fn() render( { }) describe('when not on gh provider', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('does not render the add github org text', async () => { setup() @@ -493,7 +524,9 @@ describe('ContextSwitcher', () => { }) describe('when custom modal component is passed', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('renders the modal component', async () => { setup() @@ -540,7 +573,9 @@ describe('ContextSwitcher', () => { }) describe('when user clicks on an org', () => { - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) it('fires update org mutation', async () => { const { user, mutate } = setup() From bf3aaacfddbcb4ee6af92cd3fedaf3faf0d51c11 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 17:30:16 -0300 Subject: [PATCH 07/44] chore: Update ui/CodeSnippet tests to Vitest (#3262) --- .../{CodeSnippet.spec.tsx => CodeSnippet.test.tsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/ui/CodeSnippet/{CodeSnippet.spec.tsx => CodeSnippet.test.tsx} (94%) diff --git a/src/ui/CodeSnippet/CodeSnippet.spec.tsx b/src/ui/CodeSnippet/CodeSnippet.test.tsx similarity index 94% rename from src/ui/CodeSnippet/CodeSnippet.spec.tsx rename to src/ui/CodeSnippet/CodeSnippet.test.tsx index 7080e8ecd6..edf1e92c2a 100644 --- a/src/ui/CodeSnippet/CodeSnippet.spec.tsx +++ b/src/ui/CodeSnippet/CodeSnippet.test.tsx @@ -3,7 +3,7 @@ import { userEvent } from '@testing-library/user-event' import { CodeSnippet } from './CodeSnippet' -jest.mock('copy-to-clipboard', () => () => true) +vi.mock('copy-to-clipboard', () => ({ default: () => true })) describe('CodeSnippet', () => { function setup() { @@ -49,7 +49,7 @@ wow`} it('passes clipboardOnClick through to CopyClipboard', async () => { const { user } = setup() - const callback = jest.fn() + const callback = vi.fn() render( asdf From ddbab4b38708fb9378ffbb2cbadb185b0082717d Mon Sep 17 00:00:00 2001 From: Spencer Murray <159931558+spalmurray-codecov@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:34:57 -0400 Subject: [PATCH 08/44] feat: Add new checkbox component (#3321) --- package.json | 3 +- src/ui/Checkbox/CheckboxNew.stories.tsx | 48 +++++++++++++++++++++++++ src/ui/Checkbox/CheckboxNew.test.tsx | 40 +++++++++++++++++++++ src/ui/Checkbox/CheckboxNew.tsx | 34 ++++++++++++++++++ yarn.lock | 27 ++++++++++++++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/ui/Checkbox/CheckboxNew.stories.tsx create mode 100644 src/ui/Checkbox/CheckboxNew.test.tsx create mode 100644 src/ui/Checkbox/CheckboxNew.tsx diff --git a/package.json b/package.json index 8f9a000aab..cb22525f0f 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "test:mutation": "npx stryker run", "eject": "craco eject", "lint": "eslint --fix --no-ignore --max-warnings=-1 -c .eslintrc.json", - "storybook": "storybook dev -p 6006", + "storybook": "yarn generate-icons:webpack && storybook dev -p 6006", "build-storybook": "storybook build", "chromatic": "npx chromatic --exit-zero-on-changes -ci", "format-staged": "npx prettier --write 'src/**/*.{js,jsx,ts,tsx,css,md}'", @@ -53,6 +53,7 @@ "dependencies": { "@hookform/resolvers": "^2.8.5", "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-label": "^2.0.2", diff --git a/src/ui/Checkbox/CheckboxNew.stories.tsx b/src/ui/Checkbox/CheckboxNew.stories.tsx new file mode 100644 index 0000000000..2a5387c15b --- /dev/null +++ b/src/ui/Checkbox/CheckboxNew.stories.tsx @@ -0,0 +1,48 @@ +import { Meta, StoryObj } from '@storybook/react' + +import { CheckboxNew } from './CheckboxNew' + +const meta: Meta = { + title: 'Components/CheckboxNew', + component: CheckboxNew, + argTypes: { + value: { + description: 'Controlled state checked status.', + control: 'boolean', + }, + }, +} +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => ( + <> + + + ), +} + +export const Disabled: Story = { + render: (args) => ( + <> + + + ), +} + +export const DisabledAndChecked: Story = { + render: () => ( + <> + + + ), +} + +export const ControlledState: Story = { + args: { + checked: true, + }, + render: (args) => , +} diff --git a/src/ui/Checkbox/CheckboxNew.test.tsx b/src/ui/Checkbox/CheckboxNew.test.tsx new file mode 100644 index 0000000000..fe662f9fb0 --- /dev/null +++ b/src/ui/Checkbox/CheckboxNew.test.tsx @@ -0,0 +1,40 @@ +import { render, screen, waitFor } from '@testing-library/react' +import { userEvent } from '@testing-library/user-event' + +import { CheckboxNew } from './CheckboxNew' + +describe('Checkbox', () => { + it('renders', async () => { + render() + const checkbox = await screen.findByRole('checkbox') + expect(checkbox).toBeInTheDocument() + }) + + it('becomes checked when clicked', async () => { + const user = userEvent.setup() + render() + const checkbox = await screen.findByRole('checkbox') + expect(checkbox).toBeInTheDocument() + expect(checkbox).toHaveAttribute('data-state', 'unchecked') + + await user.click(checkbox) + + await waitFor(() => + expect(checkbox).toHaveAttribute('data-state', 'checked') + ) + }) + + it('can be disabled', async () => { + render() + const checkbox = await screen.findByRole('checkbox') + expect(checkbox).toBeInTheDocument() + expect(checkbox).toHaveAttribute('disabled') + }) + + it('can have controlled state', async () => { + render() + const checkbox = await screen.findByRole('checkbox') + expect(checkbox).toBeInTheDocument() + expect(checkbox).toHaveAttribute('data-state', 'checked') + }) +}) diff --git a/src/ui/Checkbox/CheckboxNew.tsx b/src/ui/Checkbox/CheckboxNew.tsx new file mode 100644 index 0000000000..bebd4e8c18 --- /dev/null +++ b/src/ui/Checkbox/CheckboxNew.tsx @@ -0,0 +1,34 @@ +import * as CheckboxPrimitive from '@radix-ui/react-checkbox' +import React from 'react' + +import { cn } from 'shared/utils/cn' +import Icon from 'ui/Icon' + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox as CheckboxNew } diff --git a/yarn.lock b/yarn.lock index 1cd45b304c..8f2e044693 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3607,6 +3607,32 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-checkbox@npm:^1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-checkbox@npm:1.1.1" + dependencies: + "@radix-ui/primitive": "npm:1.1.0" + "@radix-ui/react-compose-refs": "npm:1.1.0" + "@radix-ui/react-context": "npm:1.1.0" + "@radix-ui/react-presence": "npm:1.1.0" + "@radix-ui/react-primitive": "npm:2.0.0" + "@radix-ui/react-use-controllable-state": "npm:1.1.0" + "@radix-ui/react-use-previous": "npm:1.1.0" + "@radix-ui/react-use-size": "npm:1.1.0" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/2d7d35b8319298166905057e9f7fb1d4b51d73bdec6c7c2127d2266e0f053c39586e316ea0da9a24612dfa86b8fc1f5160d4c37f79ae567025b62616de95c2c7 + languageName: node + linkType: hard + "@radix-ui/react-collapsible@npm:1.1.0, @radix-ui/react-collapsible@npm:^1.0.3": version: 1.1.0 resolution: "@radix-ui/react-collapsible@npm:1.1.0" @@ -11704,6 +11730,7 @@ __metadata: "@craco/craco": "npm:^7.1.0" "@hookform/resolvers": "npm:^2.8.5" "@radix-ui/react-accordion": "npm:^1.1.2" + "@radix-ui/react-checkbox": "npm:^1.1.1" "@radix-ui/react-collapsible": "npm:^1.0.3" "@radix-ui/react-dropdown-menu": "npm:^2.1.1" "@radix-ui/react-label": "npm:^2.0.2" From 72fcd08a5b4457f892f34cf26c962296e2d55cbc Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Thu, 26 Sep 2024 17:38:40 -0300 Subject: [PATCH 09/44] chore: Update ui/FileViewer to Vitest (#3263) --- ...elect.spec.tsx => CoverageSelect.test.tsx} | 0 .../Title/{Title.spec.tsx => Title.test.tsx} | 41 ++++++++++++------- ...eHeader.spec.tsx => ToggleHeader.test.tsx} | 25 +++++++---- .../ToggleHeader/{index.js => index.ts} | 0 4 files changed, 44 insertions(+), 22 deletions(-) rename src/ui/FileViewer/ToggleHeader/Title/{CoverageSelect.spec.tsx => CoverageSelect.test.tsx} (100%) rename src/ui/FileViewer/ToggleHeader/Title/{Title.spec.tsx => Title.test.tsx} (91%) rename src/ui/FileViewer/ToggleHeader/{ToggleHeader.spec.tsx => ToggleHeader.test.tsx} (86%) rename src/ui/FileViewer/ToggleHeader/{index.js => index.ts} (100%) diff --git a/src/ui/FileViewer/ToggleHeader/Title/CoverageSelect.spec.tsx b/src/ui/FileViewer/ToggleHeader/Title/CoverageSelect.test.tsx similarity index 100% rename from src/ui/FileViewer/ToggleHeader/Title/CoverageSelect.spec.tsx rename to src/ui/FileViewer/ToggleHeader/Title/CoverageSelect.test.tsx diff --git a/src/ui/FileViewer/ToggleHeader/Title/Title.spec.tsx b/src/ui/FileViewer/ToggleHeader/Title/Title.test.tsx similarity index 91% rename from src/ui/FileViewer/ToggleHeader/Title/Title.spec.tsx rename to src/ui/FileViewer/ToggleHeader/Title/Title.test.tsx index 763c700a0b..b2fc0e39f9 100644 --- a/src/ui/FileViewer/ToggleHeader/Title/Title.spec.tsx +++ b/src/ui/FileViewer/ToggleHeader/Title/Title.test.tsx @@ -1,16 +1,25 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import Title, { TitleFlags, TitleHitCount } from './Title' -jest.mock('shared/featureFlags') -jest.mock('react-use/lib/useIntersection') -const mockedUseIntersection = useIntersection as jest.Mock +vi.mock('shared/featureFlags') +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), +})) + +vi.mock('react-use', async () => { + const original = await vi.importActual('react-use') + + return { + ...original, + useIntersection: mocks.useIntersection, + } +}) const mockFirstResponse = { owner: { @@ -197,22 +206,24 @@ describe('TitleFlags', () => { } ) { const user = userEvent.setup() - const mockApiVars = jest.fn() + const mockApiVars = vi.fn() - mockedUseIntersection.mockReturnValue({ isIntersecting: isIntersecting }) + mocks.useIntersection.mockReturnValue({ + isIntersecting: isIntersecting, + }) server.use( - graphql.query('FlagsSelect', (req, res, ctx) => { - mockApiVars(req.variables) + graphql.query('FlagsSelect', (info) => { + mockApiVars(info.variables) - if (!!req.variables?.after || noNextPage) { - return res(ctx.status(200), ctx.data(mockSecondResponse)) + if (!!info.variables?.after || noNextPage) { + return HttpResponse.json({ data: mockSecondResponse }) } - return res(ctx.status(200), ctx.data(mockFirstResponse)) + return HttpResponse.json({ data: mockFirstResponse }) }), - graphql.query('BackfillFlagMemberships', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(backfillData)) + graphql.query('BackfillFlagMemberships', (info) => { + return HttpResponse.json({ data: backfillData }) }) ) diff --git a/src/ui/FileViewer/ToggleHeader/ToggleHeader.spec.tsx b/src/ui/FileViewer/ToggleHeader/ToggleHeader.test.tsx similarity index 86% rename from src/ui/FileViewer/ToggleHeader/ToggleHeader.spec.tsx rename to src/ui/FileViewer/ToggleHeader/ToggleHeader.test.tsx index 87474c6e4e..79daf37b3e 100644 --- a/src/ui/FileViewer/ToggleHeader/ToggleHeader.spec.tsx +++ b/src/ui/FileViewer/ToggleHeader/ToggleHeader.test.tsx @@ -1,12 +1,23 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 ToggleHeader from './ToggleHeader' -jest.mock('react-use/lib/useIntersection') +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), +})) + +vi.mock('react-use', async () => { + const original = await vi.importActual('react-use') + + return { + ...original, + useIntersection: mocks.useIntersection, + } +}) const mockFlagResponse = { owner: { @@ -69,11 +80,11 @@ afterAll(() => { describe('ToggleHeader', () => { function setup() { server.use( - graphql.query('BackfillFlagMemberships', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBackfillResponse)) + graphql.query('BackfillFlagMemberships', (info) => { + return HttpResponse.json({ data: mockBackfillResponse }) }), - graphql.query('FlagsSelect', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockFlagResponse)) + graphql.query('FlagsSelect', (info) => { + return HttpResponse.json({ data: mockFlagResponse }) }) ) } diff --git a/src/ui/FileViewer/ToggleHeader/index.js b/src/ui/FileViewer/ToggleHeader/index.ts similarity index 100% rename from src/ui/FileViewer/ToggleHeader/index.js rename to src/ui/FileViewer/ToggleHeader/index.ts From f2a4d490f92de66c2a5f9152d159c90428e141cf Mon Sep 17 00:00:00 2001 From: Spencer Murray <159931558+spalmurray-codecov@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:46:12 -0400 Subject: [PATCH 10/44] ref: Remove old checkbox component (#3325) --- .../CommitCoverage/UploadsCard/Upload.jsx | 15 ++--- src/ui/Checkbox/Checkbox.jsx | 49 --------------- src/ui/Checkbox/Checkbox.stories.jsx | 60 ------------------- ...oxNew.stories.tsx => Checkbox.stories.tsx} | 18 +++--- src/ui/Checkbox/Checkbox.test.jsx | 14 ----- ...CheckboxNew.test.tsx => Checkbox.test.tsx} | 10 ++-- src/ui/Checkbox/Checkbox.tsx | 34 +++++++++++ src/ui/Checkbox/{index.js => index.ts} | 0 8 files changed, 56 insertions(+), 144 deletions(-) delete mode 100644 src/ui/Checkbox/Checkbox.jsx delete mode 100644 src/ui/Checkbox/Checkbox.stories.jsx rename src/ui/Checkbox/{CheckboxNew.stories.tsx => Checkbox.stories.tsx} (59%) delete mode 100644 src/ui/Checkbox/Checkbox.test.jsx rename src/ui/Checkbox/{CheckboxNew.test.tsx => Checkbox.test.tsx} (85%) create mode 100644 src/ui/Checkbox/Checkbox.tsx rename src/ui/Checkbox/{index.js => index.ts} (100%) diff --git a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx index 7015e31385..8c35144abc 100644 --- a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx +++ b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.jsx @@ -39,19 +39,20 @@ const Upload = ({ { - if (!!e.target.checked) { - queryClient.setQueryData(['IgnoredUploadIds'], (oldData) => - without(oldData, id) - ) - } else { + onClick={() => { + if (checked) { + // User is unchecking queryClient.setQueryData(['IgnoredUploadIds'], (oldData) => [ ...(oldData ?? []), id, ]) + } else { + queryClient.setQueryData(['IgnoredUploadIds'], (oldData) => + without(oldData, id) + ) } - setChecked((c) => !c) + setChecked(!checked) }} /> diff --git a/src/ui/Checkbox/Checkbox.jsx b/src/ui/Checkbox/Checkbox.jsx deleted file mode 100644 index 98d1517c27..0000000000 --- a/src/ui/Checkbox/Checkbox.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import cs from 'classnames' -import uniqueId from 'lodash/uniqueId' -import PropTypes from 'prop-types' -import { forwardRef } from 'react' - -import { dataMarketingType } from 'shared/propTypes' - -const Checkbox = forwardRef( - ({ label, showLabel = true, disabled, ...props }, ref) => { - const id = uniqueId('radio-input') - const { className, dataMarketing, ...newProps } = props - - return ( -
- - -
- ) - } -) - -Checkbox.displayName = 'Checkbox' - -Checkbox.propTypes = { - label: PropTypes.string, - disabled: PropTypes.bool, - showLabel: PropTypes.bool, - dataMarketing: dataMarketingType, -} - -export default Checkbox diff --git a/src/ui/Checkbox/Checkbox.stories.jsx b/src/ui/Checkbox/Checkbox.stories.jsx deleted file mode 100644 index fdabea2c83..0000000000 --- a/src/ui/Checkbox/Checkbox.stories.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import { useForm } from 'react-hook-form' - -import Checkbox from './Checkbox' - -const Template = (args) => { - const { register, handleSubmit } = useForm() - - function _handleSubmit(data) { - console.log(data) - } - - return ( -
- - - - ) -} - -export const CheckboxStringLabel = Template.bind({}) - -CheckboxStringLabel.args = { - label: 'Opt-in this great email', -} - -export const NoLabelCheckbox = Template.bind({}) - -NoLabelCheckbox.args = {} - -export const CheckboxHTMLLabel = Template.bind({}) - -CheckboxHTMLLabel.args = { - label: ( - - Amazing newsletter - - ), -} - -export const CheckboxDisabled = Template.bind({}) - -CheckboxDisabled.args = { - label: 'Accept cookies', - disabled: true, -} - -export default { - title: 'Components/Checkbox', - component: Checkbox, - parameters: { - actions: { - handles: ['submit', 'form'], - }, - }, -} diff --git a/src/ui/Checkbox/CheckboxNew.stories.tsx b/src/ui/Checkbox/Checkbox.stories.tsx similarity index 59% rename from src/ui/Checkbox/CheckboxNew.stories.tsx rename to src/ui/Checkbox/Checkbox.stories.tsx index 2a5387c15b..d051345033 100644 --- a/src/ui/Checkbox/CheckboxNew.stories.tsx +++ b/src/ui/Checkbox/Checkbox.stories.tsx @@ -1,10 +1,10 @@ import { Meta, StoryObj } from '@storybook/react' -import { CheckboxNew } from './CheckboxNew' +import Checkbox from './Checkbox' -const meta: Meta = { - title: 'Components/CheckboxNew', - component: CheckboxNew, +const meta: Meta = { + title: 'Components/Checkbox', + component: Checkbox, argTypes: { value: { description: 'Controlled state checked status.', @@ -14,12 +14,12 @@ const meta: Meta = { } export default meta -type Story = StoryObj +type Story = StoryObj export const Default: Story = { render: (args) => ( <> - + ), } @@ -27,7 +27,7 @@ export const Default: Story = { export const Disabled: Story = { render: (args) => ( <> - + ), } @@ -35,7 +35,7 @@ export const Disabled: Story = { export const DisabledAndChecked: Story = { render: () => ( <> - + ), } @@ -44,5 +44,5 @@ export const ControlledState: Story = { args: { checked: true, }, - render: (args) => , + render: (args) => , } diff --git a/src/ui/Checkbox/Checkbox.test.jsx b/src/ui/Checkbox/Checkbox.test.jsx deleted file mode 100644 index 525819b961..0000000000 --- a/src/ui/Checkbox/Checkbox.test.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import { render, screen } from '@testing-library/react' - -import Checkbox from './Checkbox' - -describe('Checkbox', () => { - describe('renders default radio input', () => { - it('renders default with label', async () => { - render() - - const label = await screen.findByText('This is the label') - expect(label).toBeInTheDocument() - }) - }) -}) diff --git a/src/ui/Checkbox/CheckboxNew.test.tsx b/src/ui/Checkbox/Checkbox.test.tsx similarity index 85% rename from src/ui/Checkbox/CheckboxNew.test.tsx rename to src/ui/Checkbox/Checkbox.test.tsx index fe662f9fb0..3fd243ea70 100644 --- a/src/ui/Checkbox/CheckboxNew.test.tsx +++ b/src/ui/Checkbox/Checkbox.test.tsx @@ -1,18 +1,18 @@ import { render, screen, waitFor } from '@testing-library/react' import { userEvent } from '@testing-library/user-event' -import { CheckboxNew } from './CheckboxNew' +import Checkbox from './Checkbox' describe('Checkbox', () => { it('renders', async () => { - render() + render() const checkbox = await screen.findByRole('checkbox') expect(checkbox).toBeInTheDocument() }) it('becomes checked when clicked', async () => { const user = userEvent.setup() - render() + render() const checkbox = await screen.findByRole('checkbox') expect(checkbox).toBeInTheDocument() expect(checkbox).toHaveAttribute('data-state', 'unchecked') @@ -25,14 +25,14 @@ describe('Checkbox', () => { }) it('can be disabled', async () => { - render() + render() const checkbox = await screen.findByRole('checkbox') expect(checkbox).toBeInTheDocument() expect(checkbox).toHaveAttribute('disabled') }) it('can have controlled state', async () => { - render() + render() const checkbox = await screen.findByRole('checkbox') expect(checkbox).toBeInTheDocument() expect(checkbox).toHaveAttribute('data-state', 'checked') diff --git a/src/ui/Checkbox/Checkbox.tsx b/src/ui/Checkbox/Checkbox.tsx new file mode 100644 index 0000000000..76216bb5b3 --- /dev/null +++ b/src/ui/Checkbox/Checkbox.tsx @@ -0,0 +1,34 @@ +import * as CheckboxPrimitive from '@radix-ui/react-checkbox' +import React from 'react' + +import { cn } from 'shared/utils/cn' +import Icon from 'ui/Icon' + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export default Checkbox diff --git a/src/ui/Checkbox/index.js b/src/ui/Checkbox/index.ts similarity index 100% rename from src/ui/Checkbox/index.js rename to src/ui/Checkbox/index.ts From 8815859fc7a1f4cac94dab72e7781ddef8afd3c4 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Fri, 27 Sep 2024 09:11:11 -0300 Subject: [PATCH 11/44] 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 12/44] 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 13/44] 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 14/44] 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 15/44] 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 16/44] 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 17/44] 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 18/44] 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 19/44] 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 20/44] 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 21/44] 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 22/44] 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 23/44] 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 24/44] 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 25/44] 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 26/44] 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 27/44] 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 28/44] 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 29/44] 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 30/44] 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 = [ From 4519b02feac4bf1ba1916f022a832d856501ba2e Mon Sep 17 00:00:00 2001 From: Rohit Vinnakota <148245014+rohitvinnakota-codecov@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:01:02 -0400 Subject: [PATCH 31/44] [feat] Add configured repos table to the Codecov AI tab (#3303) --- .../CodecovAIPage/CodecovAIPage.test.tsx | 122 ++++++++++++-- src/pages/CodecovAIPage/CodecovAIPage.tsx | 14 +- .../ConfiguredRepositories.tsx | 152 ++++++++++++++++++ .../InstallCodecovAI/InstallCodecovAI.tsx | 1 - .../useCodecovAIInstallation.spec.tsx | 110 +++++++++++++ .../codecovAI/useCodecovAIInstallation.tsx | 58 +++++++ .../useCodecovAIInstalledRepos.spec.tsx | 110 +++++++++++++ .../codecovAI/useCodecovAIInstalledRepos.tsx | 59 +++++++ 8 files changed, 609 insertions(+), 17 deletions(-) create mode 100644 src/pages/CodecovAIPage/ConfiguredRepositories/ConfiguredRepositories.tsx create mode 100644 src/services/codecovAI/useCodecovAIInstallation.spec.tsx create mode 100644 src/services/codecovAI/useCodecovAIInstallation.tsx create mode 100644 src/services/codecovAI/useCodecovAIInstalledRepos.spec.tsx create mode 100644 src/services/codecovAI/useCodecovAIInstalledRepos.tsx diff --git a/src/pages/CodecovAIPage/CodecovAIPage.test.tsx b/src/pages/CodecovAIPage/CodecovAIPage.test.tsx index 9d1d3309bd..ee2eb0c4f5 100644 --- a/src/pages/CodecovAIPage/CodecovAIPage.test.tsx +++ b/src/pages/CodecovAIPage/CodecovAIPage.test.tsx @@ -1,4 +1,7 @@ -import { render, screen } from '@testing-library/react' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { cleanup, render, screen } from '@testing-library/react' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { ThemeContextProvider } from 'shared/ThemeContext' @@ -17,17 +20,75 @@ vi.mock('shared/featureFlags', async () => { } }) +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: true, + suspense: true, + }, + }, +}) + +const server = setupServer() + const wrapper: React.FC = ({ children }) => ( - - - {children} - - + + + + {children} + + + ) +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterEach(() => { + cleanup() + vi.clearAllMocks() + queryClient.clear() +}) + +afterAll(() => { + server.close() +}) + describe('CodecovAIPage', () => { + function setup( + aiFeaturesEnabled = false, + aiEnabledRepos = ['repo-1', 'repo-2'] + ) { + server.use( + graphql.query('GetCodecovAIAppInstallInfo', (info) => { + return HttpResponse.json({ + data: { + owner: { + aiFeaturesEnabled, + }, + }, + }) + }), + graphql.query('GetCodecovAIInstalledRepos', (info) => { + return HttpResponse.json({ + data: { + owner: { + aiEnabledRepos, + }, + }, + }) + }) + ) + } beforeEach(() => { mocks.useFlags.mockReturnValue({ codecovAiFeaturesTab: true }) + setup() }) it('renders top section', async () => { @@ -55,7 +116,7 @@ describe('CodecovAIPage', () => { it('renders the install button', async () => { render(, { wrapper }) - const buttonEl = screen.getByRole('link', { name: /Install Codecov AI/i }) + const buttonEl = await screen.findByText(/Install Codecov AI/i) expect(buttonEl).toBeInTheDocument() }) @@ -107,15 +168,48 @@ describe('CodecovAIPage', () => { const docLink = await screen.findByText(/Visit our guide/) expect(docLink).toBeInTheDocument() }) -}) -describe('flag is off', () => { - it('does not render page', async () => { - mocks.useFlags.mockReturnValue({ codecovAiFeaturesTab: false }) + describe('AI features are enabled and configured', () => { + beforeEach(() => { + setup(true) + mocks.useFlags.mockReturnValue({ codecovAiFeaturesTab: true }) + }) + + it('does not render install link', () => { + setup(true) + render(, { wrapper }) + const topSection = screen.queryByText(/Install Codecov AI/) + expect(topSection).not.toBeInTheDocument() + }) + + it('renders list of repos', async () => { + render(, { wrapper }) + + const repo1Link = await screen.findByText(/repo-1/) + expect(repo1Link).toBeInTheDocument() + const repo2Link = await screen.findByText(/repo-2/) + expect(repo2Link).toBeInTheDocument() + }) + + describe('No repos returned', () => { + it('renders install link', async () => { + setup(true, []) + render(, { wrapper }) + const buttonEl = await screen.findByText(/Install Codecov AI/i) + expect(buttonEl).toBeInTheDocument() + }) + }) + }) + + describe('flag is off', () => { + it('does not render page', async () => { + setup(true) + mocks.useFlags.mockReturnValue({ codecovAiFeaturesTab: false }) - render(, { wrapper }) + render(, { wrapper }) - const topSection = screen.queryByText(/Codecov AI is a/) - expect(topSection).not.toBeInTheDocument() + const topSection = screen.queryByText(/Codecov AI is a/) + expect(topSection).not.toBeInTheDocument() + }) }) }) diff --git a/src/pages/CodecovAIPage/CodecovAIPage.tsx b/src/pages/CodecovAIPage/CodecovAIPage.tsx index 25b163c531..0f9cb42a0c 100644 --- a/src/pages/CodecovAIPage/CodecovAIPage.tsx +++ b/src/pages/CodecovAIPage/CodecovAIPage.tsx @@ -1,8 +1,10 @@ import { Redirect, useParams } from 'react-router-dom' +import { useCodecovAIInstallation } from 'services/codecovAI/useCodecovAIInstallation' import { useFlags } from 'shared/featureFlags' import CodecovAICommands from './CodecovAICommands/CodecovAICommands' +import ConfiguredRepositories from './ConfiguredRepositories/ConfiguredRepositories' import InstallCodecovAI from './InstallCodecovAI/InstallCodecovAI' import LearnMoreBlurb from './LearnMoreBlurb/LearnMoreBlurb' import Tabs from './Tabs/Tabs' @@ -14,11 +16,15 @@ interface URLParams { const CodecovAIPage: React.FC = () => { const { provider, owner } = useParams() - const { codecovAiFeaturesTab } = useFlags({ codecovAiFeaturesTab: false, }) + const { data: installationData } = useCodecovAIInstallation({ + owner, + provider, + }) + if (!codecovAiFeaturesTab) { return } @@ -36,7 +42,11 @@ const CodecovAIPage: React.FC = () => {

- + {installationData?.aiFeaturesEnabled ? ( + + ) : ( + + )}
diff --git a/src/pages/CodecovAIPage/ConfiguredRepositories/ConfiguredRepositories.tsx b/src/pages/CodecovAIPage/ConfiguredRepositories/ConfiguredRepositories.tsx new file mode 100644 index 0000000000..c39ff7b882 --- /dev/null +++ b/src/pages/CodecovAIPage/ConfiguredRepositories/ConfiguredRepositories.tsx @@ -0,0 +1,152 @@ +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, +} from '@tanstack/react-table' +import React, { useMemo, useState } from 'react' +import { useParams } from 'react-router-dom' + +import { useCodecovAIInstalledRepos } from 'services/codecovAI/useCodecovAIInstalledRepos' +import A from 'ui/A' +import { Card } from 'ui/Card' +import Icon from 'ui/Icon' +import Spinner from 'ui/Spinner' + +import InstallCodecovAI from '../InstallCodecovAI/InstallCodecovAI' + +interface URLParams { + owner: string + provider: string +} + +const Loader = () => ( +
+ +
+) + +const columnHelper = createColumnHelper<{ name: string }>() + +function ConfiguredRepositories() { + const { owner, provider } = useParams() + const { data, isLoading } = useCodecovAIInstalledRepos({ + owner, + provider, + }) + + const [isSortedAscending, setIsSortedAscending] = useState(true) + + const sortRepos = () => { + setIsSortedAscending(!isSortedAscending) + } + + const tableData = useMemo(() => { + if (!data?.aiEnabledRepos) return [] + const sortedRepos = [...data.aiEnabledRepos].sort((a, b) => + isSortedAscending ? a.localeCompare(b) : b.localeCompare(a) + ) + return sortedRepos.map((name) => ({ name })) + }, [data?.aiEnabledRepos, isSortedAscending]) + + const columns = useMemo( + () => [ + columnHelper.accessor('name', { + header: 'Repo Name', + cell: (info) => { + const repoName = info.getValue() + const link = `/${provider}/${owner}/${repoName}` + return ( + + {repoName} + + ) + }, + }), + ], + [provider, owner] + ) + + const table = useReactTable({ + data: tableData, + columns, + getCoreRowModel: getCoreRowModel(), + }) + + // This should technically never happen, but render a fallback just in case + if (tableData.length === 0) { + return + } + + return ( +
+ + + + {tableData.length} configured repositories + +

+ To install more repos, please manage your Codecov AI app on GitHub. +
+ To uninstall the app, please go to your GitHub Apps settings. +

+
+
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {isLoading ? ( + + + + ) : ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + )) + )} + +
+
+ {flexRender( + header.column.columnDef.header, + header.getContext() + )} + + + +
+
+ +
+ {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} +
+
+
+ ) +} + +export default ConfiguredRepositories diff --git a/src/pages/CodecovAIPage/InstallCodecovAI/InstallCodecovAI.tsx b/src/pages/CodecovAIPage/InstallCodecovAI/InstallCodecovAI.tsx index 055015b772..b7510c3795 100644 --- a/src/pages/CodecovAIPage/InstallCodecovAI/InstallCodecovAI.tsx +++ b/src/pages/CodecovAIPage/InstallCodecovAI/InstallCodecovAI.tsx @@ -9,7 +9,6 @@ const COPY_APP_INSTALL_STRING = const InstallCodecovAI: React.FC = () => { const { theme } = useThemeContext() - const isDarkMode = theme === Theme.DARK const githubImage = loginProviderImage('Github', !isDarkMode) diff --git a/src/services/codecovAI/useCodecovAIInstallation.spec.tsx b/src/services/codecovAI/useCodecovAIInstallation.spec.tsx new file mode 100644 index 0000000000..df074d6159 --- /dev/null +++ b/src/services/codecovAI/useCodecovAIInstallation.spec.tsx @@ -0,0 +1,110 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { renderHook, waitFor } from '@testing-library/react' +import { graphql } from 'msw' +import { setupServer } from 'msw/node' + +import { useCodecovAIInstallation } from './useCodecovAIInstallation' + +const mockAiFeaturesEnabled = { + owner: { + aiFeaturesEnabled: true, + }, +} + +const mockUnsuccessfulParseError = { + owner: { + wrong: 'schema', + }, +} + +const server = setupServer() +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) + +const wrapper: React.FC = ({ children }) => ( + {children} +) + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +interface SetupArgs { + isUnsuccessfulParseError?: boolean +} + +describe('useCodecovAIInstallation', () => { + function setup({ isUnsuccessfulParseError = false }: SetupArgs) { + server.use( + graphql.query('GetCodecovAIAppInstallInfo', (req, res, ctx) => { + if (isUnsuccessfulParseError) { + return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + } + return res(ctx.status(200), ctx.data(mockAiFeaturesEnabled)) + }) + ) + } + + describe('there is valid data', () => { + it('fetches the owner app installation info', async () => { + setup({}) + const { result } = renderHook( + () => + useCodecovAIInstallation({ + owner: 'codecov', + provider: 'gh', + }), + { wrapper } + ) + + await waitFor(() => + expect(result.current.data).toStrictEqual({ + aiFeaturesEnabled: true, + }) + ) + }) + }) + + describe('unsuccessful parse of zod schema', () => { + let oldConsoleError = console.error + + beforeEach(() => { + console.error = () => null + }) + + afterEach(() => { + console.error = oldConsoleError + }) + + it('throws a 404', async () => { + setup({ isUnsuccessfulParseError: true }) + const { result } = renderHook( + () => + useCodecovAIInstallation({ + owner: 'codecov', + provider: 'gh', + }), + { wrapper } + ) + + await waitFor(() => expect(result.current.isError).toBeTruthy()) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + }) + ) + ) + }) + }) +}) diff --git a/src/services/codecovAI/useCodecovAIInstallation.tsx b/src/services/codecovAI/useCodecovAIInstallation.tsx new file mode 100644 index 0000000000..80e4404697 --- /dev/null +++ b/src/services/codecovAI/useCodecovAIInstallation.tsx @@ -0,0 +1,58 @@ +import { useQuery } from '@tanstack/react-query' +import z from 'zod' + +import Api from 'shared/api' +import { NetworkErrorObject } from 'shared/api/helpers' + +const ResponseSchema = z.object({ + owner: z + .object({ + aiFeaturesEnabled: z.boolean(), + }) + .nullable(), +}) + +const query = ` + query GetCodecovAIAppInstallInfo($username: String!) { + owner(username: $username) { + aiFeaturesEnabled + } + } +` + +interface CodecovAIInstallationProps { + owner: string + provider: string +} + +export function useCodecovAIInstallation({ + owner, + provider, +}: CodecovAIInstallationProps) { + return useQuery({ + queryKey: ['GetCodecovAIAppInstallInfo', provider, owner], + queryFn: ({ signal }) => { + return Api.graphql({ + provider, + query, + signal, + variables: { + username: owner, + }, + }).then((res) => { + const parsedRes = ResponseSchema.safeParse(res?.data) + if (!parsedRes.success) { + return Promise.reject({ + status: 404, + data: {}, + dev: 'useCodecovAIInstallation - 404 failed to parse', + } satisfies NetworkErrorObject) + } + + return { + aiFeaturesEnabled: parsedRes.data.owner?.aiFeaturesEnabled, + } + }) + }, + }) +} diff --git a/src/services/codecovAI/useCodecovAIInstalledRepos.spec.tsx b/src/services/codecovAI/useCodecovAIInstalledRepos.spec.tsx new file mode 100644 index 0000000000..a065fb3d47 --- /dev/null +++ b/src/services/codecovAI/useCodecovAIInstalledRepos.spec.tsx @@ -0,0 +1,110 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { renderHook, waitFor } from '@testing-library/react' +import { graphql } from 'msw' +import { setupServer } from 'msw/node' + +import { useCodecovAIInstalledRepos } from './useCodecovAIInstalledRepos' + +const mockAiInstalledRepos = { + owner: { + aiEnabledRepos: ['repo-1', 'repo-2'], + }, +} + +const mockUnsuccessfulParseError = { + owner: { + wrong: 'schema', + }, +} + +const server = setupServer() +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) + +const wrapper: React.FC = ({ children }) => ( + {children} +) + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +interface SetupArgs { + isUnsuccessfulParseError?: boolean +} + +describe('useCodecovAIInstalledRepos', () => { + function setup({ isUnsuccessfulParseError = false }: SetupArgs) { + server.use( + graphql.query('GetCodecovAIInstalledRepos', (req, res, ctx) => { + if (isUnsuccessfulParseError) { + return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + } + return res(ctx.status(200), ctx.data(mockAiInstalledRepos)) + }) + ) + } + + describe('there is valid data', () => { + it('fetches the correct list of repos', async () => { + setup({}) + const { result } = renderHook( + () => + useCodecovAIInstalledRepos({ + owner: 'codecov', + provider: 'gh', + }), + { wrapper } + ) + + await waitFor(() => + expect(result.current.data).toStrictEqual({ + aiEnabledRepos: ['repo-1', 'repo-2'], + }) + ) + }) + }) + + describe('unsuccessful parse of zod schema', () => { + let oldConsoleError = console.error + + beforeEach(() => { + console.error = () => null + }) + + afterEach(() => { + console.error = oldConsoleError + }) + + it('throws a 404', async () => { + setup({ isUnsuccessfulParseError: true }) + const { result } = renderHook( + () => + useCodecovAIInstalledRepos({ + owner: 'codecov', + provider: 'gh', + }), + { wrapper } + ) + + await waitFor(() => expect(result.current.isError).toBeTruthy()) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + }) + ) + ) + }) + }) +}) diff --git a/src/services/codecovAI/useCodecovAIInstalledRepos.tsx b/src/services/codecovAI/useCodecovAIInstalledRepos.tsx new file mode 100644 index 0000000000..23953d323d --- /dev/null +++ b/src/services/codecovAI/useCodecovAIInstalledRepos.tsx @@ -0,0 +1,59 @@ +import { useQuery } from '@tanstack/react-query' +import z from 'zod' + +import Api from 'shared/api' +import { NetworkErrorObject } from 'shared/api/helpers' + +const ResponseSchema = z.object({ + owner: z + .object({ + aiEnabledRepos: z.array(z.string()).nullable(), + }) + .nullable(), +}) + +const query = ` + query GetCodecovAIInstalledRepos($username: String!) { + owner(username: $username) { + aiEnabledRepos + } + } +` + +interface CodecovAIInstalledReposProps { + owner: string + provider: string +} + +export function useCodecovAIInstalledRepos({ + owner, + provider, +}: CodecovAIInstalledReposProps) { + return useQuery({ + queryKey: ['GetCodecovAIInstalledRepos', provider, owner], + queryFn: ({ signal }) => { + return Api.graphql({ + provider, + query, + signal, + variables: { + username: owner, + }, + }).then((res) => { + const parsedRes = ResponseSchema.safeParse(res?.data) + + if (!parsedRes.success) { + return Promise.reject({ + status: 404, + data: {}, + dev: 'useCodecovAIInstalledRepos - 404 failed to parse', + } satisfies NetworkErrorObject) + } + + return { + aiEnabledRepos: parsedRes.data.owner?.aiEnabledRepos, + } + }) + }, + }) +} From 98c662e72a7273a1e0c249232de46838e879b9ac Mon Sep 17 00:00:00 2001 From: Rohit Vinnakota <148245014+rohitvinnakota-codecov@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:18:15 -0400 Subject: [PATCH 32/44] [fix] Update error message copy on uploads card (#3326) --- .../CommitCoverage/UploadsCard/RenderError.tsx | 3 ++- .../CommitCoverage/UploadsCard/Upload.spec.jsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/RenderError.tsx b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/RenderError.tsx index 0d4d482538..d8cfafefe6 100644 --- a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/RenderError.tsx +++ b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/RenderError.tsx @@ -69,7 +69,8 @@ const ErrorMessage = ({ errorCode, count }: ErrorMessageProps) => { {icon}

- Upload failed. Please rerun the upload. {renderCount} + Processing failed. Please rerun the upload in a new commit.{' '} + {renderCount}

) diff --git a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.spec.jsx b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.spec.jsx index 469956a213..4fd03c180f 100644 --- a/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.spec.jsx +++ b/src/pages/CommitDetailPage/CommitCoverage/UploadsCard/Upload.spec.jsx @@ -163,7 +163,7 @@ describe('UploadsCard', () => { }) const processingFailed = screen.getByText( - /Upload failed. Please rerun the upload./ + /Processing failed. Please rerun the upload in a new commit./ ) expect(processingFailed).toBeInTheDocument() }) @@ -229,7 +229,7 @@ describe('UploadsCard', () => { { wrapper } ) - const processingFailed = screen.getByText(/Upload failed/) + const processingFailed = screen.getByText(/Processing failed./) expect(processingFailed).toBeInTheDocument() const uploadExpired = screen.getByText( From efbd1704845ae9cf817b3fb7b1e50807ec7b5a07 Mon Sep 17 00:00:00 2001 From: Rohit Vinnakota <148245014+rohitvinnakota-codecov@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:59:01 -0400 Subject: [PATCH 33/44] [fix] Adjust spacing on AI commands text (#3340) --- .../CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx | 8 ++++---- src/pages/CodecovAIPage/CodecovAIPage.test.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx b/src/pages/CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx index 301a139c5d..d22d4d4601 100644 --- a/src/pages/CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx +++ b/src/pages/CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx @@ -14,14 +14,14 @@ const CodecovAICommands: React.FC = () => {
  • @codecov-ai-reviewer test - {' '} - --the assistant will generate tests for the PR. + + -- the assistant will generate tests for the PR.
  • @codecov-ai-reviewer review - {' '} - --the assistant will review the PR and make suggestions. + + -- the assistant will review the PR and make suggestions.
  • diff --git a/src/pages/CodecovAIPage/CodecovAIPage.test.tsx b/src/pages/CodecovAIPage/CodecovAIPage.test.tsx index ee2eb0c4f5..116654c5d5 100644 --- a/src/pages/CodecovAIPage/CodecovAIPage.test.tsx +++ b/src/pages/CodecovAIPage/CodecovAIPage.test.tsx @@ -136,12 +136,12 @@ describe('CodecovAIPage', () => { expect(commandText).toBeInTheDocument() const commandOneText = await screen.findByText( - /the assistant will generate tests/ + / the assistant will generate tests/ ) expect(commandOneText).toBeInTheDocument() const commandTwoText = await screen.findByText( - /the assistant will review the PR/ + / the assistant will review the PR/ ) expect(commandTwoText).toBeInTheDocument() }) From 8c134464d1feaa19168e5b874d7bfa391af2d252 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Tue, 1 Oct 2024 10:05:35 -0700 Subject: [PATCH 34/44] fix: Use coverageAnalytics new graphql fields (#3339) --- src/services/repos/useRepos.test.tsx | 12 +- src/services/repos/useRepos.tsx | 14 ++- src/services/repos/useReposTeam.test.tsx | 16 ++- src/services/repos/useReposTeam.tsx | 10 +- .../ListRepo/ReposTable/ReposTable.test.tsx | 88 ++++++++++----- .../ReposTable/getReposColumnsHelper.tsx | 12 +- .../ReposTableTeam/ReposTableTeam.test.jsx | 104 +++++++++++++----- .../ReposTableTeam/ReposTableTeam.tsx | 9 +- src/shared/utils/demo.test.ts | 6 +- 9 files changed, 191 insertions(+), 80 deletions(-) diff --git a/src/services/repos/useRepos.test.tsx b/src/services/repos/useRepos.test.tsx index d0b77d39b5..d37e2079b2 100644 --- a/src/services/repos/useRepos.test.tsx +++ b/src/services/repos/useRepos.test.tsx @@ -24,9 +24,11 @@ const repo1 = { name: 'codecov-bash', active: true, activated: true, - lines: 99, + coverageAnalytics: { + lines: 99, + percentCovered: null, + }, private: false, - coverage: null, updatedAt: '2021-04-22T14:09:39.822872+00:00', author: { username: 'codecov', @@ -46,9 +48,11 @@ const repo2 = { name: 'codecov-circleci-orb', active: false, activated: true, - lines: 99, + coverageAnalytics: { + lines: 99, + percentCovered: null, + }, private: false, - coverage: null, updatedAt: '2021-04-22T14:09:39.826948+00:00', author: { username: 'codecov', diff --git a/src/services/repos/useRepos.tsx b/src/services/repos/useRepos.tsx index b6a239f91c..ec15bd3007 100644 --- a/src/services/repos/useRepos.tsx +++ b/src/services/repos/useRepos.tsx @@ -13,9 +13,13 @@ const RepositorySchema = z active: z.boolean(), activated: z.boolean().nullable(), private: z.boolean(), - coverage: z.number().nullish(), + coverageAnalytics: z + .object({ + percentCovered: z.number().nullish(), + lines: z.number().nullable(), + }) + .nullable(), latestCommitAt: z.string().nullable(), - lines: z.number().nullable(), author: z.object({ username: z.string().nullable(), }), @@ -70,10 +74,12 @@ const query = `query ReposForOwner( active activated private - coverage + coverageAnalytics { + percentCovered + lines + } updatedAt latestCommitAt - lines author { username } diff --git a/src/services/repos/useReposTeam.test.tsx b/src/services/repos/useReposTeam.test.tsx index 40806d6088..695ed739b9 100644 --- a/src/services/repos/useReposTeam.test.tsx +++ b/src/services/repos/useReposTeam.test.tsx @@ -24,7 +24,9 @@ const repo1 = { activated: true, private: false, latestCommitAt: '2021-04-22T14:09:39.826948+00:00', - lines: 99, + coverageAnalytics: { + lines: 99, + }, author: { username: 'codecov', }, @@ -38,7 +40,9 @@ const repo2 = { activated: true, private: false, latestCommitAt: '2021-04-22T14:09:39.826948+00:00', - lines: 99, + coverageAnalytics: { + lines: 99, + }, author: { username: 'codecov', }, @@ -52,7 +56,9 @@ const repo3 = { activated: true, private: false, latestCommitAt: '2021-04-22T14:09:39.826948+00:00', - lines: 99, + coverageAnalytics: { + lines: 99, + }, author: { username: 'codecov', }, @@ -66,7 +72,9 @@ const repo4 = { activated: true, private: false, latestCommitAt: '2021-04-22T14:09:39.826948+00:00', - lines: 99, + coverageAnalytics: { + lines: 99, + }, author: { username: 'codecov', }, diff --git a/src/services/repos/useReposTeam.tsx b/src/services/repos/useReposTeam.tsx index 4be24771d7..5dcebb842c 100644 --- a/src/services/repos/useReposTeam.tsx +++ b/src/services/repos/useReposTeam.tsx @@ -14,7 +14,11 @@ const RepositorySchema = z activated: z.boolean().nullable(), private: z.boolean(), latestCommitAt: z.string().nullable(), - lines: z.number().nullable(), + coverageAnalytics: z + .object({ + lines: z.number().nullable(), + }) + .nullable(), author: z.object({ username: z.string().nullable(), }), @@ -70,7 +74,9 @@ const query = `query GetReposTeam( activated private latestCommitAt - lines + coverageAnalytics { + lines + } author { username } diff --git a/src/shared/ListRepo/ReposTable/ReposTable.test.tsx b/src/shared/ListRepo/ReposTable/ReposTable.test.tsx index 67a0916a0b..dbf3a67a13 100644 --- a/src/shared/ListRepo/ReposTable/ReposTable.test.tsx +++ b/src/shared/ListRepo/ReposTable/ReposTable.test.tsx @@ -44,9 +44,11 @@ const mockRepositories = ( }, name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 43, + coverageAnalytics: { + percentCovered: 43, + lines: 99, + }, active: true, - lines: 99, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, coverageEnabled, @@ -62,9 +64,11 @@ const mockRepositories = ( }, name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), - coverage: 100, + coverageAnalytics: { + percentCovered: 100, + lines: 101, + }, active: true, - lines: 101, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, coverageEnabled, @@ -81,7 +85,9 @@ const mockRepositories = ( name: 'Repo name 3', latestCommitAt: null, active: true, - lines: 207, + coverageAnalytics: { + lines: 207, + }, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, coverageEnabled, @@ -219,9 +225,11 @@ describe('ReposTable', () => { }, name: 'Repo name extra', latestCommitAt: subDays(new Date(), 5).toISOString(), - coverage: 50, + coverageAnalytics: { + percentCovered: 50, + lines: 20, + }, active: true, - lines: 20, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, coverageEnabled: true, @@ -442,10 +450,12 @@ describe('ReposTable', () => { }, name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 43, + coverageAnalytics: { + percentCovered: 43, + lines: 3, + }, active: false, repositoryConfig: null, - lines: 3, updatedAt: '2020-08-25T16:36:19.67986800:00', coverageEnabled: false, bundleAnalysisEnabled: false, @@ -460,9 +470,11 @@ describe('ReposTable', () => { }, name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), - coverage: 100, + coverageAnalytics: { + percentCovered: 100, + lines: 0, + }, active: false, - lines: 0, repositoryConfig: null, updatedAt: '2020-08-25T16:36:19.67986800:00', coverageEnabled: false, @@ -478,9 +490,11 @@ describe('ReposTable', () => { }, name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), - coverage: 0, + coverageAnalytics: { + percentCovered: 0, + lines: 0, + }, active: false, - lines: 0, repositoryConfig: null, updatedAt: '2020-08-25T16:36:19.67986800:00', coverageEnabled: false, @@ -729,9 +743,11 @@ describe('ReposTable', () => { }, name: 'Repo name first page', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 43, + coverageAnalytics: { + percentCovered: 43, + lines: 99, + }, active: true, - lines: 99, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, coverageEnabled: false, @@ -770,11 +786,13 @@ describe('ReposTable', () => { }, name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 0, + coverageAnalytics: { + percentCovered: 0, + lines: 123, + }, active: true, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -788,11 +806,13 @@ describe('ReposTable', () => { }, name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), - coverage: 100, + coverageAnalytics: { + percentCovered: 100, + lines: 123, + }, active: true, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -806,11 +826,13 @@ describe('ReposTable', () => { }, name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), - coverage: null, + coverageAnalytics: { + percentCovered: null, + lines: 123, + }, active: false, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -867,11 +889,13 @@ describe('ReposTable', () => { }, name: 'gazebo', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 0, + coverageAnalytics: { + percentCovered: 0, + lines: 123, + }, active: true, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -888,11 +912,13 @@ describe('ReposTable', () => { }, name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), - coverage: 0, + coverageAnalytics: { + percentCovered: 0, + lines: 123, + }, active: true, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -906,11 +932,13 @@ describe('ReposTable', () => { }, name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), - coverage: 100, + coverageAnalytics: { + percentCovered: 100, + lines: 123, + }, active: true, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -924,11 +952,13 @@ describe('ReposTable', () => { }, name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), - coverage: null, + coverageAnalytics: { + percentCovered: null, + lines: 123, + }, active: false, updatedAt: '2020-08-25T16:36:19.67986800:00', repositoryConfig: null, - lines: 123, coverageEnabled: false, bundleAnalysisEnabled: false, }, diff --git a/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx b/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx index 4ee50508b8..95a8ae1a8c 100644 --- a/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx +++ b/src/shared/ListRepo/ReposTable/getReposColumnsHelper.tsx @@ -81,26 +81,28 @@ export const getReposColumnsHelper = ({ ) }, }), - columnHelper.accessor('lines', { + columnHelper.accessor('coverageAnalytics.lines', { header: 'Tracked lines', id: 'lines', cell: (info) => { const repo = info.row.original return ( <> -
    {repo?.lines}
    +
    + {repo?.coverageAnalytics?.lines} +
    ) }, }), - columnHelper.accessor('coverage', { + columnHelper.accessor('coverageAnalytics.percentCovered', { header: 'Test coverage', id: 'coverage', cell: (info) => { const repo = info.row.original - return typeof repo?.coverage === 'number' ? ( + return typeof repo?.coverageAnalytics?.percentCovered === 'number' ? ( { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 99, + coverageAnalytics: { + lines: 99, + }, coverageEnabled, bundleAnalysisEnabled, }, @@ -111,7 +113,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 101, + coverageAnalytics: { + lines: 101, + }, coverageEnabled, bundleAnalysisEnabled, }, @@ -126,7 +130,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: null, active: true, - lines: 207, + coverageAnalytics: { + lines: 207, + }, coverageEnabled, bundleAnalysisEnabled, }, @@ -267,7 +273,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: false, - lines: 99, + coverageAnalytics: { + lines: 99, + }, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -282,7 +290,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: false, - lines: 101, + coverageAnalytics: { + lines: 101, + }, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -297,7 +307,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: false, - lines: 207, + coverageAnalytics: { + lines: 207, + }, coverageEnabled: false, bundleAnalysisEnabled: false, }, @@ -357,7 +369,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -372,7 +386,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -387,7 +403,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -480,7 +498,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -509,7 +529,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -545,7 +567,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -560,7 +584,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -575,7 +601,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -607,7 +635,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -622,7 +652,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -637,7 +669,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -668,7 +702,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -683,7 +719,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -698,7 +736,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: false, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -730,7 +770,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -745,7 +787,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -760,7 +804,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -794,7 +840,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 1', latestCommitAt: subDays(new Date(), 3).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -809,7 +857,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 2', latestCommitAt: subDays(new Date(), 2).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, @@ -824,7 +874,9 @@ describe('ReposTableTeam', () => { name: 'Repo name 3', latestCommitAt: subDays(new Date(), 5).toISOString(), active: true, - lines: 0, + coverageAnalytics: { + lines: 0, + }, coverageEnabled: true, bundleAnalysisEnabled: true, }, diff --git a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx index 761543eb43..53fa9451a6 100644 --- a/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx +++ b/src/shared/ListRepo/ReposTableTeam/ReposTableTeam.tsx @@ -92,7 +92,7 @@ const getColumns = ({ if (inactive) { return [ nameColumn, - columnHelper.accessor('lines', { + columnHelper.accessor('coverageAnalytics.lines', { header: '', id: 'lines', cell: (info) => { @@ -123,13 +123,14 @@ const getColumns = ({ ) }, }), - columnHelper.accessor('lines', { + columnHelper.accessor('coverageAnalytics.lines', { header: 'Tracked lines', id: 'lines', cell: (info) => { const repo = info.row.original - return typeof repo?.lines === 'number' && !!repo?.active ? ( - {repo.lines} + return typeof repo?.coverageAnalytics?.lines === 'number' && + !!repo?.active ? ( + {repo.coverageAnalytics?.lines} ) : ( { name: 'gazebo', active: true, activated: true, - lines: 99, private: false, - coverage: null, + coverageAnalytics: { + lines: 99, + coverage: null, + }, updatedAt: '2021-04-22T14:09:39.822872+00:00', author: { username: 'codecov', From 34be384cc0a3ced8bfa5d9e7e656336fd44e699a Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 13:39:01 -0400 Subject: [PATCH 35/44] chore: Update services/user tests to Vitest (#3308) --- src/services/user/{index.js => index.ts} | 0 ...User.spec.tsx => useInternalUser.test.tsx} | 27 ++++---- ...ec.js => useIsCurrentUserAnAdmin.test.jsx} | 28 +++++---- ...ntexts.spec.tsx => useMyContexts.test.tsx} | 38 +++++------ ...rdUser.spec.js => useOnboardUser.test.jsx} | 46 ++++++-------- .../{useOwner.spec.js => useOwner.test.jsx} | 62 +++++------------- ...c.tsx => useOwnerRateLimitStatus.test.tsx} | 45 +++++-------- ...yncUser.spec.js => useResyncUser.test.jsx} | 63 ++++++++----------- ...file.spec.js => useUpdateProfile.test.jsx} | 55 ++++++++-------- .../{useUser.spec.tsx => useUser.test.tsx} | 48 +++++++------- 10 files changed, 176 insertions(+), 236 deletions(-) rename src/services/user/{index.js => index.ts} (100%) rename src/services/user/{useInternalUser.spec.tsx => useInternalUser.test.tsx} (76%) rename src/services/user/{useIsCurrentUserAnAdmin.spec.js => useIsCurrentUserAnAdmin.test.jsx} (83%) rename src/services/user/{useMyContexts.spec.tsx => useMyContexts.test.tsx} (84%) rename src/services/user/{useOnboardUser.spec.js => useOnboardUser.test.jsx} (80%) rename src/services/user/{useOwner.spec.js => useOwner.test.jsx} (54%) rename src/services/user/{useOwnerRateLimitStatus.spec.tsx => useOwnerRateLimitStatus.test.tsx} (67%) rename src/services/user/{useResyncUser.spec.js => useResyncUser.test.jsx} (84%) rename src/services/user/{useUpdateProfile.spec.js => useUpdateProfile.test.jsx} (84%) rename src/services/user/{useUser.spec.tsx => useUser.test.tsx} (82%) diff --git a/src/services/user/index.js b/src/services/user/index.ts similarity index 100% rename from src/services/user/index.js rename to src/services/user/index.ts diff --git a/src/services/user/useInternalUser.spec.tsx b/src/services/user/useInternalUser.test.tsx similarity index 76% rename from src/services/user/useInternalUser.spec.tsx rename to src/services/user/useInternalUser.test.tsx index d6a7a6e5ef..2d229110ed 100644 --- a/src/services/user/useInternalUser.spec.tsx +++ b/src/services/user/useInternalUser.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 { useInternalUser } from './useInternalUser' @@ -28,20 +28,17 @@ afterAll(() => { describe('useInternalUser', () => { function setup(hasError = false) { server.use( - rest.get('/internal/user', (req, res, ctx) => { + http.get('/internal/user', (info) => { if (hasError) { - return res(ctx.status(400), ctx.json({})) + return HttpResponse.json({}, { status: 400 }) } - return res( - ctx.status(200), - ctx.json({ - email: 'cool@email.com', - name: 'cool-user', - externalId: '1234', - termsAgreement: false, - owners: [], - }) - ) + return HttpResponse.json({ + email: 'cool@email.com', + name: 'cool-user', + externalId: '1234', + termsAgreement: false, + owners: [], + }) }) ) } @@ -49,7 +46,6 @@ describe('useInternalUser', () => { describe('calling hook', () => { it('returns api response', async () => { setup() - const { result } = renderHook(() => useInternalUser({}), { wrapper }) await waitFor(() => @@ -67,7 +63,6 @@ describe('useInternalUser', () => { describe('when hook call errors', () => { it('returns empty object', async () => { setup(true) - const { result } = renderHook(() => useInternalUser({}), { wrapper }) await waitFor(() => expect(result.current.data).toStrictEqual({})) diff --git a/src/services/user/useIsCurrentUserAnAdmin.spec.js b/src/services/user/useIsCurrentUserAnAdmin.test.jsx similarity index 83% rename from src/services/user/useIsCurrentUserAnAdmin.spec.js rename to src/services/user/useIsCurrentUserAnAdmin.test.jsx index e72e2c766d..6eee4f0426 100644 --- a/src/services/user/useIsCurrentUserAnAdmin.spec.js +++ b/src/services/user/useIsCurrentUserAnAdmin.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 { useIsCurrentUserAnAdmin } from './useIsCurrentUserAnAdmin' @@ -9,7 +9,6 @@ import { useIsCurrentUserAnAdmin } from './useIsCurrentUserAnAdmin' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper = (initialEntries = '/gh/codecov') => @@ -21,11 +20,16 @@ const wrapper = ) -beforeAll(() => server.listen()) +const server = setupServer() +beforeAll(() => { + server.listen() +}) + afterEach(() => { queryClient.clear() server.resetHandlers() }) + afterAll(() => { server.close() }) @@ -33,10 +37,9 @@ afterAll(() => { describe('useIsCurrentUserAnAdmin', () => { function setup() { server.use( - graphql.query('DetailOwner', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ + data: { owner: { ownerid: 123, username: 'cool-user', @@ -44,16 +47,15 @@ describe('useIsCurrentUserAnAdmin', () => { isCurrentUserPartOfOrg: true, isAdmin: true, }, - }) - ) - ) + }, + }) + }) ) } describe('when called', () => { - beforeEach(() => setup()) - it('returns boolean value', async () => { + setup() const { result } = renderHook( () => useIsCurrentUserAnAdmin({ owner: 'codecov' }), { wrapper: wrapper() } diff --git a/src/services/user/useMyContexts.spec.tsx b/src/services/user/useMyContexts.test.tsx similarity index 84% rename from src/services/user/useMyContexts.spec.tsx rename to src/services/user/useMyContexts.test.tsx index 7cf8c9de1e..47c2d9519c 100644 --- a/src/services/user/useMyContexts.spec.tsx +++ b/src/services/user/useMyContexts.test.tsx @@ -1,23 +1,23 @@ 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 { useMyContexts } from './useMyContexts' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper: React.FC = ({ children }) => ( {children} ) const orgList1 = { username: 'org1', avatarUrl: 'http://127.0.0.1/avatar-url' } - const orgList2 = { username: 'org2', avatarUrl: 'http://127.0.0.1/avatar-url' } +const server = setupServer() beforeAll(() => { server.listen() }) @@ -38,14 +38,14 @@ interface SetupArgs { describe('useMyContexts', () => { function setup({ badResponse = false }: SetupArgs) { server.use( - graphql.query('MyContexts', (req, res, ctx) => { + graphql.query('MyContexts', (info) => { if (badResponse) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({}) } - const orgList = !!req.variables?.after ? orgList2 : orgList1 - const hasNextPage = req.variables?.after ? false : true - const endCursor = req.variables?.after ? 'second' : 'first' + const orgList = !!info.variables?.after ? orgList2 : orgList1 + const hasNextPage = info.variables?.after ? false : true + const endCursor = info.variables?.after ? 'second' : 'first' const queryData = { me: { @@ -64,7 +64,7 @@ describe('useMyContexts', () => { }, } - return res(ctx.status(200), ctx.data(queryData)) + return HttpResponse.json({ data: queryData }) }) ) } @@ -76,9 +76,6 @@ describe('useMyContexts', () => { wrapper, }) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - const expectedData = { currentUser: { avatarUrl: 'http://127.0.0.1/avatar-url', @@ -105,6 +102,15 @@ describe('useMyContexts', () => { }) describe('and response is bad', () => { + let consoleSpy: MockInstance + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + consoleSpy.mockRestore() + }) + it('throws 404 failed to parse', async () => { console.error = () => {} setup({ badResponse: true }) @@ -112,9 +118,6 @@ describe('useMyContexts', () => { wrapper, }) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.failureReason).toEqual( expect.objectContaining({ @@ -128,9 +131,8 @@ describe('useMyContexts', () => { }) describe('when fetchNextPage is called', () => { - beforeEach(() => setup({})) - it('returns combined data set', async () => { + setup({}) const { result } = renderHook(() => useMyContexts({ provider: 'gh' }), { wrapper, }) diff --git a/src/services/user/useOnboardUser.spec.js b/src/services/user/useOnboardUser.test.jsx similarity index 80% rename from src/services/user/useOnboardUser.spec.js rename to src/services/user/useOnboardUser.test.jsx index 4d6d267c91..215b0cc466 100644 --- a/src/services/user/useOnboardUser.spec.js +++ b/src/services/user/useOnboardUser.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 { useOnboardUser } from './index' @@ -28,41 +28,42 @@ const wrapper = ) const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useOnboardUser', () => { function setup() { server.use( - graphql.mutation('OnboardUser', (req, res, ctx) => { + graphql.mutation('OnboardUser', (info) => { const newUser = { ...user, onboardingCompleted: true, } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { onboardUser: { me: newUser, }, - }) - ) + }, + }) }) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - describe('when calling the mutation', () => { it('returns success', async () => { + setup() const { result } = renderHook(() => useOnboardUser(), { wrapper: wrapper(), }) @@ -73,6 +74,7 @@ describe('useOnboardUser', () => { }) it('updates the local cache', async () => { + setup() const { result } = renderHook(() => useOnboardUser(), { wrapper: wrapper(), }) @@ -92,20 +94,12 @@ describe('useOnboardUser', () => { }) describe('when called with opts', () => { - const onSuccessFn = jest.fn() - beforeEach(() => { - setup() - }) - it('returns onSuccess from opts', async () => { + setup() + const onSuccessFn = jest.fn() const { result } = renderHook( - () => - useOnboardUser({ - onSuccess: onSuccessFn, - }), - { - wrapper: wrapper(), - } + () => useOnboardUser({ onSuccess: onSuccessFn }), + { wrapper: wrapper() } ) result.current.mutate({}) diff --git a/src/services/user/useOwner.spec.js b/src/services/user/useOwner.test.jsx similarity index 54% rename from src/services/user/useOwner.spec.js rename to src/services/user/useOwner.test.jsx index a576068575..9f8df7e8f3 100644 --- a/src/services/user/useOwner.spec.js +++ b/src/services/user/useOwner.test.jsx @@ -1,18 +1,18 @@ 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 { useOwner } from './useOwner' -const server = setupServer() const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, logger: { error: () => {}, }, }) + const wrapper = (initialEntries = '/gh') => ({ children }) => ( @@ -23,22 +23,25 @@ const wrapper = ) -beforeAll(() => server.listen()) +const server = setupServer() +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useOwner', () => { function setup(dataReturned = undefined) { server.use( - graphql.query('DetailOwner', (req, res, ctx) => { - return res( - ctx.data({ - owner: dataReturned, - }) - ) + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ data: { owner: dataReturned } }) }) ) } @@ -51,11 +54,8 @@ describe('useOwner', () => { isAdmin: false, } - beforeEach(() => { - setup(codecovOrg) - }) - it('returns the org', async () => { + setup(codecovOrg) const { result } = renderHook(() => useOwner({ username: 'codecov' }), { wrapper: wrapper(), }) @@ -63,36 +63,4 @@ describe('useOwner', () => { await waitFor(() => expect(result.current.data).toEqual(codecovOrg)) }) }) - - describe('when calling useIsCurrentUserAnAdmin for admins', () => { - const codecovOrg = { - username: 'codecov', - avatarUrl: 'http://127.0.0.1/avatar-url', - isCurrentUserPartOfOrg: true, - isAdmin: true, - } - beforeEach(async () => { - setup(codecovOrg) - }) - - it('returns value', async () => { - const { result: firstResult } = renderHook( - () => useOwner({ username: 'codecov' }), - { - wrapper: wrapper(), - } - ) - - await waitFor(() => expect(firstResult.current.isSuccess)) - - await waitFor(() => - expect(firstResult.current.data).toStrictEqual({ - username: 'codecov', - avatarUrl: 'http://127.0.0.1/avatar-url', - isCurrentUserPartOfOrg: true, - isAdmin: true, - }) - ) - }) - }) }) diff --git a/src/services/user/useOwnerRateLimitStatus.spec.tsx b/src/services/user/useOwnerRateLimitStatus.test.tsx similarity index 67% rename from src/services/user/useOwnerRateLimitStatus.spec.tsx rename to src/services/user/useOwnerRateLimitStatus.test.tsx index b738af491e..aa2d1a9f64 100644 --- a/src/services/user/useOwnerRateLimitStatus.spec.tsx +++ b/src/services/user/useOwnerRateLimitStatus.test.tsx @@ -1,25 +1,19 @@ 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 { useOwnerRateLimitStatus } from './useOwnerRateLimitStatus' const mockRateLimitStatus = { - me: { - owner: { - isGithubRateLimited: true, - }, - }, + me: { owner: { isGithubRateLimited: true } }, } const mockUnsuccessfulParseError = { - owner: { - wrong: 'schema', - }, + owner: { wrong: 'schema' }, } -const server = setupServer() const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) @@ -28,6 +22,7 @@ const wrapper: React.FC = ({ children }) => ( {children} ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -48,11 +43,11 @@ interface SetupArgs { describe('useOwnerRateLimitStatus', () => { function setup({ isUnsuccessfulParseError = false }: SetupArgs) { server.use( - graphql.query('GetOwnerRateLimitStatus', (req, res, ctx) => { + graphql.query('GetOwnerRateLimitStatus', (info) => { if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } - return res(ctx.status(200), ctx.data(mockRateLimitStatus)) + return HttpResponse.json({ data: mockRateLimitStatus }) }) ) } @@ -61,10 +56,7 @@ describe('useOwnerRateLimitStatus', () => { it('fetches the owner rate limit status', async () => { setup({}) const { result } = renderHook( - () => - useOwnerRateLimitStatus({ - provider: 'gh', - }), + () => useOwnerRateLimitStatus({ provider: 'gh' }), { wrapper } ) @@ -77,27 +69,22 @@ describe('useOwnerRateLimitStatus', () => { }) describe('unsuccessful parse of zod schema', () => { - let oldConsoleError = console.error - - beforeEach(() => { - console.error = () => null + let consoleSpy: MockInstance + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) - afterEach(() => { - console.error = oldConsoleError + afterAll(() => { + consoleSpy.mockRestore() }) it('throws a 404', async () => { setup({ isUnsuccessfulParseError: true }) const { result } = renderHook( - () => - useOwnerRateLimitStatus({ - provider: 'gh', - }), + () => useOwnerRateLimitStatus({ provider: 'gh' }), { wrapper } ) - await waitFor(() => expect(result.current.isError).toBeTruthy()) await waitFor(() => expect(result.current.error).toEqual( expect.objectContaining({ diff --git a/src/services/user/useResyncUser.spec.js b/src/services/user/useResyncUser.test.jsx similarity index 84% rename from src/services/user/useResyncUser.spec.js rename to src/services/user/useResyncUser.test.jsx index b25683a341..c6cddce4d1 100644 --- a/src/services/user/useResyncUser.spec.js +++ b/src/services/user/useResyncUser.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 { POLLING_INTERVAL, useResyncUser } from './useResyncUser' @@ -19,15 +19,15 @@ const wrapper = ) -const server = setupServer() - -const invalidateQueriesSpy = jest.spyOn(queryClient, 'invalidateQueries') -const getQueriesDataSpy = jest.spyOn(queryClient, 'getQueriesData') +const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries') +const getQueriesDataSpy = vi.spyOn(queryClient, 'getQueriesData') +const server = setupServer() beforeAll(() => { server.listen() }) -beforeEach(() => { +afterEach(() => { + vi.clearAllMocks() queryClient.clear() server.resetHandlers() }) @@ -37,31 +37,18 @@ afterAll(() => { describe('useResyncUser', () => { let syncStatus = false - function setup() { server.use( - graphql.query('IsSyncing', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ - me: { - isSyncing: syncStatus, - }, - }) - ) + graphql.query('IsSyncing', (info) => { + return HttpResponse.json({ + data: { me: { isSyncing: syncStatus } }, + }) }), - graphql.mutation('SyncData', (req, res, ctx) => { + graphql.mutation('SyncData', (info) => { syncStatus = true - return res( - ctx.status(200), - ctx.data({ - syncWithGitProvider: { - me: { - isSyncing: syncStatus, - }, - }, - }) - ) + return HttpResponse.json({ + data: { syncWithGitProvider: { me: { isSyncing: syncStatus } } }, + }) }) ) } @@ -69,10 +56,10 @@ describe('useResyncUser', () => { describe('when the hook is called and the syncing is not in progress', () => { beforeEach(() => { syncStatus = false - setup() }) it('returns syncing false', async () => { + setup() const { result } = renderHook(() => useResyncUser(), { wrapper: wrapper(), }) @@ -84,10 +71,10 @@ describe('useResyncUser', () => { describe('when the user trigger a sync', () => { beforeEach(() => { syncStatus = false - setup() }) it('returns syncing true', async () => { + setup() const { result } = renderHook(() => useResyncUser(), { wrapper: wrapper(), }) @@ -113,18 +100,17 @@ describe('useResyncUser', () => { }) it('calls invalidate queries on each sync', async () => { - jest.useFakeTimers() + vi.useFakeTimers() const { result } = renderHook(() => useResyncUser(), { wrapper: wrapper(), }) await waitFor(() => expect(result.current.isSyncing).toBe(true)) - await waitFor(() => expect(invalidateQueriesSpy).toHaveBeenCalledTimes(2)) // For some reason number of called times is doubling; but when console logging within the queryFn we see - // that the loop is being entered the correct number of times. This may be some jest weirdness - jest.advanceTimersByTime(POLLING_INTERVAL) + // that the loop is being entered the correct number of times. This may be some vi weirdness + vi.advanceTimersByTime(POLLING_INTERVAL) await waitFor(() => expect(invalidateQueriesSpy).toHaveBeenCalledTimes(4)) @@ -134,12 +120,12 @@ describe('useResyncUser', () => { { pages: { repos: Array.from({ length: 20 }) } }, ]) - jest.advanceTimersByTime(POLLING_INTERVAL) + vi.advanceTimersByTime(POLLING_INTERVAL) await waitFor(() => expect(invalidateQueriesSpy).toHaveBeenCalledTimes(5)) // Confirm that we don't call the query anymore after we've reached the page size - jest.advanceTimersByTime(POLLING_INTERVAL) + vi.advanceTimersByTime(POLLING_INTERVAL) await waitFor(() => expect(invalidateQueriesSpy).toHaveBeenCalledTimes(5)) @@ -157,17 +143,17 @@ describe('useResyncUser', () => { // Call one extra time on success await waitFor(() => expect(invalidateQueriesSpy).toHaveBeenCalledTimes(6)) - jest.useRealTimers() + vi.useRealTimers() }) }) describe('when a sync finishes', () => { beforeEach(() => { syncStatus = true - setup() }) it('returns syncing false', async () => { + setup() const { result } = renderHook(() => useResyncUser(), { wrapper: wrapper(), }) @@ -187,6 +173,7 @@ describe('useResyncUser', () => { }) it('calls invalidateQueries for repos', async () => { + setup() const { result } = renderHook(() => useResyncUser(), { wrapper: wrapper(), }) diff --git a/src/services/user/useUpdateProfile.spec.js b/src/services/user/useUpdateProfile.test.jsx similarity index 84% rename from src/services/user/useUpdateProfile.spec.js rename to src/services/user/useUpdateProfile.test.jsx index 3015044287..9836d3e374 100644 --- a/src/services/user/useUpdateProfile.spec.js +++ b/src/services/user/useUpdateProfile.test.jsx @@ -1,14 +1,14 @@ 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 config from 'config' import { useUpdateProfile } from './useUpdateProfile' -jest.mock('config') +vi.mock('config') const user = { username: 'TerrySmithDC', @@ -21,7 +21,6 @@ const user = { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper = (initialEntries = '/gh') => ({ children }) => ( @@ -32,38 +31,43 @@ const wrapper = ) -beforeAll(() => server.listen()) +const server = setupServer() +beforeAll(() => { + server.listen() +}) + beforeEach(() => { queryClient.clear() server.resetHandlers() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useUpdateProfile', () => { function setup() { server.use( - graphql.mutation('UpdateProfile', (req, res, ctx) => { + graphql.mutation('UpdateProfile', (info) => { const newUser = { ...user, - name: req.variables.input.name, - email: req.variables.input.email, + name: info.variables.input.name, + email: info.variables.input.email, } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { updateProfile: { me: newUser, }, - }) - ) + }, + }) }) ) } describe('when running in self-hosted', () => { beforeEach(() => { - setup() config.IS_SELF_HOSTED = true }) @@ -74,11 +78,10 @@ describe('useUpdateProfile', () => { } it('returns success', async () => { + setup() const { result } = renderHook( () => useUpdateProfile({ provider: 'gh' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(newData) @@ -95,11 +98,10 @@ describe('useUpdateProfile', () => { }) it('returns new user', async () => { + setup() const { result } = renderHook( () => useUpdateProfile({ provider: 'gh' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(newData) @@ -119,7 +121,6 @@ describe('useUpdateProfile', () => { describe('when not running in self-hosted', () => { beforeEach(() => { - setup() config.IS_SELF_HOSTED = false }) @@ -130,11 +131,10 @@ describe('useUpdateProfile', () => { } it('returns success', async () => { + setup() const { result } = renderHook( () => useUpdateProfile({ provider: 'gh' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(newData) @@ -143,11 +143,10 @@ describe('useUpdateProfile', () => { }) it('returns new user', async () => { + setup() const { result } = renderHook( () => useUpdateProfile({ provider: 'gh' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) result.current.mutate(newData) diff --git a/src/services/user/useUser.spec.tsx b/src/services/user/useUser.test.tsx similarity index 82% rename from src/services/user/useUser.spec.tsx rename to src/services/user/useUser.test.tsx index 5dcf023456..874661bff4 100644 --- a/src/services/user/useUser.spec.tsx +++ b/src/services/user/useUser.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 { User, useUser } from './useUser' @@ -70,33 +71,32 @@ const wrapper: (initialEntries?: string) => React.FC = ) const server = setupServer() +beforeAll(() => { + server.listen() +}) -beforeAll(() => server.listen()) beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useUser', () => { function setup(userData: User | {}) { server.use( - graphql.query('CurrentUser', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(userData)) + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ data: userData }) }) ) } describe('when query resolves', () => { describe('there is user data', () => { - beforeEach(() => { - const spy = jest.spyOn(console, 'error') - spy.mockImplementation(jest.fn()) - - setup(user) - }) - it('returns the user', async () => { + setup(user) const { result } = renderHook(() => useUser(), { wrapper: wrapper(), }) @@ -106,14 +106,17 @@ describe('useUser', () => { }) describe('there is no user data', () => { - beforeEach(() => { - const spy = jest.spyOn(console, 'error') - spy.mockImplementation(jest.fn()) + let consoleSpy: MockInstance + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) - setup(nullUser) + afterAll(() => { + consoleSpy.mockRestore() }) it('returns the user', async () => { + setup(nullUser) const { result } = renderHook(() => useUser(), { wrapper: wrapper(), }) @@ -123,14 +126,17 @@ describe('useUser', () => { }) describe('the response is bad', () => { - beforeEach(() => { - const spy = jest.spyOn(console, 'error') - spy.mockImplementation(jest.fn()) + let consoleSpy: MockInstance + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) - setup(badResponse) + afterAll(() => { + consoleSpy.mockRestore() }) it('returns 404 failed to parse', async () => { + setup(badResponse) const { result } = renderHook(() => useUser(), { wrapper: wrapper(), }) From 7abf6b21f4ef5bb6788eee450378ad7a6be7b71f Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Tue, 1 Oct 2024 14:01:07 -0400 Subject: [PATCH 36/44] chore: Update services/selfHosted tests to Vitest (#3307) --- .../selfHosted/{index.js => index.ts} | 0 ...c.js => useSelfHostedCurrentUser.test.jsx} | 28 +++++------ ...pec.js => useSelfHostedHasAdmins.test.jsx} | 49 ++++++------------ ... => useSelfHostedSeatsAndLicense.test.tsx} | 46 +++++++---------- ...c.js => useSelfHostedSeatsConfig.test.jsx} | 28 +++++------ ...pec.tsx => useSelfHostedSettings.test.tsx} | 37 ++++++++------ ...pec.tsx => useSelfHostedUserList.test.tsx} | 50 ++++++++++--------- 7 files changed, 107 insertions(+), 131 deletions(-) rename src/services/selfHosted/{index.js => index.ts} (100%) rename src/services/selfHosted/{useSelfHostedCurrentUser.spec.js => useSelfHostedCurrentUser.test.jsx} (76%) rename src/services/selfHosted/{useSelfHostedHasAdmins.spec.js => useSelfHostedHasAdmins.test.jsx} (54%) rename src/services/selfHosted/{useSelfHostedSeatsAndLicense.spec.tsx => useSelfHostedSeatsAndLicense.test.tsx} (67%) rename src/services/selfHosted/{useSelfHostedSeatsConfig.spec.js => useSelfHostedSeatsConfig.test.jsx} (76%) rename src/services/selfHosted/{useSelfHostedSettings.spec.tsx => useSelfHostedSettings.test.tsx} (71%) rename src/services/selfHosted/{useSelfHostedUserList.spec.tsx => useSelfHostedUserList.test.tsx} (84%) diff --git a/src/services/selfHosted/index.js b/src/services/selfHosted/index.ts similarity index 100% rename from src/services/selfHosted/index.js rename to src/services/selfHosted/index.ts diff --git a/src/services/selfHosted/useSelfHostedCurrentUser.spec.js b/src/services/selfHosted/useSelfHostedCurrentUser.test.jsx similarity index 76% rename from src/services/selfHosted/useSelfHostedCurrentUser.spec.js rename to src/services/selfHosted/useSelfHostedCurrentUser.test.jsx index 12ef216f1b..2adf79df21 100644 --- a/src/services/selfHosted/useSelfHostedCurrentUser.spec.js +++ b/src/services/selfHosted/useSelfHostedCurrentUser.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 { useSelfHostedCurrentUser } from './useSelfHostedCurrentUser' @@ -27,36 +27,36 @@ const wrapper = ({ children }) => ( ) const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useSelfHostedCurrentUser', () => { function setup() { server.use( - rest.get('/internal/users/current', (req, res, ctx) => - res(ctx.status(200), ctx.json(user)) - ) + http.get('/internal/users/current', (info) => { + return HttpResponse.json(user) + }) ) } describe('when called', () => { describe('when data is loaded', () => { - beforeEach(() => { - setup() - }) - it('returns the user info', async () => { + setup() const { result } = renderHook(() => useSelfHostedCurrentUser(), { wrapper, }) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.data).toEqual(user)) }) }) diff --git a/src/services/selfHosted/useSelfHostedHasAdmins.spec.js b/src/services/selfHosted/useSelfHostedHasAdmins.test.jsx similarity index 54% rename from src/services/selfHosted/useSelfHostedHasAdmins.spec.js rename to src/services/selfHosted/useSelfHostedHasAdmins.test.jsx index 9b6e667560..80d05e85a2 100644 --- a/src/services/selfHosted/useSelfHostedHasAdmins.spec.js +++ b/src/services/selfHosted/useSelfHostedHasAdmins.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 { useSelfHostedHasAdmins } from './useSelfHostedHasAdmins' @@ -13,55 +13,36 @@ const wrapper = ({ children }) => ( ) const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useSelfHostedHasAdmins', () => { function setup({ data }) { server.use( - graphql.query('HasAdmins', (req, res, ctx) => - res(ctx.status(200), ctx.data(data)) - ) + graphql.query('HasAdmins', (info) => { + return HttpResponse.json({ data }) + }) ) } describe('when called', () => { - beforeEach(() => { - setup({ data: { config: { hasAdmins: true } } }) - }) - - it('returns isLoading', () => { - const { result } = renderHook( - () => useSelfHostedHasAdmins({ provider: 'gl' }), - { - wrapper, - } - ) - - expect(result.current.isLoading).toBeTruthy() - }) - }) - - describe('when data is loaded', () => { - beforeEach(async () => { - setup({ data: { config: { hasAdmins: true } } }) - }) - it('returns the user info', async () => { + setup({ data: { config: { hasAdmins: true } } }) const { result } = renderHook( () => useSelfHostedHasAdmins({ provider: 'gl' }), - { - wrapper, - } + { wrapper } ) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.data).toEqual(true)) }) }) diff --git a/src/services/selfHosted/useSelfHostedSeatsAndLicense.spec.tsx b/src/services/selfHosted/useSelfHostedSeatsAndLicense.test.tsx similarity index 67% rename from src/services/selfHosted/useSelfHostedSeatsAndLicense.spec.tsx rename to src/services/selfHosted/useSelfHostedSeatsAndLicense.test.tsx index 7c2851fcc0..df93c71590 100644 --- a/src/services/selfHosted/useSelfHostedSeatsAndLicense.spec.tsx +++ b/src/services/selfHosted/useSelfHostedSeatsAndLicense.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 { useSelfHostedSeatsAndLicense } from './useSelfHostedSeatsAndLicense' @@ -9,9 +10,7 @@ const mockSelfHostedLicense = { config: { seatsUsed: 5, seatsLimit: 30, - selfHostedLicense: { - expirationDate: '2020-05-09T00:00:00', - }, + selfHostedLicense: { expirationDate: '2020-05-09T00:00:00' }, }, } @@ -20,12 +19,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() }) @@ -46,11 +45,11 @@ interface SetupArgs { describe('useSelfHostedSeatsAndLicense', () => { function setup({ isUnsuccessfulParseError = false }: SetupArgs) { server.use( - graphql.query('SelfHostedSeatsAndLicense', (req, res, ctx) => { + graphql.query('SelfHostedSeatsAndLicense', (info) => { if (isUnsuccessfulParseError) { - return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + return HttpResponse.json({ data: mockUnsuccessfulParseError }) } else { - return res(ctx.status(200), ctx.data(mockSelfHostedLicense)) + return HttpResponse.json({ data: mockSelfHostedLicense }) } }) ) @@ -62,14 +61,10 @@ describe('useSelfHostedSeatsAndLicense', () => { it('returns the license details', async () => { setup({}) const { result } = renderHook( - () => - useSelfHostedSeatsAndLicense({ - provider: 'gh', - }), + () => useSelfHostedSeatsAndLicense({ provider: 'gh' }), { wrapper } ) - await waitFor(() => result.current.isSuccess) await waitFor(() => expect(result.current.data).toEqual({ seatsUsed: 5, @@ -84,32 +79,25 @@ describe('useSelfHostedSeatsAndLicense', () => { }) describe('unsuccessful parse of zod schema', () => { - beforeEach(() => { - jest.spyOn(console, 'error') + let consoleSpy: MockInstance + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) - afterEach(() => { - jest.resetAllMocks() + afterAll(() => { + consoleSpy.mockRestore() }) it('throws a 404', async () => { setup({ isUnsuccessfulParseError: true }) const { result } = renderHook( - () => - useSelfHostedSeatsAndLicense({ - provider: 'gh', - }), - { - wrapper, - } + () => useSelfHostedSeatsAndLicense({ provider: 'gh' }), + { wrapper } ) - await waitFor(() => expect(result.current.isError).toBeTruthy()) await waitFor(() => expect(result.current.error).toEqual( - expect.objectContaining({ - status: 404, - }) + expect.objectContaining({ status: 404 }) ) ) }) diff --git a/src/services/selfHosted/useSelfHostedSeatsConfig.spec.js b/src/services/selfHosted/useSelfHostedSeatsConfig.test.jsx similarity index 76% rename from src/services/selfHosted/useSelfHostedSeatsConfig.spec.js rename to src/services/selfHosted/useSelfHostedSeatsConfig.test.jsx index 60c03c2feb..cd929a22ce 100644 --- a/src/services/selfHosted/useSelfHostedSeatsConfig.spec.js +++ b/src/services/selfHosted/useSelfHostedSeatsConfig.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 { useSelfHostedSeatsConfig } from './useSelfHostedSeatsConfig' @@ -25,35 +25,35 @@ const wrapper = ({ children }) => ( ) const server = setupServer() -beforeAll(() => server.listen()) +beforeAll(() => { + server.listen() +}) + beforeEach(() => { server.resetHandlers() queryClient.clear() }) -afterAll(() => server.close()) + +afterAll(() => { + server.close() +}) describe('useSelfHostedSeatsConfig', () => { function setup() { server.use( - graphql.query('Seats', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockData)) - ) + graphql.query('Seats', (req, res, ctx) => { + return HttpResponse.json({ data: mockData }) + }) ) } describe('when called', () => { - beforeEach(() => { - setup() - }) - it('returns data', async () => { + setup() const { result } = renderHook(() => useSelfHostedSeatsConfig(), { wrapper, }) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.data).toStrictEqual({ seatsUsed: 5, diff --git a/src/services/selfHosted/useSelfHostedSettings.spec.tsx b/src/services/selfHosted/useSelfHostedSettings.test.tsx similarity index 71% rename from src/services/selfHosted/useSelfHostedSettings.spec.tsx rename to src/services/selfHosted/useSelfHostedSettings.test.tsx index 1e7103c6bd..a271ac4f25 100644 --- a/src/services/selfHosted/useSelfHostedSettings.spec.tsx +++ b/src/services/selfHosted/useSelfHostedSettings.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 { MemoryRouter, Route } from 'react-router-dom' +import { type MockInstance } from 'vitest' import { useSelfHostedSettings } from './useSelfHostedSettings' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const mockResponse = { config: { @@ -27,6 +27,7 @@ const wrapper: React.FC = ({ children }) => ( ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -43,11 +44,11 @@ afterAll(() => { describe('useSelfHostedSettings', () => { function setup({ invalidResponse = false }) { server.use( - graphql.query('SelfHostedSettings', (req, res, ctx) => { + graphql.query('SelfHostedSettings', (info) => { if (invalidResponse) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({}) } - return res(ctx.status(200), ctx.data(mockResponse)) + return HttpResponse.json({ data: mockResponse }) }) ) } @@ -57,9 +58,6 @@ describe('useSelfHostedSettings', () => { setup({}) const { result } = renderHook(() => useSelfHostedSettings(), { wrapper }) - await waitFor(() => result.current.isFetching) - await waitFor(() => !result.current.isFetching) - await waitFor(() => expect(result.current.data).toStrictEqual({ planAutoActivate: true, @@ -71,8 +69,14 @@ describe('useSelfHostedSettings', () => { }) describe('invalid response', () => { + let consoleSpy: MockInstance + beforeAll(() => { - console.error = () => {} + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + consoleSpy.mockRestore() }) it('rejects with 404', async () => { @@ -81,12 +85,13 @@ describe('useSelfHostedSettings', () => { wrapper, }) - await waitFor(() => expect(result.current.isError).toBeTruthy()) - expect(result.current.error).toEqual( - expect.objectContaining({ - status: 404, - dev: 'useSelfHostedSettings - 404 schema parsing failed', - }) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + dev: 'useSelfHostedSettings - 404 schema parsing failed', + }) + ) ) }) }) diff --git a/src/services/selfHosted/useSelfHostedUserList.spec.tsx b/src/services/selfHosted/useSelfHostedUserList.test.tsx similarity index 84% rename from src/services/selfHosted/useSelfHostedUserList.spec.tsx rename to src/services/selfHosted/useSelfHostedUserList.test.tsx index de4e0d70cb..a258bd24e9 100644 --- a/src/services/selfHosted/useSelfHostedUserList.spec.tsx +++ b/src/services/selfHosted/useSelfHostedUserList.test.tsx @@ -1,8 +1,9 @@ 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 { useSelfHostedUserList } from './useSelfHostedUserList' @@ -43,7 +44,6 @@ const mockSecondResponse = { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) -const server = setupServer() const wrapper = (initialEntries = '/gh'): React.FC => ({ children }) => ( @@ -54,6 +54,7 @@ const wrapper = ) +const server = setupServer() beforeAll(() => { server.listen() }) @@ -70,21 +71,19 @@ afterAll(() => { describe('useSelfHostedUserList', () => { function setup({ invalidResponse = false }) { server.use( - rest.get('/internal/users', (req, res, ctx) => { + http.get('/internal/users', (info) => { if (invalidResponse) { - return res(ctx.status(200), ctx.json({})) + return HttpResponse.json({}) } - const { - url: { searchParams }, - } = req + 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) }) ) } @@ -118,9 +117,7 @@ describe('useSelfHostedUserList', () => { setup({}) const { result } = renderHook( () => useSelfHostedUserList({ search: '' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) await waitFor(() => result.current.isLoading) @@ -156,9 +153,7 @@ describe('useSelfHostedUserList', () => { setup({}) const { result } = renderHook( () => useSelfHostedUserList({ search: 'codecov' }), - { - wrapper: wrapper(), - } + { wrapper: wrapper() } ) await waitFor(() => result.current.isFetching) @@ -194,8 +189,14 @@ describe('useSelfHostedUserList', () => { }) describe('endpoint returns invalid data', () => { - beforeEach(() => { - console.error = () => {} + let consoleSpy: MockInstance + + beforeAll(() => { + consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) + + afterAll(() => { + consoleSpy.mockRestore() }) it('rejects with 404', async () => { @@ -204,12 +205,13 @@ describe('useSelfHostedUserList', () => { wrapper: wrapper(), }) - await waitFor(() => expect(result.current.isError).toBeTruthy()) - expect(result.current.error).toEqual( - expect.objectContaining({ - status: 404, - dev: 'useSelfHostedUserList - 404 schema parsing failed', - }) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + dev: 'useSelfHostedUserList - 404 schema parsing failed', + }) + ) ) }) }) From bc9a7e033a094c6ab9c89b10f7e93a65d2cb0be4 Mon Sep 17 00:00:00 2001 From: Codecov Releaser Date: Tue, 1 Oct 2024 14:54:18 -0400 Subject: [PATCH 37/44] Release 24.10.1 (#3341) --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 99454f1510..46cc01256f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -24.9.3 \ No newline at end of file +24.10.1 \ No newline at end of file From 37de42b8e12223ad048b7d4b63a01cd881e622bc Mon Sep 17 00:00:00 2001 From: calvin-codecov Date: Tue, 1 Oct 2024 14:24:22 -0700 Subject: [PATCH 38/44] Cy/vuln 765 (#3342) --- package.json | 2 +- yarn.lock | 33 +++++++++++---------------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index d249ec9d18..4169a8fbd3 100644 --- a/package.json +++ b/package.json @@ -183,7 +183,7 @@ "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^5.0.1", "vitest": "^2.1.1", - "webpack": "^5.84.1", + "webpack": "^5.94.0", "webpackbar": "^6.0.1" }, "engines": { diff --git a/yarn.lock b/yarn.lock index d8b9f203c1..868c90c699 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6159,17 +6159,7 @@ __metadata: languageName: node linkType: hard -"@types/eslint-scope@npm:^3.7.3": - version: 3.7.7 - resolution: "@types/eslint-scope@npm:3.7.7" - dependencies: - "@types/eslint": "npm:*" - "@types/estree": "npm:*" - checksum: 10c0/a0ecbdf2f03912679440550817ff77ef39a30fa8bfdacaf6372b88b1f931828aec392f52283240f0d648cf3055c5ddc564544a626bcf245f3d09fcb099ebe3cc - languageName: node - linkType: hard - -"@types/eslint@npm:*, @types/eslint@npm:^7.29.0 || ^8.4.1": +"@types/eslint@npm:^7.29.0 || ^8.4.1": version: 8.56.10 resolution: "@types/eslint@npm:8.56.10" dependencies: @@ -10209,13 +10199,13 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.17.0": - version: 5.17.0 - resolution: "enhanced-resolve@npm:5.17.0" +"enhanced-resolve@npm:^5.17.1": + version: 5.17.1 + resolution: "enhanced-resolve@npm:5.17.1" dependencies: graceful-fs: "npm:^4.2.4" tapable: "npm:^2.2.0" - checksum: 10c0/90065e58e4fd08e77ba47f827eaa17d60c335e01e4859f6e644bb3b8d0e32b203d33894aee92adfa5121fa262f912b48bdf0d0475e98b4a0a1132eea1169ad37 + checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370 languageName: node linkType: hard @@ -11859,7 +11849,7 @@ __metadata: vite-plugin-svgr: "npm:^4.2.0" vite-tsconfig-paths: "npm:^5.0.1" vitest: "npm:^2.1.1" - webpack: "npm:^5.84.1" + webpack: "npm:^5.94.0" webpackbar: "npm:^6.0.1" zod: "npm:^3.21.4" languageName: unknown @@ -22312,11 +22302,10 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5, webpack@npm:^5.64.4, webpack@npm:^5.84.1": - version: 5.93.0 - resolution: "webpack@npm:5.93.0" +"webpack@npm:5, webpack@npm:^5.64.4, webpack@npm:^5.94.0": + version: 5.95.0 + resolution: "webpack@npm:5.95.0" dependencies: - "@types/eslint-scope": "npm:^3.7.3" "@types/estree": "npm:^1.0.5" "@webassemblyjs/ast": "npm:^1.12.1" "@webassemblyjs/wasm-edit": "npm:^1.12.1" @@ -22325,7 +22314,7 @@ __metadata: acorn-import-attributes: "npm:^1.9.5" browserslist: "npm:^4.21.10" chrome-trace-event: "npm:^1.0.2" - enhanced-resolve: "npm:^5.17.0" + enhanced-resolve: "npm:^5.17.1" es-module-lexer: "npm:^1.2.1" eslint-scope: "npm:5.1.1" events: "npm:^3.2.0" @@ -22345,7 +22334,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 10c0/f0c72f1325ff57a4cc461bb978e6e1296f2a7d45c9765965271aa686ccdd448512956f4d7fdcf8c164d073af046c5a0aba17ce85ea98e33e5e2bfbfe13aa5808 + checksum: 10c0/b9e6d0f8ebcbf0632494ac0b90fe4acb8f4a9b83f7ace4a67a15545a36fe58599c912ab58e625e1bf58ab3b0916c75fe99da6196d412ee0cab0b5065edd84238 languageName: node linkType: hard From 622d0fbb60257be687a9213bfd2e48b3cc765ab3 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 09:40:38 -0300 Subject: [PATCH 39/44] chore: Update pages/RepoPage/FailedTestsTab tests to Vitest (#3343) --- ...odecovCLI.spec.tsx => CodecovCLI.test.tsx} | 3 +- ...tsTab.spec.tsx => FailedTestsTab.test.tsx} | 69 +++++++++------- ...ector.spec.tsx => BranchSelector.test.tsx} | 78 ++++++++++--------- ...ble.spec.tsx => FailedTestsTable.test.tsx} | 71 +++++++---------- .../FailedTestsTable/FailedTestsTable.tsx | 2 +- ...rkTabs.spec.tsx => FrameworkTabs.test.tsx} | 0 ...rd.spec.tsx => FrameworkTabsCard.test.tsx} | 3 +- ...ctions.spec.tsx => GitHubActions.test.tsx} | 3 +- ...ec.tsx => useInfiniteTestResults.test.tsx} | 16 ++-- 9 files changed, 121 insertions(+), 124 deletions(-) rename src/pages/RepoPage/FailedTestsTab/CodecovCLI/{CodecovCLI.spec.tsx => CodecovCLI.test.tsx} (99%) rename src/pages/RepoPage/FailedTestsTab/{FailedTestsTab.spec.tsx => FailedTestsTab.test.tsx} (86%) rename src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/{BranchSelector.spec.tsx => BranchSelector.test.tsx} (85%) rename src/pages/RepoPage/FailedTestsTab/FailedTestsTable/{FailedTestsTable.spec.tsx => FailedTestsTable.test.tsx} (89%) rename src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabs/{FrameworkTabs.spec.tsx => FrameworkTabs.test.tsx} (100%) rename src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/{FrameworkTabsCard.spec.tsx => FrameworkTabsCard.test.tsx} (94%) rename src/pages/RepoPage/FailedTestsTab/GitHubActions/{GitHubActions.spec.tsx => GitHubActions.test.tsx} (99%) rename src/pages/RepoPage/FailedTestsTab/hooks/{useInfiniteTestResults.spec.tsx => useInfiniteTestResults.test.tsx} (93%) diff --git a/src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.spec.tsx b/src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.test.tsx similarity index 99% rename from src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.test.tsx index decf466f63..0c356b23f5 100644 --- a/src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.test.tsx @@ -19,8 +19,7 @@ const wrapper: (initialEntries?: string) => React.FC = ) -jest.mock('../FrameworkTabsCard', () => ({ - __esModule: true, +vi.mock('../FrameworkTabsCard', () => ({ FrameworkTabsCard: () => 'FrameworkTabsCard', })) diff --git a/src/pages/RepoPage/FailedTestsTab/FailedTestsTab.spec.tsx b/src/pages/RepoPage/FailedTestsTab/FailedTestsTab.test.tsx similarity index 86% rename from src/pages/RepoPage/FailedTestsTab/FailedTestsTab.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/FailedTestsTab.test.tsx index 146e76a23e..06bcb8d74d 100644 --- a/src/pages/RepoPage/FailedTestsTab/FailedTestsTab.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/FailedTestsTab.test.tsx @@ -1,26 +1,40 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { PropsWithChildren, Suspense } from 'react' import { MemoryRouter, Route, useLocation } from 'react-router-dom' -import { useRedirect } from 'shared/useRedirect' - import FailedTestsTab from './FailedTestsTab' -jest.mock('./GitHubActions', () => () => 'GitHub Actions tab') -jest.mock('./CodecovCLI', () => () => 'Codecov CLI tab') -jest.mock( - './FailedTestsTable/FailedTestsTable.tsx', - () => () => 'Failed Tests Table' -) -jest.mock('./FailedTestsTable/BranchSelector', () => () => 'Branch Selector') -jest.mock('../ActivationAlert', () => () => 'Activation Alert') - -jest.mock('shared/useRedirect') -const mockedUseRedirect = useRedirect as jest.Mock +const mocks = vi.hoisted(() => ({ + useRedirect: vi.fn(), +})) + +vi.mock('./GitHubActions', () => ({ + default: () => 'GitHub Actions tab', +})) +vi.mock('./CodecovCLI', () => ({ + default: () => 'Codecov CLI tab', +})) +vi.mock('./FailedTestsTable/FailedTestsTable.tsx', () => ({ + default: () => 'Failed Tests Table', +})) +vi.mock('./FailedTestsTable/BranchSelector', () => ({ + default: () => 'Branch Selector', +})) +vi.mock('../ActivationAlert', () => ({ + default: () => 'Activation Alert', +})) + +vi.mock('shared/useRedirect', async () => { + const actual = await vi.importActual('shared/useRedirect') + return { + ...actual, + useRedirect: mocks.useRedirect, + } +}) let testLocation: ReturnType @@ -97,8 +111,8 @@ const mockRepoOverview = ({ } describe('FailedTestsTab', () => { - const hardRedirect = jest.fn() - mockedUseRedirect.mockImplementation((data) => ({ + const hardRedirect = vi.fn() + mocks.useRedirect.mockImplementation((data) => ({ hardRedirect: () => hardRedirect(data), })) @@ -112,20 +126,17 @@ describe('FailedTestsTab', () => { isPrivate?: boolean }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { if (testEnabled) { - return res( - ctx.status(200), - ctx.data( - mockRepoOverview({ - testAnalyticsEnabled: true, - isCurrentUserActivated, - isPrivate, - }) - ) - ) + return HttpResponse.json({ + data: mockRepoOverview({ + testAnalyticsEnabled: true, + isCurrentUserActivated, + isPrivate, + }), + }) } - return res(ctx.status(200), ctx.data(mockRepoOverview({}))) + return HttpResponse.json({ data: mockRepoOverview({}) }) }) ) diff --git a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.spec.tsx b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.test.tsx similarity index 85% rename from src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.test.tsx index 0738886e73..65613a0d70 100644 --- a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/BranchSelector/BranchSelector.test.tsx @@ -1,18 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import BranchSelector from './BranchSelector' -jest.mock('react-use/lib/useIntersection') -const mockedUseIntersection = useIntersection as unknown as jest.Mock<{ - isIntersecting: boolean -}> +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), +})) + +vi.mock('react-use', async () => { + const original = await vi.importActual('react-use') + return { + ...original, + useIntersection: mocks.useIntersection, + } +}) const mockRepoOverview = { __typename: 'Repository', @@ -156,25 +162,24 @@ describe('BranchSelector', () => { }) server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { if (nullOverview) { - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) + }, + }) }), - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { let branch = 'main' - if (req.variables?.branch) { - branch = req.variables?.branch + if (info.variables?.branch) { + branch = info.variables?.branch } let mockedBranch = mockBranch(branch) @@ -182,35 +187,32 @@ describe('BranchSelector', () => { mockedBranch = mockBranch(branch, null) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockedBranch }, }, - }) - ) + }, + }) }), - 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 === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches(hasNextPage) } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) } }, + }) }) ) @@ -302,7 +304,7 @@ describe('BranchSelector', () => { hasNextPage: false, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) @@ -325,7 +327,7 @@ describe('BranchSelector', () => { hasNextPage: true, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) diff --git a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.spec.tsx b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.test.tsx similarity index 89% rename from src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.test.tsx index 2ea5f498eb..119ad7ad55 100644 --- a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.test.tsx @@ -6,8 +6,8 @@ import { waitForElementToBeRemoved, } 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 { mockIsIntersecting } from 'react-intersection-observer/test-utils' import { MemoryRouter, Route } from 'react-router-dom' @@ -58,8 +58,16 @@ const wrapper = ) +let consoleError: any +let consoleWarn: any + beforeAll(() => { server.listen() + // Mock console.error and console.warn + consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}) + consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + + vi.useFakeTimers().setSystemTime(new Date('2024-06-01T00:00:00Z')) }) afterEach(() => { @@ -68,21 +76,10 @@ afterEach(() => { afterAll(() => { server.close() -}) - -let consoleError: any -let consoleWarn: any - -beforeEach(() => { - // Mock console.error and console.warn - consoleError = jest.spyOn(console, 'error').mockImplementation(() => {}) - consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {}) -}) - -afterEach(() => { // Restore console methods consoleError.mockRestore() consoleWarn.mockRestore() + vi.useRealTimers() }) interface SetupArgs { @@ -94,16 +91,16 @@ describe('FailedTestsTable', () => { function setup({ noEntries = false }: SetupArgs) { const queryClient = new QueryClient() - const user = userEvent.setup() - const mockVariables = jest.fn() + const user = userEvent.setup({ delay: null }) + const mockVariables = vi.fn() server.use( - graphql.query('GetTestResults', (req, res, ctx) => { - mockVariables(req.variables) + graphql.query('GetTestResults', (info) => { + mockVariables(info.variables) + if (noEntries) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -116,8 +113,8 @@ describe('FailedTestsTable', () => { }, }, }, - }) - ) + }, + }) } const dataReturned = { @@ -125,23 +122,12 @@ describe('FailedTestsTable', () => { repository: { __typename: 'Repository', testResults: { - edges: req.variables.after - ? [ - { - node: node3, - }, - ] - : [ - { - node: node1, - }, - { - node: node2, - }, - ], + edges: info.variables.after + ? [{ node: node3 }] + : [{ node: node1 }, { node: node2 }], pageInfo: { - hasNextPage: req.variables.after ? false : true, - endCursor: req.variables.after + hasNextPage: info.variables.after ? false : true, + endCursor: info.variables.after ? 'aa' : 'MjAyMC0wOC0xMSAxNzozMDowMiswMDowMHwxMDA=', }, @@ -149,7 +135,7 @@ describe('FailedTestsTable', () => { }, }, } - return res(ctx.status(200), ctx.data(dataReturned)) + return HttpResponse.json({ data: dataReturned }) }) ) @@ -214,8 +200,9 @@ describe('FailedTestsTable', () => { wrapper: wrapper(queryClient), }) - expect(consoleError).not.toHaveBeenCalled() - expect(consoleWarn).not.toHaveBeenCalled() + const tableBody = screen.getByTestId('failed-tests-table-body') + // waiting for the loading element to be removed + await waitFor(() => expect(tableBody).toBeEmptyDOMElement()) }) }) diff --git a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.tsx b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.tsx index 6517a014e4..67afa1d539 100644 --- a/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.tsx +++ b/src/pages/RepoPage/FailedTestsTab/FailedTestsTable/FailedTestsTable.tsx @@ -228,7 +228,7 @@ const FailedTestsTable = () => { ))} - + {isLoading ? ( diff --git a/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabs/FrameworkTabs.spec.tsx b/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabs/FrameworkTabs.test.tsx similarity index 100% rename from src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabs/FrameworkTabs.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabs/FrameworkTabs.test.tsx diff --git a/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.spec.tsx b/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.test.tsx similarity index 94% rename from src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.test.tsx index 37964db8fc..04d2752378 100644 --- a/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/FrameworkTabsCard/FrameworkTabsCard.test.tsx @@ -3,8 +3,7 @@ import userEvent from '@testing-library/user-event' import { FrameworkTabsCard } from './FrameworkTabsCard' -jest.mock('./FrameworkTabs', () => ({ - __esModule: true, +vi.mock('./FrameworkTabs', () => ({ FrameworkTabs: () => 'FrameworkTabs', })) diff --git a/src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.spec.tsx b/src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.test.tsx similarity index 99% rename from src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.test.tsx index edf4b08a19..fa096773c9 100644 --- a/src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/GitHubActions/GitHubActions.test.tsx @@ -7,8 +7,7 @@ import { ThemeContextProvider } from 'shared/ThemeContext' import GitHubActions from './GitHubActions' -jest.mock('../FrameworkTabsCard', () => ({ - __esModule: true, +vi.mock('../FrameworkTabsCard', () => ({ FrameworkTabsCard: () => 'FrameworkTabsCard', })) diff --git a/src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.spec.tsx b/src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.test.tsx similarity index 93% rename from src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.spec.tsx rename to src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.test.tsx index 5589d77531..99fd7d5b04 100644 --- a/src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.spec.tsx +++ b/src/pages/RepoPage/FailedTestsTab/hooks/useInfiniteTestResults.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 { useInfiniteTestResults } from './useInfiniteTestResults' @@ -98,17 +98,17 @@ describe('useInfiniteTestResults', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('GetTestResults', (req, res, ctx) => { + graphql.query('GetTestResults', (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(mockTestResults)) + return HttpResponse.json({ data: mockTestResults }) } }) ) From f3fdc67bb83413d0b70492bc94a1a6e5a19be78e Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 09:59:17 -0300 Subject: [PATCH 40/44] chore: Update pages/RepoPage/CoverageTab tests to Vitest (#3335) --- ...ners.spec.tsx => BackfillBanners.test.tsx} | 17 ++- .../BackfillBanners/BackfillBanners.tsx | 2 +- ...Banner.spec.tsx => SyncingBanner.test.tsx} | 3 +- ...er.spec.tsx => TriggerSyncBanner.test.tsx} | 20 +-- ....tsx => useRepoBackfillingStatus.test.tsx} | 12 +- .../{hooks.ts => useRepoBackfillingStatus.ts} | 0 ...ntsTab.spec.tsx => ComponentsTab.test.tsx} | 76 +++++------ .../ComponentsTab/ComponentsTab.tsx | 2 +- ...ector.spec.tsx => BranchSelector.test.tsx} | 82 ++++++------ .../{Header.spec.tsx => Header.test.tsx} | 27 ++-- ...ed.spec.tsx => TimescaleDisabled.test.tsx} | 3 +- ...able.spec.tsx => ComponentsTable.test.tsx} | 33 +++-- ...spec.tsx => DeleteComponentModal.test.tsx} | 14 +- ...kline.spec.tsx => TableSparkline.test.tsx} | 0 ...ec.tsx => useRepoComponentsTable.test.tsx} | 29 ++-- ...erageTab.spec.tsx => CoverageTab.test.tsx} | 26 ++-- .../BackfillBanners/BackfillBanners.jsx | 2 +- ...ners.spec.jsx => BackfillBanners.test.jsx} | 21 ++- ...Banner.spec.tsx => SyncingBanner.test.tsx} | 3 +- ...er.spec.tsx => TriggerSyncBanner.test.tsx} | 47 ++++--- ...ec.ts => useRepoBackfillingStatus.test.ts} | 17 ++- .../{hooks.ts => useRepoBackfillingStatus.ts} | 0 .../CoverageTab/FlagsTab/FlagsTab.jsx | 5 +- .../{FlagsTab.spec.jsx => FlagsTab.test.jsx} | 74 ++++++----- .../{Header.spec.jsx => Header.test.jsx} | 65 ++++++--- ...ed.spec.tsx => TimescaleDisabled.test.tsx} | 3 +- ...odal.spec.tsx => DeleteFlagModal.test.tsx} | 22 ++-- ...lagsTable.spec.tsx => FlagsTable.test.tsx} | 45 +++---- .../subroute/FlagsTable/FlagsTable.tsx | 2 +- ...kline.spec.tsx => TableSparkline.test.tsx} | 0 ...le.spec.tsx => useRepoFlagsTable.test.tsx} | 86 +++++++----- ...ec.tsx => FirstPullRequestBanner.test.tsx} | 0 ...rviewTab.spec.tsx => OverviewTab.test.tsx} | 124 +++++++++--------- ...eTrend.spec.jsx => CoverageTrend.test.jsx} | 34 +++-- .../{Summary.spec.jsx => Summary.test.jsx} | 123 +++++++++-------- ...opdown.spec.jsx => TrendDropdown.test.jsx} | 0 ...Plan.spec.tsx => SummaryTeamPlan.test.tsx} | 119 +++++++++-------- .../SummaryTeamPlan/SummaryTeamPlan.tsx | 7 +- .../OverviewTab/hooks/{index.js => index.ts} | 0 ...or.spec.tsx => useBranchSelector.test.tsx} | 10 +- ...a.spec.tsx => useCoverageTabData.test.tsx} | 20 +-- ....js => useRepoCoverageTimeseries.test.jsx} | 22 ++-- ...pec.tsx => ComponentsMultiSelect.test.tsx} | 56 ++++---- ...eChart.spec.jsx => CoverageChart.test.jsx} | 36 +++-- ...eTable.spec.tsx => CodeTreeTable.test.tsx} | 58 ++++---- .../CodeTreeTable/{index.js => index.ts} | 0 ...xplorer.spec.jsx => FileExplorer.test.jsx} | 43 +++--- ...tTable.spec.tsx => FileListTable.test.tsx} | 44 +++---- .../FileListTable/{index.js => index.ts} | 0 ...lect.spec.jsx => FlagMultiSelect.test.jsx} | 48 ++++--- .../FileExplorer/hooks/{index.js => index.ts} | 0 ...sx => useRepoBranchContentsTable.test.tsx} | 18 +-- ...t.spec.tsx => RepoContentsResult.test.tsx} | 24 ++-- .../shared/{index.js => index.ts} | 0 ...ileviewer.spec.jsx => Fileviewer.test.jsx} | 69 +++++----- .../{Sunburst.spec.jsx => Sunburst.test.jsx} | 33 +++-- ....js => useConvertD3ToBreadcrumbs.test.jsx} | 8 +- ...hart.spec.js => useSunburstChart.test.jsx} | 49 ++++--- ....spec.tsx => useCoverageRedirect.test.tsx} | 23 ++-- ...seSummary.spec.tsx => useSummary.test.tsx} | 57 ++++---- 60 files changed, 928 insertions(+), 835 deletions(-) rename src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/{BackfillBanners.spec.tsx => BackfillBanners.test.tsx} (84%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/{SyncingBanner.spec.tsx => SyncingBanner.test.tsx} (94%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/{TriggerSyncBanner.spec.tsx => TriggerSyncBanner.test.tsx} (85%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/{hooks.spec.tsx => useRepoBackfillingStatus.test.tsx} (89%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/{hooks.ts => useRepoBackfillingStatus.ts} (100%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/{ComponentsTab.spec.tsx => ComponentsTab.test.tsx} (84%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/{BranchSelector.spec.tsx => BranchSelector.test.tsx} (82%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/Header/{Header.spec.tsx => Header.test.tsx} (91%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/{TimescaleDisabled.spec.tsx => TimescaleDisabled.test.tsx} (95%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/{ComponentsTable.spec.tsx => ComponentsTable.test.tsx} (92%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/{DeleteComponentModal.spec.tsx => DeleteComponentModal.test.tsx} (92%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/TableEntries/{TableSparkline.spec.tsx => TableSparkline.test.tsx} (100%) rename src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/{useRepoComponentsTable.spec.tsx => useRepoComponentsTable.test.tsx} (93%) rename src/pages/RepoPage/CoverageTab/{CoverageTab.spec.tsx => CoverageTab.test.tsx} (93%) rename src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/{BackfillBanners.spec.jsx => BackfillBanners.test.jsx} (58%) rename src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/{SyncingBanner.spec.tsx => SyncingBanner.test.tsx} (95%) rename src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/{TriggerSyncBanner.spec.tsx => TriggerSyncBanner.test.tsx} (69%) rename src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/{hooks.spec.ts => useRepoBackfillingStatus.test.ts} (81%) rename src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/{hooks.ts => useRepoBackfillingStatus.ts} (100%) rename src/pages/RepoPage/CoverageTab/FlagsTab/{FlagsTab.spec.jsx => FlagsTab.test.jsx} (85%) rename src/pages/RepoPage/CoverageTab/FlagsTab/Header/{Header.spec.jsx => Header.test.jsx} (82%) rename src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/{TimescaleDisabled.spec.tsx => TimescaleDisabled.test.tsx} (95%) rename src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/{DeleteFlagModal.spec.tsx => DeleteFlagModal.test.tsx} (85%) rename src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/{FlagsTable.spec.tsx => FlagsTable.test.tsx} (91%) rename src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/TableEntries/{TableSparkline.spec.tsx => TableSparkline.test.tsx} (100%) rename src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/{useRepoFlagsTable.spec.tsx => useRepoFlagsTable.test.tsx} (81%) rename src/pages/RepoPage/CoverageTab/OverviewTab/FirstPullRequestBanner/{FirstPullRequestBanner.spec.tsx => FirstPullRequestBanner.test.tsx} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/{OverviewTab.spec.tsx => OverviewTab.test.tsx} (78%) rename src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/{CoverageTrend.spec.jsx => CoverageTrend.test.jsx} (71%) rename src/pages/RepoPage/CoverageTab/OverviewTab/Summary/{Summary.spec.jsx => Summary.test.jsx} (80%) rename src/pages/RepoPage/CoverageTab/OverviewTab/Summary/TrendDropdown/{TrendDropdown.spec.jsx => TrendDropdown.test.jsx} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/{SummaryTeamPlan.spec.tsx => SummaryTeamPlan.test.tsx} (80%) rename src/pages/RepoPage/CoverageTab/OverviewTab/hooks/{index.js => index.ts} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/hooks/{useBranchSelector.spec.tsx => useBranchSelector.test.tsx} (96%) rename src/pages/RepoPage/CoverageTab/OverviewTab/hooks/{useCoverageTabData.spec.tsx => useCoverageTabData.test.tsx} (91%) rename src/pages/RepoPage/CoverageTab/OverviewTab/hooks/{useRepoCoverageTimeseries.spec.js => useRepoCoverageTimeseries.test.jsx} (93%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/{ComponentsMultiSelect.spec.tsx => ComponentsMultiSelect.test.tsx} (88%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/{CoverageChart.spec.jsx => CoverageChart.test.jsx} (87%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/{CodeTreeTable.spec.tsx => CodeTreeTable.test.tsx} (93%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/{index.js => index.ts} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/{FileExplorer.spec.jsx => FileExplorer.test.jsx} (83%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/{FileListTable.spec.tsx => FileListTable.test.tsx} (93%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/{index.js => index.ts} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/{FlagMultiSelect.spec.jsx => FlagMultiSelect.test.jsx} (88%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/{index.js => index.ts} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/{useRepoBranchContentsTable.spec.tsx => useRepoBranchContentsTable.test.tsx} (94%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/{RepoContentsResult.spec.tsx => RepoContentsResult.test.tsx} (92%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/{index.js => index.ts} (100%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/{Fileviewer.spec.jsx => Fileviewer.test.jsx} (80%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/{Sunburst.spec.jsx => Sunburst.test.jsx} (76%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/{useConvertD3ToBreadcrumbs.spec.js => useConvertD3ToBreadcrumbs.test.jsx} (95%) rename src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/{useSunburstChart.spec.js => useSunburstChart.test.jsx} (82%) rename src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/{useCoverageRedirect.spec.tsx => useCoverageRedirect.test.tsx} (92%) rename src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/{useSummary.spec.tsx => useSummary.test.tsx} (84%) diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.test.tsx similarity index 84% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.test.tsx index de722acabd..5d5a8cb838 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.test.tsx @@ -1,14 +1,13 @@ -import { render, screen } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { render, screen } from '@testing-library/react' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import BackfillBanners from './BackfillBanners' -jest.mock('./TriggerSyncBanner', () => () => 'TriggerSyncBanner') -jest.mock('./SyncingBanner', () => () => 'SyncingBanner') +vi.mock('./TriggerSyncBanner', () => ({ default: () => 'TriggerSyncBanner' })) +vi.mock('./SyncingBanner', () => ({ default: () => 'SyncingBanner' })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -40,9 +39,9 @@ afterAll(() => { describe('BackfillBanner', () => { function setup(data = {}) { server.use( - graphql.query('BackfillComponentMemberships', (req, res, ctx) => - res(ctx.status(200), ctx.data(data)) - ) + graphql.query('BackfillComponentMemberships', (info) => { + return HttpResponse.json({ data }) + }) ) } diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.tsx index 39946db69b..38d9298869 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/BackfillBanners.tsx @@ -1,6 +1,6 @@ -import { useRepoBackfillingStatus } from './hooks' import SyncingBanner from './SyncingBanner' import TriggerSyncBanner from './TriggerSyncBanner' +import { useRepoBackfillingStatus } from './useRepoBackfillingStatus' function BackfillBanners() { const { componentsMeasurementsActive, isRepoBackfilling } = diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx similarity index 94% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx index 855f31f1ef..f97c2847cd 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx @@ -1,6 +1,5 @@ -import { render, screen } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' import SyncingBanner from './SyncingBanner' diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx similarity index 85% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx index a21bbe1c2f..844d491751 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx @@ -1,10 +1,8 @@ -import { render, screen } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { waitFor } from '@testing-library/react' +import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' import TriggerSyncBanner from './TriggerSyncBanner' @@ -41,16 +39,18 @@ afterAll(() => { }) describe('TriggerSyncBanner', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) function setup() { const user = userEvent.setup() - const mutate = jest.fn() + const mutate = vi.fn() server.use( - graphql.mutation('ActivateMeasurements', (req, res, ctx) => { - mutate(req.variables) - return res(ctx.status(200), ctx.data({})) + graphql.mutation('ActivateMeasurements', (info) => { + mutate(info.variables) + return HttpResponse.json({ data: { activateMeasurements: null } }) }) ) return { mutate, user } diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/hooks.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/useRepoBackfillingStatus.test.tsx similarity index 89% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/hooks.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/useRepoBackfillingStatus.test.tsx index 74ab24756a..1cfe89ea1f 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/hooks.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/useRepoBackfillingStatus.test.tsx @@ -1,10 +1,10 @@ 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 { useRepoBackfillingStatus } from './hooks' +import { useRepoBackfillingStatus } from './useRepoBackfillingStatus' const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -66,9 +66,9 @@ const mockBackfillInProgress = { describe('BackfillComponentMemberships', () => { function setup(data = mockBackfillComplete) { server.use( - graphql.query('BackfillComponentMemberships', (req, res, ctx) => - res(ctx.status(200), ctx.data(data)) - ) + graphql.query('BackfillComponentMemberships', (info) => { + return HttpResponse.json({ data }) + }) ) } diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/hooks.ts b/src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/useRepoBackfillingStatus.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/hooks.ts rename to src/pages/RepoPage/CoverageTab/ComponentsTab/BackfillBanners/useRepoBackfillingStatus.ts diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.test.tsx similarity index 84% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.test.tsx index 1b4071caa5..0fdba0abb9 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.test.tsx @@ -1,8 +1,8 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -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' @@ -10,23 +10,20 @@ import { TierNames, TTierNames } from 'services/tier' import ComponentsTab from './ComponentsTab' -jest.mock('shared/featureFlags') - -jest.mock( - './BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.tsx', - () => () => 'Trigger Sync Banner' -) -jest.mock( - './BackfillBanners/SyncingBanner/SyncingBanner.tsx', - () => () => 'Syncing Banner' -) -jest.mock( - './subroute/ComponentsTable/ComponentsTable', - () => () => 'Components table' -) -jest.mock('./Header', () => ({ children }: { children: React.ReactNode }) => ( -

    Components Header Component {children}

    -)) +vi.mock('./BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.tsx', () => ({ + default: () => 'Trigger Sync Banner', +})) +vi.mock('./BackfillBanners/SyncingBanner/SyncingBanner.tsx', () => ({ + default: () => 'Syncing Banner', +})) +vi.mock('./subroute/ComponentsTable/ComponentsTable', () => ({ + default: () => 'Components table', +})) +vi.mock('./Header', () => ({ + default: ({ children }: { children: React.ReactNode }) => ( +

    Components Header Component {children}

    + ), +})) const mockRepoSettings = ( isPrivate = false, @@ -167,43 +164,40 @@ describe('Components Tab', () => { isCurrentUserPartOfOrg?: boolean }) { server.use( - graphql.query('OwnerTier', (req, res, ctx) => { + graphql.query('OwnerTier', (info) => { if (tierValue === TierNames.TEAM) { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.TEAM } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.TEAM } } }, + }) } - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.PRO } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.PRO } } }, + }) }), - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepoSettings(isPrivate, isCurrentUserPartOfOrg)) - ) + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ + data: mockRepoSettings(isPrivate, isCurrentUserPartOfOrg), + }) + }), + graphql.query('BackfillComponentMemberships', (info) => { + return HttpResponse.json({ data }) }), - graphql.query('BackfillComponentMemberships', (req, res, ctx) => - res(ctx.status(200), ctx.data(data)) - ), - graphql.query('FlagsSelect', (req, res, ctx) => { + graphql.query('FlagsSelect', (info) => { const dataReturned = { owner: { repository: { __typename: 'Repository', flags: { - edges: req.variables.after ? [...flags[0]] : [...flags[1]], + edges: info.variables.after ? [...flags[0]] : [...flags[1]], pageInfo: { - hasNextPage: !req.variables.after, - endCursor: req.variables.after ? 'aabb' : 'dW5pdA==', + hasNextPage: !info.variables.after, + endCursor: info.variables.after ? 'aabb' : 'dW5pdA==', }, }, }, }, } - return res(ctx.status(200), ctx.data(dataReturned)) + return HttpResponse.json({ data: dataReturned }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.tsx index 262a280fd3..1a1ff3aa0e 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/ComponentsTab.tsx @@ -6,7 +6,7 @@ import { useRepoSettingsTeam } from 'services/repo' import { TierNames, useTier } from 'services/tier' import BackfillBanners from './BackfillBanners/BackfillBanners' -import { useRepoBackfillingStatus } from './BackfillBanners/hooks' +import { useRepoBackfillingStatus } from './BackfillBanners/useRepoBackfillingStatus' import Header from './Header' import ComponentsTable from './subroute/ComponentsTable/ComponentsTable' import TimescaleDisabled from './TimescaleDisabled' diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.test.tsx similarity index 82% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.test.tsx index e91b643dc6..4fa3fa65d5 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/BranchSelector/BranchSelector.test.tsx @@ -1,18 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import BranchSelector from './BranchSelector' -jest.mock('react-use/lib/useIntersection') -const mockedUseIntersection = useIntersection as unknown as jest.Mock<{ - isIntersecting: boolean -}> +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 mockRepoOverview = { __typename: 'Repository', @@ -131,8 +137,8 @@ describe('BranchSelector', () => { } ) { const user = userEvent.setup() - const fetchNextPage = jest.fn() - const mockSearching = jest.fn() + const fetchNextPage = vi.fn() + const mockSearching = vi.fn() const queryClient = new QueryClient({ defaultOptions: { @@ -144,56 +150,52 @@ describe('BranchSelector', () => { }) server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { if (nullOverview) { - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) + }, + }) }), - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { let branch = 'main' - if (req.variables?.branch) { - branch = req.variables?.branch + if (info.variables?.branch) { + branch = info.variables?.branch } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch(branch) }, }, - }) - ) + }, + }) }), - 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 === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches(hasNextPage) } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) } }, + }) }) ) @@ -259,7 +261,7 @@ describe('BranchSelector', () => { hasNextPage: false, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) @@ -282,7 +284,7 @@ describe('BranchSelector', () => { hasNextPage: true, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.test.tsx similarity index 91% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.test.tsx index 0809393bc4..10faf2b6f9 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/Header/Header.test.tsx @@ -1,14 +1,13 @@ -import { render, screen, waitFor } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' import Header from './Header' -jest.mock('./BranchSelector', () => () => 'BranchSelector') +vi.mock('./BranchSelector', () => ({ default: () => 'BranchSelector' })) const server = setupServer() const queryClient = new QueryClient() @@ -80,20 +79,22 @@ const mockResponse = { } describe('Header', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) function setup() { const user = userEvent.setup() - const mockApiVars = jest.fn() + const mockApiVars = vi.fn() server.use( - graphql.query('BackfillComponentMemberships', (req, res, ctx) => - res(ctx.status(200), ctx.data(backfillData)) - ), - graphql.query('RepoComponentsSelector', (req, res, ctx) => { - mockApiVars(req.variables) + graphql.query('BackfillComponentMemberships', (info) => { + return HttpResponse.json({ data: backfillData }) + }), + graphql.query('RepoComponentsSelector', (info) => { + mockApiVars(info.variables) - return res(ctx.status(200), ctx.data(mockResponse)) + return HttpResponse.json({ data: mockResponse }) }) ) diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.test.tsx similarity index 95% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.test.tsx index 5e3b6bd379..e17c3bdb59 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/TimescaleDisabled/TimescaleDisabled.test.tsx @@ -1,5 +1,4 @@ -import { render, screen } from 'custom-testing-library' - +import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' import TimescaleDisabled from './TimescaleDisabled' diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.test.tsx similarity index 92% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.test.tsx index 66631933cb..395d902763 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/ComponentsTable.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -148,29 +148,28 @@ describe('ComponentsTable', () => { noReportsUploaded?: boolean }) { const user = userEvent.setup() - const fetchNextPage = jest.fn() + const fetchNextPage = vi.fn() server.use( - graphql.query('ComponentMeasurements', (req, res, ctx) => { + graphql.query('ComponentMeasurements', (info) => { if (noData) { - return res(ctx.status(200), ctx.data(mockEmptyComponentMeasurements)) + return HttpResponse.json({ data: mockEmptyComponentMeasurements }) } if (noReportsUploaded) { - return res( - ctx.status(200), - ctx.data(mockNoReportsUploadedMeasurements) - ) + return HttpResponse.json({ + data: mockNoReportsUploadedMeasurements, + }) } - return res(ctx.status(200), ctx.data(mockedComponentMeasurements)) + return HttpResponse.json({ data: mockedComponentMeasurements }) }), - graphql.query('GetRepo', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetRepo)) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) }), - graphql.query('RepoConfig', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockRepoConfig)) - ) + graphql.query('RepoConfig', (info) => { + return HttpResponse.json({ data: mockRepoConfig }) + }) ) return { fetchNextPage, user } @@ -179,11 +178,11 @@ describe('ComponentsTable', () => { describe('when rendered', () => { beforeEach(() => { setup({}) - jest.useFakeTimers().setSystemTime(new Date('2024-02-02')) + vi.useFakeTimers().setSystemTime(new Date('2024-02-02')) }) afterAll(() => { - jest.useRealTimers() + vi.useRealTimers() }) it('renders table headers', async () => { diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.test.tsx similarity index 92% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.test.tsx index c376d51270..ed2135cfca 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/DeleteComponentModal/DeleteComponentModal.test.tsx @@ -2,13 +2,13 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 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 { MemoryRouter, Route } from 'react-router-dom' import DeleteComponentModal from './DeleteComponentModal' -jest.mock('ui/Avatar', () => () => 'Avatar') +vi.mock('ui/Avatar', () => ({ default: () => 'Avatar' })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -43,9 +43,11 @@ afterAll(() => { describe('DeleteComponentModal', () => { function setup() { server.use( - graphql.mutation('deleteComponentMeasurements', (req, res, ctx) => - res(ctx.status(200), ctx.data({})) - ) + graphql.mutation('deleteComponentMeasurements', (info) => { + return HttpResponse.json({ + data: { deleteComponentMeasurements: null }, + }) + }) ) return { user: userEvent.setup() } diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/TableEntries/TableSparkline.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/TableEntries/TableSparkline.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/TableEntries/TableSparkline.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/TableEntries/TableSparkline.test.tsx diff --git a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.spec.tsx b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.test.tsx similarity index 93% rename from src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.test.tsx index c129205bb4..9b1db75d4c 100644 --- a/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/ComponentsTab/subroute/ComponentsTable/hooks/useRepoComponentsTable.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' import { format, sub, subDays, subMonths } from 'date-fns' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import React, { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -42,10 +42,13 @@ afterAll(() => { server.close() }) -jest.mock('services/navigation', () => ({ - ...jest.requireActual('services/navigation'), - useLocationParams: jest.fn(), -})) +vi.mock('services/navigation', async () => { + const actual = await vi.importActual('services/navigation') + return { + ...actual, + useLocationParams: vi.fn(), + } +}) const mockGetRepo = ({ noUploadToken = false, @@ -157,16 +160,16 @@ describe('useRepoComponentsTable', () => { const requestFilters = jest.fn() server.use( - graphql.query('ComponentMeasurements', (req, res, ctx) => { - requestFilters(req.variables) + graphql.query('ComponentMeasurements', (info) => { + requestFilters(info.variables) if (noData) { - return res(ctx.status(200), ctx.data(mockEmptyComponentMeasurements)) + return HttpResponse.json({ data: mockEmptyComponentMeasurements }) } - return res(ctx.status(200), ctx.data(mockedComponentMeasurements)) + return HttpResponse.json({ data: mockedComponentMeasurements }) }), - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(repoData({}))) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: repoData({}) }) + }) ) return { requestFilters } diff --git a/src/pages/RepoPage/CoverageTab/CoverageTab.spec.tsx b/src/pages/RepoPage/CoverageTab/CoverageTab.test.tsx similarity index 93% rename from src/pages/RepoPage/CoverageTab/CoverageTab.spec.tsx rename to src/pages/RepoPage/CoverageTab/CoverageTab.test.tsx index 68228d31fc..0d30176267 100644 --- a/src/pages/RepoPage/CoverageTab/CoverageTab.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/CoverageTab.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -28,10 +28,16 @@ const mockRepoSettingsTeam = { }, } -jest.mock('./OverviewTab', () => () => 'OverviewTab') -jest.mock('./FlagsTab', () => () => 'FlagsTab') -jest.mock('./ComponentsTab', () => () => 'ComponentsTab') -jest.mock('ui/LoadingLogo', () => () => 'Loader') +vi.mock('./OverviewTab', () => ({ + default: () => 'OverviewTab', +})) +vi.mock('./FlagsTab', () => ({ + default: () => 'FlagsTab', +})) +vi.mock('./ComponentsTab', () => ({ + default: () => 'ComponentsTab', +})) +vi.mock('ui/LoadingLogo', () => ({ default: () => 'Loader' })) let testLocation: ReturnType @@ -88,11 +94,11 @@ interface SetupArgs { describe('CoverageTab', () => { function setup({ tierName = TierNames.PRO }: SetupArgs) { server.use( - graphql.query('OwnerTier', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: { plan: { tierName } } })) + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ data: { owner: { plan: { tierName } } } }) }), - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoSettingsTeam)) + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ data: mockRepoSettingsTeam }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.jsx b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.jsx index 0ff59031b4..dd30c0bd24 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.jsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.jsx @@ -1,6 +1,6 @@ -import { useRepoBackfillingStatus } from './hooks' import SyncingBanner from './SyncingBanner' import TriggerSyncBanner from './TriggerSyncBanner' +import { useRepoBackfillingStatus } from './useRepoBackfillingStatus' function BackfillBanners() { const { flagsMeasurementsActive, isRepoBackfilling } = diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.spec.jsx b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.test.jsx similarity index 58% rename from src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.spec.jsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.test.jsx index 11778fa114..62f3bcb2f2 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/BackfillBanners.test.jsx @@ -1,16 +1,25 @@ -import { render, screen } from 'custom-testing-library' +import { render, screen } from '@testing-library/react' import BackfillBanners from './BackfillBanners' -import { useRepoBackfillingStatus } from './hooks' -jest.mock('./TriggerSyncBanner', () => () => 'TriggerSyncBanner') -jest.mock('./SyncingBanner', () => () => 'SyncingBanner') +const mocks = vi.hoisted(() => ({ + useRepoBackfillingStatus: vi.fn(), +})) -jest.mock('./hooks') +vi.mock('./useRepoBackfillingStatus', async () => { + const actual = await vi.importActual('./useRepoBackfillingStatus') + return { + ...actual, + useRepoBackfillingStatus: mocks.useRepoBackfillingStatus, + } +}) + +vi.mock('./TriggerSyncBanner', () => ({ default: () => 'TriggerSyncBanner' })) +vi.mock('./SyncingBanner', () => ({ default: () => 'SyncingBanner' })) describe('BackfillBanner', () => { function setup(data) { - useRepoBackfillingStatus.mockReturnValue(data) + mocks.useRepoBackfillingStatus.mockReturnValue(data) render() } diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx similarity index 95% rename from src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx index 37ce84f4f6..905376caa9 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/SyncingBanner/SyncingBanner.test.tsx @@ -1,6 +1,5 @@ -import { render, screen } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' import SyncingBanner from './SyncingBanner' diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx similarity index 69% rename from src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx index 07d4f67fc9..c36fa3fd80 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.test.tsx @@ -1,21 +1,32 @@ -import { render, screen } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { MemoryRouter, Route, useParams } from 'react-router-dom' - -import { useActivateMeasurements } from 'services/repo' +import { MemoryRouter, Route } from 'react-router-dom' import TriggerSyncBanner from './TriggerSyncBanner' -jest.mock('services/user') - -jest.mock('services/repo/useActivateMeasurements') -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), // import and retain the original functionalities - useParams: jest.fn(() => {}), +const mocks = vi.hoisted(() => ({ + useActivateMeasurements: vi.fn(), + useParams: vi.fn(), })) +vi.mock('services/user') + +vi.mock('services/repo', async () => { + const actual = await vi.importActual('services/repo') + return { + ...actual, + useActivateMeasurements: mocks.useActivateMeasurements, + } +}) +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') // import and retain the original functionalities + return { + ...actual, + useParams: mocks.useParams, + } +}) + const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -33,22 +44,20 @@ const wrapper: React.FC = ({ children }) => ( ) describe('TriggerSyncBanner', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => { + vi.resetAllMocks() + }) function setup() { const user = userEvent.setup() - const mutate = jest.fn() - - const mockedUseParams = useParams as jest.Mock - const mockedUseActivateFlagMeasurements = - useActivateMeasurements as jest.Mock + const mutate = vi.fn() - mockedUseParams.mockReturnValue({ + mocks.useParams.mockReturnValue({ owner: 'codecov', provider: 'gh', repo: 'gazebo', }) - mockedUseActivateFlagMeasurements.mockReturnValue({ mutate }) + mocks.useActivateMeasurements.mockReturnValue({ mutate }) return { mutate, user } } diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/hooks.spec.ts b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/useRepoBackfillingStatus.test.ts similarity index 81% rename from src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/hooks.spec.ts rename to src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/useRepoBackfillingStatus.test.ts index 16ceaeace9..a3b9e1795c 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/hooks.spec.ts +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/useRepoBackfillingStatus.test.ts @@ -1,10 +1,18 @@ import { renderHook } from '@testing-library/react' -import { useRepoBackfilled } from 'services/repo' +import { useRepoBackfillingStatus } from './useRepoBackfillingStatus' -import { useRepoBackfillingStatus } from './hooks' +const mocks = vi.hoisted(() => ({ + useRepoBackfilled: vi.fn(), +})) -jest.mock('services/repo') +vi.mock('services/repo', async () => { + const actual = await vi.importActual('services/repo') + return { + ...actual, + useRepoBackfilled: mocks.useRepoBackfilled, + } +}) type MockType = { flagsMeasurementsActive?: boolean @@ -19,8 +27,7 @@ const repoBackfillData: MockType = { describe('useRepoBackfillingStatus', () => { function setup(data = repoBackfillData) { - const mockedUseRepoBackfilled = useRepoBackfilled as jest.Mock - mockedUseRepoBackfilled.mockReturnValue({ data }) + mocks.useRepoBackfilled.mockReturnValue({ data }) return renderHook(() => useRepoBackfillingStatus()) } diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/hooks.ts b/src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/useRepoBackfillingStatus.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/hooks.ts rename to src/pages/RepoPage/CoverageTab/FlagsTab/BackfillBanners/useRepoBackfillingStatus.ts diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.jsx b/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.jsx index d5b2aa4364..6126513e53 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.jsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.jsx @@ -2,14 +2,13 @@ import { Redirect, useParams } from 'react-router-dom' import { SentryRoute } from 'sentry' -import { useRepoSettingsTeam } from 'services/repo' -import { useRepoFlagsSelect } from 'services/repo/useRepoFlagsSelect' +import { useRepoFlagsSelect, useRepoSettingsTeam } from 'services/repo' import { TierNames, useTier } from 'services/tier' import FlagsNotConfigured from 'shared/FlagsNotConfigured' import blurredTable from './assets/blurredTable.png' import BackfillBanners from './BackfillBanners/BackfillBanners' -import { useRepoBackfillingStatus } from './BackfillBanners/hooks' +import { useRepoBackfillingStatus } from './BackfillBanners/useRepoBackfillingStatus' import Header from './Header' import FlagsTable from './subroute/FlagsTable/FlagsTable' import TimescaleDisabled from './TimescaleDisabled' diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.spec.jsx b/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.test.jsx similarity index 85% rename from src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.spec.jsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.test.jsx index 672941a20d..c8484d03d6 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/FlagsTab.test.jsx @@ -1,31 +1,40 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -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 { useRepoBackfilled, useRepoFlagsSelect } from 'services/repo' import { TierNames } from 'services/tier' import FlagsTab from './FlagsTab' -jest.mock('services/repo/useRepoBackfilled') -jest.mock('services/repo/useRepoFlagsSelect') -jest.mock('shared/featureFlags') +const mocks = vi.hoisted(() => ({ + useRepoFlagsSelect: vi.fn(), + useRepoBackfilled: vi.fn(), +})) + +vi.mock('services/repo', async () => { + const actual = await vi.importActual('services/repo') + return { + ...actual, + useRepoFlagsSelect: mocks.useRepoFlagsSelect, + useRepoBackfilled: mocks.useRepoBackfilled, + } +}) -jest.mock( - './BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.tsx', - () => () => 'Trigger Sync Banner' -) -jest.mock( - './BackfillBanners/SyncingBanner/SyncingBanner.tsx', - () => () => 'Syncing Banner' -) -jest.mock('./subroute/FlagsTable/FlagsTable', () => () => 'Flags table') -jest.mock('./Header', () => ({ children }) => ( -

    Flags Header Component {children}

    -)) +vi.mock('./BackfillBanners/TriggerSyncBanner/TriggerSyncBanner.tsx', () => ({ + default: () => 'Trigger Sync Banner', +})) +vi.mock('./BackfillBanners/SyncingBanner/SyncingBanner.tsx', () => ({ + default: () => 'Syncing Banner', +})) +vi.mock('./subroute/FlagsTable/FlagsTable', () => ({ + default: () => 'Flags table', +})) +vi.mock('./Header', () => ({ + default: ({ children }) =>

    Flags Header Component {children}

    , +})) const flagsData = [ { @@ -100,27 +109,24 @@ describe('Flags Tab', () => { isPrivate = false, isCurrentUserPartOfOrg = true, }) { - useRepoFlagsSelect.mockReturnValue({ data: flags }) - useRepoBackfilled.mockReturnValue(data) + mocks.useRepoFlagsSelect.mockReturnValue({ data: flags }) + mocks.useRepoBackfilled.mockReturnValue(data) server.use( - graphql.query('OwnerTier', (req, res, ctx) => { + graphql.query('OwnerTier', (info) => { if (tierValue === TierNames.TEAM) { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.TEAM } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.TEAM } } }, + }) } - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.PRO } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.PRO } } }, + }) }), - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepoSettings(isPrivate, isCurrentUserPartOfOrg)) - ) + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ + data: mockRepoSettings(isPrivate, isCurrentUserPartOfOrg), + }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.spec.jsx b/src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.test.jsx similarity index 82% rename from src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.spec.jsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.test.jsx index 4c81c3004a..5e4124c545 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/Header/Header.test.jsx @@ -2,17 +2,42 @@ import { render, screen, waitFor } from 'custom-testing-library' import userEvent from '@testing-library/user-event' import { MemoryRouter, Route } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' -import { useLocationParams } from 'services/navigation' -import { useRepoBackfilled, useRepoFlagsSelect } from 'services/repo' +import {} from 'services/repo' import Header from './Header' -jest.mock('react-use/lib/useIntersection') -jest.mock('services/navigation/useLocationParams') -jest.mock('services/repo/useRepoBackfilled') -jest.mock('services/repo/useRepoFlagsSelect') +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), + useLocationParams: vi.fn(), + useRepoBackfilled: vi.fn(), + useRepoFlagsSelect: vi.fn(), +})) + +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) + +vi.mock('services/navigation', async () => { + const actual = await vi.importActual('services/navigation') + return { + ...actual, + useLocationParams: mocks.useLocationParams, + } +}) + +vi.mock('services/repo', async () => { + const actual = await vi.importActual('services/repo') + return { + ...actual, + useRepoBackfilled: mocks.useRepoBackfilled, + useRepoFlagsSelect: mocks.useRepoFlagsSelect, + } +}) const wrapper = ({ children }) => ( @@ -23,21 +48,23 @@ const wrapper = ({ children }) => ( ) describe('Header', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => { + vi.clearAllMocks() + }) function setup(setRepoFlags = true) { const user = userEvent.setup() - const updateLocationMock = jest.fn() + const updateLocationMock = vi.fn() - useLocationParams.mockReturnValue({ + mocks.useLocationParams.mockReturnValue({ params: { search: '', historicalTrend: '', flags: [] }, updateParams: updateLocationMock, }) - useRepoBackfilled.mockReturnValue({ + mocks.useRepoBackfilled.mockReturnValue({ data: { flagsCount: 99 }, }) if (setRepoFlags) { - useRepoFlagsSelect.mockReturnValue({ + mocks.useRepoFlagsSelect.mockReturnValue({ data: [{ name: 'flag1' }], }) } @@ -172,13 +199,13 @@ describe('Header', () => { describe('when there is a next page', () => { it('calls fetchNextPage', async () => { const { user } = setup(false) - const fetchNextPage = jest.fn() - useRepoFlagsSelect.mockReturnValue({ + const fetchNextPage = vi.fn() + mocks.useRepoFlagsSelect.mockReturnValue({ data: [{ name: 'flag1' }], fetchNextPage, hasNextPage: true, }) - useIntersection.mockReturnValue({ isIntersecting: true }) + mocks.useIntersection.mockReturnValue({ isIntersecting: true }) render(
    , { wrapper }) @@ -192,13 +219,13 @@ describe('Header', () => { describe('when there is no next page', () => { it('does not calls fetchNextPage', async () => { const { user } = setup(false) - const fetchNextPage = jest.fn() - useRepoFlagsSelect.mockReturnValue({ + const fetchNextPage = vi.fn() + mocks.useRepoFlagsSelect.mockReturnValue({ data: [{ name: 'flag1' }], fetchNextPage, hasNextPage: false, }) - useIntersection.mockReturnValue({ isIntersecting: true }) + mocks.useIntersection.mockReturnValue({ isIntersecting: true }) render(
    , { wrapper }) @@ -249,7 +276,7 @@ describe('Header', () => { await waitFor( () => - expect(useRepoFlagsSelect).toHaveBeenCalledWith({ + expect(mocks.useRepoFlagsSelect).toHaveBeenCalledWith({ filters: { term: 'flag2' }, options: { suspense: false }, }), diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.test.tsx similarity index 95% rename from src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.test.tsx index e8e94177d4..338d57f391 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/TimescaleDisabled/TimescaleDisabled.test.tsx @@ -1,5 +1,4 @@ -import { render, screen } from 'custom-testing-library' - +import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' import TimescaleDisabled from './TimescaleDisabled' diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.test.tsx similarity index 85% rename from src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.test.tsx index d5902a324c..1767a7abbc 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/DeleteFlagModal/DeleteFlagModal.test.tsx @@ -2,13 +2,13 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 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 { MemoryRouter, Route } from 'react-router-dom' import DeleteFlagModal from './DeleteFlagModal' -jest.mock('ui/Avatar', () => () => 'Avatar') +vi.mock('ui/Avatar', () => ({ default: () => 'Avatar' })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -41,9 +41,9 @@ afterAll(() => { describe('DeleteFlagModal', () => { function setup() { server.use( - graphql.mutation('deleteFlag', (req, res, ctx) => - res(ctx.status(200), ctx.data({})) - ) + graphql.mutation('deleteFlag', (info) => { + return HttpResponse.json({ data: { deleteFlag: null } }) + }) ) return { user: userEvent.setup() } @@ -56,7 +56,7 @@ describe('DeleteFlagModal', () => { it('renders the modal message', async () => { render( - , + , { wrapper, } @@ -74,7 +74,7 @@ describe('DeleteFlagModal', () => { it('renders delete and cancel buttons', async () => { render( - , + , { wrapper, } @@ -89,7 +89,7 @@ describe('DeleteFlagModal', () => { it('renders appropriate title', async () => { render( - , + , { wrapper, } @@ -102,7 +102,7 @@ describe('DeleteFlagModal', () => { describe('when clicking delete button', () => { it('selects a default organization', async () => { const { user } = setup() - const closeModal = jest.fn() + const closeModal = vi.fn() render( , { @@ -121,7 +121,7 @@ describe('DeleteFlagModal', () => { describe('when clicking cancel button', () => { it('closes the modal', async () => { const { user } = setup() - const closeModal = jest.fn() + const closeModal = vi.fn() render( , { diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.test.tsx similarity index 91% rename from src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.test.tsx index d414b03c72..57aae4e453 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.test.tsx @@ -7,8 +7,8 @@ import { waitForElementToBeRemoved, } 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 { mockIsIntersecting } from 'react-intersection-observer/test-utils' import { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -198,42 +198,37 @@ describe('FlagsTable', () => { isAdmin = true, }: SetupArgs) { const user = userEvent.setup() - const fetchNextPage = jest.fn() + const fetchNextPage = vi.fn() server.use( - graphql.query('FlagMeasurements', (req, res, ctx) => { - if (req?.variables?.after) { - return res( - ctx.status(200), - ctx.data(mockFlagMeasurements({ after: true })) - ) + graphql.query('FlagMeasurements', (info) => { + if (info?.variables?.after) { + return HttpResponse.json({ + data: mockFlagMeasurements({ after: true }), + }) } if (noData) { - return res(ctx.status(200), ctx.data(mockEmptyFlagMeasurements)) + return HttpResponse.json({ data: mockEmptyFlagMeasurements }) } if (includeNullFlag) { - return res( - ctx.status(200), - ctx.data(mockFlagMeasurements({ nullFlag: true })) - ) + return HttpResponse.json({ + data: mockFlagMeasurements({ nullFlag: true }), + }) } if (noReportsUploaded) { - return res( - ctx.status(200), - ctx.data(mockNoReportsUploadedMeasurements) - ) + return HttpResponse.json({ data: mockNoReportsUploadedMeasurements }) } - return res(ctx.status(200), ctx.data(mockFlagMeasurements({}))) + return HttpResponse.json({ data: mockFlagMeasurements({}) }) }), - graphql.query('GetRepo', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetRepo({ isAdmin }))) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo({ isAdmin }) }) }), - graphql.query('RepoConfig', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockRepoConfig)) + graphql.query('RepoConfig', (info) => + HttpResponse.json({ data: mockRepoConfig }) ) ) @@ -355,9 +350,7 @@ describe('FlagsTable', () => { const { user } = setup({}) render(, { wrapper: wrapper() }) - const trashIconButtons = await screen.findAllByRole('button', { - name: /trash/, - }) + const trashIconButtons = await screen.findAllByTestId(/trash/) expect(trashIconButtons).toHaveLength(3) const [firstIcon] = trashIconButtons diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.tsx index 0ade86c61a..6374666d4e 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/FlagsTable.tsx @@ -113,7 +113,7 @@ function createTableData({ } className="text-ds-gray-tertiary hover:text-ds-gray-senary" > - +
    ) : null, diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/TableEntries/TableSparkline.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/TableEntries/TableSparkline.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/TableEntries/TableSparkline.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/TableEntries/TableSparkline.test.tsx diff --git a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.spec.tsx b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.test.tsx similarity index 81% rename from src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.test.tsx index 5861914731..d083d5e15c 100644 --- a/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/FlagsTab/subroute/FlagsTable/hooks/useRepoFlagsTable.test.tsx @@ -1,30 +1,48 @@ import { renderHook, waitFor } from '@testing-library/react' import { format, sub, subDays, subMonths } from 'date-fns' -import { useParams } from 'react-router-dom' import { TIME_OPTION_VALUES } from 'pages/RepoPage/shared/constants' -import { useLocationParams } from 'services/navigation' -import { useRepo } from 'services/repo' -import { useRepoFlags } from 'services/repo/useRepoFlags' import useRepoFlagsTable from './useRepoFlagsTable' -jest.mock('services/repo/useRepoFlags') -jest.mock('services/repo') - -jest.mock('services/navigation', () => ({ - ...jest.requireActual('services/navigation'), - useLocationParams: jest.fn(), -})) -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: jest.fn(), +const mocks = vi.hoisted(() => ({ + useParams: vi.fn(), + useLocationParams: vi.fn(), + useRepo: vi.fn(), + useRepoFlags: vi.fn(), })) -const mockedUseParams = useParams as jest.Mock -const mockedUseRepo = useRepo as jest.Mock -const mockedUseRepoFlags = useRepoFlags as jest.Mock -const mockedUseLocationParams = useLocationParams as jest.Mock +vi.mock('services/repo', async () => { + const actual = await vi.importActual('services/repo') + return { + ...actual, + useRepo: mocks.useRepo, + } +}) + +vi.mock('services/repo/useRepoFlags', async () => { + const actual = await vi.importActual('services/repo/useRepoFlags') + return { + ...actual, + useRepoFlags: mocks.useRepoFlags, + } +}) + +vi.mock('services/navigation', async () => { + const actual = await vi.importActual('services/navigation') + return { + ...actual, + useLocationParams: mocks.useLocationParams, + } +}) + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') + return { + ...actual, + useParams: mocks.useParams, + } +}) const flagsData = [ { @@ -43,7 +61,7 @@ const flagsData = [ }, ] -const fetchNextPage = jest.fn() +const fetchNextPage = vi.fn() const repoFlagsMock = { data: flagsData, @@ -79,23 +97,23 @@ describe('useRepoFlagsTable', () => { noOldestCommit = false, useParamsValue = {}, }: SetupArgs) { - mockedUseParams.mockReturnValue({ + mocks.useParams.mockReturnValue({ provider: 'gh', owner: 'codecov', repo: 'gazebo', }) - mockedUseLocationParams.mockReturnValue({ + mocks.useLocationParams.mockReturnValue({ params: { ...defaultParams, ...useParamsValue }, }) if (noOldestCommit) { - mockedUseRepo.mockReturnValue({ + mocks.useRepo.mockReturnValue({ data: { repository: { oldestCommitAt: null }, }, }) } else { - mockedUseRepo.mockReturnValue({ + mocks.useRepo.mockReturnValue({ data: { repository: { oldestCommitAt: '2020-06-11T18:28:52' }, }, @@ -103,9 +121,9 @@ describe('useRepoFlagsTable', () => { } if (isEmptyRepoFlags) { - mockedUseRepoFlags.mockReturnValue(emptyRepoFlagsMock) + mocks.useRepoFlags.mockReturnValue(emptyRepoFlagsMock) } else { - mockedUseRepoFlags.mockReturnValue(repoFlagsMock) + mocks.useRepoFlags.mockReturnValue(repoFlagsMock) } } @@ -139,7 +157,7 @@ describe('useRepoFlagsTable', () => { renderHook(() => useRepoFlagsTable(true)) await waitFor(() => - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 3 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -154,7 +172,7 @@ describe('useRepoFlagsTable', () => { renderHook(() => useRepoFlagsTable(false)) await waitFor(() => - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 3 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -173,7 +191,7 @@ describe('useRepoFlagsTable', () => { const { result } = renderHook(() => useRepoFlagsTable(false)) expect(result.current.isSearching).toEqual(true) - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 3 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: 'flag1', flagsNames: [] }, @@ -197,7 +215,7 @@ describe('useRepoFlagsTable', () => { it('calls useRepoFlagsTable with correct query params', () => { renderHook(() => useRepoFlagsTable(false)) - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 3 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -216,7 +234,7 @@ describe('useRepoFlagsTable', () => { it('calls useRepoFlagsTable with correct query params', () => { renderHook(() => useRepoFlagsTable(false)) - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: '2020-06-11', beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -238,7 +256,7 @@ describe('useRepoFlagsTable', () => { it('calls useRepoFlagsTable with correct query params', () => { renderHook(() => useRepoFlagsTable(false)) - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 6 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -260,7 +278,7 @@ describe('useRepoFlagsTable', () => { renderHook(() => useRepoFlagsTable(false)) const afterDate = format(subMonths(new Date(), 6), 'yyyy-MM-dd') - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate, beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -282,7 +300,7 @@ describe('useRepoFlagsTable', () => { renderHook(() => useRepoFlagsTable(false)) const afterDate = format(subDays(new Date(), 7), 'yyyy-MM-dd') - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate, beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: [] }, @@ -302,7 +320,7 @@ describe('useRepoFlagsTable', () => { renderHook(() => useRepoFlagsTable(false)) - expect(useRepoFlags).toHaveBeenCalledWith({ + expect(mocks.useRepoFlags).toHaveBeenCalledWith({ afterDate: format(sub(new Date(), { months: 3 }), 'yyyy-MM-dd'), beforeDate: format(new Date(), 'yyyy-MM-dd'), filters: { term: '', flagsNames: ['flag1'] }, diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/FirstPullRequestBanner/FirstPullRequestBanner.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/FirstPullRequestBanner/FirstPullRequestBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/FirstPullRequestBanner/FirstPullRequestBanner.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/FirstPullRequestBanner/FirstPullRequestBanner.test.tsx diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.test.tsx similarity index 78% rename from src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.test.tsx index 9de66c62f7..9baa83957e 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/OverviewTab.test.tsx @@ -1,17 +1,17 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' -import { graphql, rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import { TierNames, TTierNames } from 'services/tier' import CoverageOverviewTab from './OverviewTab' -jest.mock('./Summary', () => () => 'Summary') -jest.mock('./SummaryTeamPlan', () => () => 'SummaryTeamPlan') -jest.mock('./subroute/Sunburst', () => () => 'Sunburst') -jest.mock('./subroute/Fileviewer', () => () => 'FileViewer') +vi.mock('./Summary', () => ({ default: () => 'Summary' })) +vi.mock('./SummaryTeamPlan', () => ({ default: () => 'SummaryTeamPlan' })) +vi.mock('./subroute/Sunburst', () => ({ default: () => 'Sunburst' })) +vi.mock('./subroute/Fileviewer', () => ({ default: () => 'FileViewer' })) const mockRepoSettings = (isPrivate = false) => ({ owner: { @@ -349,76 +349,70 @@ describe('Coverage overview tab', () => { fileCount = 10, }: SetupArgs) { server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockRepo(isPrivate, isFirstPullRequest))) - ), - graphql.query('GetBranches', (req, res, ctx) => - res(ctx.status(200), ctx.data(branchesMock)) - ), - graphql.query('GetBranch', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ + data: mockRepo(isPrivate, isFirstPullRequest), + }) + }), + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ data: branchesMock }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { ...branchMock } }, - }) - ) - ), - graphql.query('BranchContents', (req, res, ctx) => - res(ctx.status(200), ctx.data(branchesContentsMock)) - ), - graphql.query('RepoConfig', (req, res, ctx) => - res(ctx.status(200), ctx.data(repoConfigMock)) - ), - graphql.query('GetRepoOverview', (req, res, ctx) => - res(ctx.status(200), ctx.data(overviewMock)) - ), - graphql.query('GetRepoCoverage', (req, res, ctx) => - res(ctx.status(200), ctx.data({ owner: null })) - ), - graphql.query('GetBranchCoverageMeasurements', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockBranchMeasurements)) - ), - graphql.query('BackfillFlagMemberships', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockBackfillFlag)) - ), - graphql.query('OwnerTier', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: tierValue } } }) - ) + }, + }) + }), + graphql.query('BranchContents', (info) => { + return HttpResponse.json({ data: branchesContentsMock }) + }), + graphql.query('RepoConfig', (info) => { + return HttpResponse.json({ data: repoConfigMock }) + }), + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: overviewMock }) }), - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoSettings(isPrivate))) + graphql.query('GetRepoCoverage', (info) => { + return HttpResponse.json({ data: { owner: null } }) }), - graphql.query('CoverageTabData', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockCoverageTabData(fileCount))) + graphql.query('GetBranchCoverageMeasurements', (info) => { + return HttpResponse.json({ data: mockBranchMeasurements }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockOverview)) + graphql.query('BackfillFlagMemberships', (info) => { + return HttpResponse.json({ data: mockBackfillFlag }) }), - graphql.query('GetBranchComponents', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBranchComponents)) + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ + data: { owner: { plan: { tierName: tierValue } } }, + }) }), - graphql.query('FlagsSelect', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockFlagSelect)) + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ data: mockRepoSettings(isPrivate) }) }), - rest.get( - '/internal/:provider/:owner/:repo/coverage/tree', - (req, res, ctx) => { - return res(ctx.status(200), ctx.json(treeMock)) - } - ), - rest.post( - '/internal/charts/:provider/:owner/coverage/:repo', - (req, res, ctx) => { - return res(ctx.status(200), ctx.json({ data: {} })) - } - ) + graphql.query('CoverageTabData', (info) => { + return HttpResponse.json({ data: mockCoverageTabData(fileCount) }) + }), + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockOverview }) + }), + graphql.query('GetBranchComponents', (info) => { + return HttpResponse.json({ data: mockBranchComponents }) + }), + graphql.query('FlagsSelect', (info) => { + return HttpResponse.json({ data: mockFlagSelect }) + }), + http.get('/internal/:provider/:owner/:repo/coverage/tree', (info) => { + return HttpResponse.json({ data: treeMock }) + }), + http.post('/internal/charts/:provider/:owner/coverage/:repo', (info) => { + return HttpResponse.json({ data: {} }) + }) ) } afterEach(() => { - jest.resetAllMocks() + vi.resetAllMocks() }) it('renders default summary', async () => { diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.test.jsx similarity index 71% rename from src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.test.jsx index de4c49ea1d..8834720c93 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/CoverageTrend/CoverageTrend.test.jsx @@ -2,15 +2,31 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' -import { useBranches } from 'services/branches' - import CoverageTrend from './CoverageTrend' -import { useBranchSelector, useRepoCoverageTimeseries } from '../../hooks' +const mocks = vi.hoisted(() => ({ + useBranches: vi.fn(), + useBranchSelector: vi.fn(), + useRepoCoverageTimeseries: vi.fn(), +})) + +vi.mock('services/branches', async () => { + const actual = await vi.importActual('services/branches') + return { + ...actual, + useBranches: mocks.useBranches, + } +}) +vi.mock('../../hooks', async () => { + const actual = await vi.importActual('../../hooks') + return { + ...actual, + useRepoCoverageTimeseries: mocks.useRepoCoverageTimeseries, + useBranchSelector: mocks.useBranchSelector, + } +}) -jest.mock('services/branches') -jest.mock('../../hooks') -jest.mock('../TrendDropdown', () => () => 'TrendDropdown') +vi.mock('../TrendDropdown', () => ({ default: () => 'TrendDropdown' })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -26,11 +42,11 @@ const wrapper = ({ children }) => ( const renderCoverageTab = () => render(, { wrapper }) describe('CoverageTrend', () => { function setup({ coverageData }) { - useRepoCoverageTimeseries.mockReturnValue(coverageData) - useBranches.mockReturnValue({ + mocks.useRepoCoverageTimeseries.mockReturnValue(coverageData) + mocks.useBranches.mockReturnValue({ data: { branches: [{ name: 'bells-hells', head: { commitid: '1' } }] }, }) - useBranchSelector.mockReturnValue({ + mocks.useBranchSelector.mockReturnValue({ selection: { name: 'bells-hells' }, }) } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.test.jsx similarity index 80% rename from src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.test.jsx index 6432387c78..8dc5033bda 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/Summary.test.jsx @@ -1,19 +1,35 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import Summary from './Summary' -import { useCoverageRedirect } from '../summaryHooks' +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), + useCoverageRedirect: vi.fn(), +})) -jest.mock('../summaryHooks/useCoverageRedirect') -jest.mock('./CoverageTrend', () => () => 'CoverageTrend') -jest.mock('react-use/lib/useIntersection') +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) + +vi.mock('../summaryHooks/useCoverageRedirect', async () => { + const actual = await vi.importActual('../summaryHooks/useCoverageRedirect') + return { + ...actual, + useCoverageRedirect: mocks.useCoverageRedirect, + } +}) + +vi.mock('./CoverageTrend', () => ({ default: () => 'CoverageTrend' })) const mockRepoOverview = { __typename: 'Repository', @@ -152,7 +168,7 @@ describe('Summary', () => { isRedirectionEnabled: false, newPath: undefined, }, - setNewPath: jest.fn(), + setNewPath: vi.fn(), }, } = { hasNextPage: false, @@ -161,65 +177,60 @@ describe('Summary', () => { isRedirectionEnabled: false, newPath: undefined, }, - setNewPath: jest.fn(), + setNewPath: vi.fn(), }, } ) { const user = userEvent.setup() - const fetchNextPage = jest.fn() - const mockSearching = jest.fn() + const fetchNextPage = vi.fn() + const mockSearching = vi.fn() - useCoverageRedirect.mockReturnValue(coverageRedirectData) + mocks.useCoverageRedirect.mockReturnValue(coverageRedirectData) server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch } }, - }) - ) - ), - 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 === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches(hasNextPage) } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) } }, + }) }), - graphql.query('GetRepoCoverage', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ owner: { repository: mockRepoCoverage } }) - ) - ), - graphql.query('RepoConfig', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockRepoConfig)) - ) + graphql.query('GetRepoCoverage', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockRepoCoverage } }, + }) + }), + graphql.query('RepoConfig', (info) => { + return HttpResponse.json({ data: mockRepoConfig }) + }) ) return { fetchNextPage, mockSearching, user } @@ -295,7 +306,7 @@ describe('Summary', () => { describe('uses a conditional Redirect', () => { it('updates the location', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const coverageRedirectData = { redirectState: { newPath: '/some/new/location', @@ -321,7 +332,7 @@ describe('Summary', () => { describe('fires the setNewPath on branch selection', () => { it('updates the location', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const coverageRedirectData = { redirectState: { newPath: '/some/new/location', @@ -349,7 +360,7 @@ describe('Summary', () => { describe('when onLoadMore is triggered', () => { describe('there is a next page', () => { it('calls fetchNextPage', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const { fetchNextPage, user } = setup({ hasNextPage: true, coverageRedirectData: { @@ -360,7 +371,7 @@ describe('Summary', () => { setNewPath: mockSetNewPath, }, }) - useIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) render(, { wrapper: wrapper() }) @@ -379,9 +390,9 @@ describe('Summary', () => { actually calling it but because of scoping it was always falsy */ - const fetchNextPage = jest.fn() + const fetchNextPage = vi.fn() it('does not call fetchNextPage', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const { user } = setup({ hasNextPage: false, @@ -394,7 +405,7 @@ describe('Summary', () => { }, }) - useIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/TrendDropdown/TrendDropdown.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/Summary/TrendDropdown/TrendDropdown.test.jsx similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/Summary/TrendDropdown/TrendDropdown.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/Summary/TrendDropdown/TrendDropdown.test.jsx diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.test.tsx similarity index 80% rename from src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.test.tsx index ac734aeb12..e28880724e 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.test.tsx @@ -1,18 +1,34 @@ 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 } 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' -import useIntersection from 'react-use/lib/useIntersection' +import { type Mock } from 'vitest' import SummaryTeamPlan from './SummaryTeamPlan' -import { useCoverageRedirect } from '../summaryHooks' +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn(), + useCoverageRedirect: vi.fn(), +})) -jest.mock('../summaryHooks/useCoverageRedirect') -jest.mock('react-use/lib/useIntersection') +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) + +vi.mock('../summaryHooks/useCoverageRedirect', async () => { + const actual = await vi.importActual('../summaryHooks/useCoverageRedirect') + return { + ...actual, + useCoverageRedirect: mocks.useCoverageRedirect, + } +}) const mockRepoOverview = { __typename: 'Repository', @@ -143,7 +159,7 @@ describe('Summary', () => { isRedirectionEnabled: false, newPath: undefined, }, - setNewPath: jest.fn(), + setNewPath: vi.fn(), }, }: { isIntersecting?: boolean @@ -153,7 +169,7 @@ describe('Summary', () => { isRedirectionEnabled: boolean newPath?: string } - setNewPath: jest.Mock + setNewPath: Mock } } = { hasNextPage: false, @@ -162,69 +178,62 @@ describe('Summary', () => { isRedirectionEnabled: false, newPath: undefined, }, - setNewPath: jest.fn(), + setNewPath: vi.fn(), }, } ) { const user = userEvent.setup() - const fetchNextPage = jest.fn() - const mockSearching = jest.fn() + const fetchNextPage = vi.fn() + const mockSearching = vi.fn() - const mockUseCoverageRedirect = useCoverageRedirect as jest.Mock - mockUseCoverageRedirect.mockReturnValue(coverageRedirectData) + mocks.useCoverageRedirect.mockReturnValue(coverageRedirectData) - const mockUseIntersection = useIntersection as jest.Mock - mockUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting, }) server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch } }, - }) - ) - ), - 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 === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches(hasNextPage) } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) } }, + }) }), - graphql.query('GetRepoCoverage', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ owner: { repository: mockRepoCoverage } }) - ) - ) + graphql.query('GetRepoCoverage', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockRepoCoverage } }, + }) + }) ) return { fetchNextPage, mockSearching, user } @@ -246,7 +255,7 @@ describe('Summary', () => { render(, { wrapper: wrapper() }) const dropDownBtn = await screen.findByRole('button') - const icon = await within(dropDownBtn).findByText('branch.svg') + const icon = await within(dropDownBtn).findByTestId('branch') expect(icon).toBeInTheDocument() }) @@ -282,7 +291,7 @@ describe('Summary', () => { describe('uses a conditional Redirect', () => { it('updates the location', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const coverageRedirectData = { redirectState: { newPath: '/some/new/location', @@ -308,7 +317,7 @@ describe('Summary', () => { describe('fires the setNewPath on branch selection', () => { it('updates the location', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const coverageRedirectData = { redirectState: { newPath: '/some/new/location', @@ -336,7 +345,7 @@ describe('Summary', () => { describe('when onLoadMore is triggered', () => { describe('there is a next page', () => { it('calls fetchNextPage', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const { fetchNextPage, user } = setup({ isIntersecting: true, hasNextPage: true, @@ -364,9 +373,9 @@ describe('Summary', () => { actually calling it but because of scoping it was always falsy */ - const fetchNextPage = jest.fn() + const fetchNextPage = vi.fn() it('does not call fetchNextPage', async () => { - const mockSetNewPath = jest.fn() + const mockSetNewPath = vi.fn() const { user } = setup({ isIntersecting: true, diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.tsx index d3ce8ab41b..809ca64b2e 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/SummaryTeamPlan/SummaryTeamPlan.tsx @@ -58,7 +58,12 @@ const SummaryTeamPlan = () => { items={branchList} buttonIcon={ - + } /> diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/index.js b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/index.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/hooks/index.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/hooks/index.ts diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.test.tsx similarity index 96% rename from src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.test.tsx index d8f6f4272e..a40b8a67ca 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useBranchSelector.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' @@ -68,12 +68,12 @@ afterAll(() => { describe('useBranchSelector', () => { function setup(branchName: string, returnBranches: boolean = true) { server.use( - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { if (returnBranches) { - return res(ctx.status(200), ctx.data(mockBranches(branchName))) + return HttpResponse.json({ data: mockBranches(branchName) }) } - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.test.tsx similarity index 91% rename from src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.test.tsx index cc28adb5f2..0c8a13d196 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useCoverageTabData.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 { useCoverageTabData } from './useCoverageTabData' @@ -115,21 +115,21 @@ describe('useCoverageTabData', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('CoverageTabData', (req, res, ctx) => { + graphql.query('CoverageTabData', (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(mockCoverageTabData)) + return HttpResponse.json({ data: mockCoverageTabData }) } }), - 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/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.test.jsx similarity index 93% rename from src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.test.jsx index 549a37299b..10b39a21a7 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.spec.js +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/hooks/useRepoCoverageTimeseries.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 { Trend } from 'shared/utils/legacyCharts' @@ -94,21 +94,21 @@ afterEach(() => { afterAll(() => server.close()) describe('useRepoCoverageTimeseries', () => { - let config = jest.fn() + let config = vi.fn() function setup({ noCoverageData = false } = { noCoverageData: false }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockRepoOverview)) - ), - graphql.query('GetBranchCoverageMeasurements', (req, res, ctx) => { - config(req.variables) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) + }), + graphql.query('GetBranchCoverageMeasurements', (info) => { + config(info.variables) if (noCoverageData) { - return res(ctx.status(200), ctx.data(mockNullBranchMeasurements)) + return HttpResponse.json({ data: mockNullBranchMeasurements }) } - return res(ctx.status(200), ctx.data(mockBranchMeasurements)) + return HttpResponse.json({ data: mockBranchMeasurements }) }) ) } @@ -268,7 +268,7 @@ describe('useRepoCoverageTimeseries', () => { }) it('calls select', async () => { - let selectMock = jest.fn() + let selectMock = vi.fn() renderHook(() => useRepoCoverageTimeseries({}, { select: selectMock }), { wrapper: wrapper(''), diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.test.tsx similarity index 88% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.test.tsx index f8a9581ae1..11e8992b95 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/ComponentsMultiSelect/ComponentsMultiSelect.test.tsx @@ -7,8 +7,8 @@ import { } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Location } from 'history' -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 ComponentsMultiSelect from './ComponentsMultiSelect' @@ -146,45 +146,39 @@ describe('ComponentsMultiSelect', () => { } ) { const user = userEvent.setup() - const mockApiVars = jest.fn() + const mockApiVars = vi.fn() server.use( - graphql.query('GetBranchComponents', (req, res, ctx) => { - mockApiVars(req.variables) + graphql.query('GetBranchComponents', (info) => { + mockApiVars(info.variables) - return res( - ctx.status(200), - ctx.data(mockComponentsResponse(components)) - ) + return HttpResponse.json({ data: mockComponentsResponse(components) }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch } }, - }) - ) - ), - graphql.query('GetBranches', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(branchesMock)) + }, + }) }), - graphql.query('GetRepoCoverage', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ owner: { repository: mockRepoCoverage } }) - ) - ) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ data: branchesMock }) + }), + graphql.query('GetRepoCoverage', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockRepoCoverage } }, + }) + }) ) return { user, mockApiVars } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.test.jsx similarity index 87% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.test.jsx index 2ba093cc64..fe6b54cb9f 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/CoverageChart/CoverageChart.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 CoverageChart from './CoverageChart' @@ -138,28 +138,26 @@ describe('CoverageChart', () => { coverageRepoStatus, }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(repoOverviewData)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: repoOverviewData }) }), - graphql.query('GetBranches', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(branchesData)) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ data: branchesData }) }), - graphql.query('GetBranch', (req, res, ctx) => - res(ctx.status(200), ctx.data(branchMock)) - ), - graphql.query('GetBranchCoverageMeasurements', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ data: branchMock }) + }), + graphql.query('GetBranchCoverageMeasurements', (info) => { if (coverageRepoStatus) { - return res(ctx.status(400), ctx.errors({ owner: null })) + return HttpResponse.json( + { errors: [{ owner: null }] }, + { status: 500 } + ) } - return res( - ctx.status(200), - ctx.data({ - owner: { - repository: branchMeasurementsData, - }, - }) - ) + return HttpResponse.json({ + data: { owner: { repository: branchMeasurementsData } }, + }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.test.tsx similarity index 93% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.test.tsx index 4bfe63e07a..625a5746c5 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/CodeTreeTable.test.tsx @@ -1,8 +1,8 @@ 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 } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import qs from 'qs' import { MemoryRouter, Route } from 'react-router-dom' @@ -221,46 +221,34 @@ describe('CodeTreeTable', () => { hasMultipleRows = false, }) { const user = userEvent.setup() - const requestFilters = jest.fn() + const requestFilters = vi.fn() server.use( - graphql.query('BranchContents', (req, res, ctx) => { - if (req.variables?.filters) { - requestFilters(req.variables?.filters) + graphql.query('BranchContents', (info) => { + if (info.variables?.filters) { + requestFilters(info.variables?.filters) } if (missingCoverage) { - return res(ctx.status(200), ctx.data({ owner: mockMissingCoverage })) + return HttpResponse.json({ data: { owner: mockMissingCoverage } }) + } else if (unknownPath) { + return HttpResponse.json({ data: { owner: mockUnknownPath } }) + } else if (noHeadReport) { + return HttpResponse.json({ data: { owner: mockNoHeadReport } }) + } else if (noFiles || info?.variables?.filters?.searchValue) { + return HttpResponse.json({ data: { owner: mockNoFiles } }) + } else if (noFlagCoverage) { + return HttpResponse.json({ data: { owner: mockNoFiles } }) + } else if (hasMultipleRows) { + return HttpResponse.json({ data: { owner: mockDataMultipleRows } }) + } else if (isNestedTreeData) { + return HttpResponse.json({ data: { owner: mockTreeDataNested } }) + } else { + return HttpResponse.json({ data: { owner: mockTreeData } }) } - - if (unknownPath) { - return res(ctx.status(200), ctx.data({ owner: mockUnknownPath })) - } - - if (noHeadReport) { - return res(ctx.status(200), ctx.data({ owner: mockNoHeadReport })) - } - - if (noFiles || req.variables?.filters?.searchValue) { - return res(ctx.status(200), ctx.data({ owner: mockNoFiles })) - } - - if (noFlagCoverage) { - return res(ctx.status(200), ctx.data({ owner: mockNoFiles })) - } - - if (hasMultipleRows) { - return res(ctx.status(200), ctx.data({ owner: mockDataMultipleRows })) - } - - if (isNestedTreeData) { - return res(ctx.status(200), ctx.data({ owner: mockTreeDataNested })) - } - - return res(ctx.status(200), ctx.data({ owner: mockTreeData })) }), - 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/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/index.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/index.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/index.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/CodeTreeTable/index.ts diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.test.jsx similarity index 83% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.test.jsx index 773fc833d6..eb77512757 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileExplorer.test.jsx @@ -1,21 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' import FileExplorer from './FileExplorer' -jest.mock('./FileListTable', () => () => 'File list table') -jest.mock('./CodeTreeTable', () => () => 'Code tree table') -jest.mock( - 'shared/ContentsTable/DisplayTypeButton', - () => () => 'Display type button' -) -jest.mock('shared/ContentsTable/FileBreadcrumb', () => () => 'File breadcrumb') -jest.mock('./FlagMultiSelect', () => () => 'FlagMultiSelect') -jest.mock('../ComponentsMultiSelect', () => () => 'Components Selector') +vi.mock('./FileListTable', () => ({ default: () => 'File list table' })) +vi.mock('./CodeTreeTable', () => ({ default: () => 'Code tree table' })) +vi.mock('shared/ContentsTable/DisplayTypeButton', () => ({ + default: () => 'Display type button', +})) +vi.mock('shared/ContentsTable/FileBreadcrumb', () => ({ + default: () => 'File breadcrumb', +})) +vi.mock('./FlagMultiSelect', () => ({ default: () => 'FlagMultiSelect' })) +vi.mock('../ComponentsMultiSelect', () => ({ + default: () => 'Components Selector', +})) const queryClient = new QueryClient({ defaultOptions: { @@ -168,26 +171,26 @@ describe('FileExplorer', () => { const user = userEvent.setup() server.use( - graphql.query('BranchContents', (req, res, ctx) => { + graphql.query('BranchContents', (info) => { if ( - req.variables?.filters?.displayType && - req.variables?.filters?.displayType === 'LIST' + info.variables?.filters?.displayType && + info.variables?.filters?.displayType === 'LIST' ) { - return res(ctx.status(200), ctx.data({ owner: mockListData })) + return HttpResponse.json({ data: { owner: mockListData } }) } if (missingCoverage) { - return res(ctx.status(200), ctx.data({ owner: mockMissingCoverage })) + return HttpResponse.json({ data: { owner: mockMissingCoverage } }) } if (unknownPath) { - return res(ctx.status(200), ctx.data({ owner: mockUnknownPath })) + return HttpResponse.json({ data: { owner: mockUnknownPath } }) } - return res(ctx.status(200), ctx.data({ owner: mockTreeData })) + return HttpResponse.json({ data: { owner: mockTreeData } }) }), - 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/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.test.tsx similarity index 93% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.test.tsx index c0be38f9bc..35dcdf024f 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/FileListTable.test.tsx @@ -1,8 +1,8 @@ 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 } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import qs from 'qs' import { MemoryRouter, Route } from 'react-router-dom' @@ -156,38 +156,30 @@ describe('FileListTable', () => { unknownPath = false, }) { const user = userEvent.setup({}) - const requestFilters = jest.fn() + const requestFilters = vi.fn() server.use( - graphql.query('BranchContents', (req, res, ctx) => { - if (req.variables?.filters) { - requestFilters(req.variables?.filters) + graphql.query('BranchContents', (info) => { + if (info.variables?.filters) { + requestFilters(info.variables?.filters) } if (noHeadReport) { - return res(ctx.status(200), ctx.data({ owner: mockNoHeadReport })) + return HttpResponse.json({ data: { owner: mockNoHeadReport } }) + } else if (noFiles || info?.variables?.filters?.searchValue) { + return HttpResponse.json({ data: { owner: mockNoFiles } }) + } else if (noFlagCoverage) { + return HttpResponse.json({ data: { owner: mockNoFiles } }) + } else if (missingCoverage) { + return HttpResponse.json({ data: { owner: mockMissingCoverage } }) + } else if (unknownPath) { + return HttpResponse.json({ data: { owner: mockUnknownPath } }) } - if (noFiles || req.variables?.filters?.searchValue) { - return res(ctx.status(200), ctx.data({ owner: mockNoFiles })) - } - - if (noFlagCoverage) { - return res(ctx.status(200), ctx.data({ owner: mockNoFiles })) - } - - if (missingCoverage) { - return res(ctx.status(200), ctx.data({ owner: mockMissingCoverage })) - } - - if (unknownPath) { - return res(ctx.status(200), ctx.data({ owner: mockUnknownPath })) - } - - return res(ctx.status(200), ctx.data({ owner: mockListData })) + return HttpResponse.json({ data: { owner: mockListData } }) }), - 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/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/index.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/index.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/index.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FileListTable/index.ts diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.test.jsx similarity index 88% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.test.jsx index f88d133fce..16c7a784c9 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/FlagMultiSelect.test.jsx @@ -1,16 +1,25 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import { TierNames } from 'services/tier' import FlagMultiSelect from './FlagMultiSelect' -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 mockRepoSettings = (isPrivate) => ({ owner: { @@ -177,31 +186,30 @@ describe('FlagMultiSelect', () => { } ) { const user = userEvent.setup() - const mockApiVars = jest.fn() + const mockApiVars = vi.fn() - useIntersection.mockReturnValue({ isIntersecting: isIntersecting }) + mocks.useIntersection.mockReturnValue({ isIntersecting: isIntersecting }) server.use( - graphql.query('FlagsSelect', (req, res, ctx) => { - mockApiVars(req.variables) + graphql.query('FlagsSelect', (info) => { + mockApiVars(info.variables) - if (!!req.variables?.after || noNextPage) { - return res(ctx.status(200), ctx.data(mockSecondResponse)) + if (!!info.variables?.after || noNextPage) { + return HttpResponse.json({ data: mockSecondResponse }) } - return res(ctx.status(200), ctx.data(mockFirstResponse)) + return HttpResponse.json({ data: mockFirstResponse }) }), - graphql.query('BackfillFlagMemberships', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(backfillData)) + graphql.query('BackfillFlagMemberships', (info) => { + return HttpResponse.json({ data: backfillData }) }), - graphql.query('OwnerTier', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: tierValue } } }) - ) + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ + data: { owner: { plan: { tierName: tierValue } } }, + }) }), - 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) }) }) ) diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/index.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/index.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/index.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/index.ts diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.test.tsx similarity index 94% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.test.tsx index f0939a150f..c1df4363d0 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/hooks/useRepoBranchContentsTable.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 qs from 'qs' import React from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -123,20 +123,20 @@ const mockOverview = { describe('useRepoBranchContentsTable', () => { function setup({ noData } = { noData: false }) { - const calledBranchContents = jest.fn() + const calledBranchContents = vi.fn() server.use( - graphql.query('BranchContents', (req, res, ctx) => { - calledBranchContents(req?.variables) + graphql.query('BranchContents', (info) => { + calledBranchContents(info?.variables) if (noData) { - return res(ctx.status(200), ctx.data(mockCommitNoContentData)) + return HttpResponse.json({ data: mockCommitNoContentData }) } - return res(ctx.status(200), ctx.data(mockBranchContentData)) + return HttpResponse.json({ data: mockBranchContentData }) }), - 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/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.test.tsx similarity index 92% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.test.tsx index 8ae70e7c47..e79b45a33d 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/RepoContentsResult.test.tsx @@ -1,16 +1,25 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' -import { MemoryRouter, Route, useParams } from 'react-router-dom' +import { MemoryRouter, Route } from 'react-router-dom' import RepoContentsResult from './RepoContentsResult' -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: jest - .fn() - .mockReturnValue({ provider: 'p', owner: 'blah', repo: 'bloo' }), +const mocks = vi.hoisted(() => ({ + useParams: vi.fn(), })) +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') + return { + ...actual, + useParams: mocks.useParams.mockReturnValue({ + provider: 'p', + owner: 'blah', + repo: 'bloo', + }), + } +}) + describe('RepoContentsResult', () => { it('renders no results if user is searching', async () => { const props = { @@ -82,8 +91,7 @@ describe('RepoContentsResult', () => { }, }) - const mockedUseParams = useParams as jest.Mock - mockedUseParams.mockReturnValue({ + mocks.useParams.mockReturnValue({ owner: 'codecov', provider: 'gh', repo: 'cool-repo', diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/index.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/index.ts similarity index 100% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/index.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/FileExplorer/shared/index.ts diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.test.jsx similarity index 80% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.test.jsx index fae9450bc5..93e40aa9fa 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Fileviewer/Fileviewer.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, 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 { TierNames } from 'services/tier' @@ -9,7 +9,7 @@ import { useScrollToLine } from 'ui/CodeRenderer/hooks/useScrollToLine' import FileView from './Fileviewer' -jest.mock('ui/CodeRenderer/hooks/useScrollToLine') +vi.mock('ui/CodeRenderer/hooks/useScrollToLine') const mockRepoSettings = (isPrivate) => ({ owner: { @@ -147,7 +147,7 @@ const wrapper = ) beforeAll(() => { - jest.spyOn(console, 'error').mockImplementation(() => {}) + vi.spyOn(console, 'error').mockImplementation(() => {}) server.listen() }) afterEach(() => { @@ -155,7 +155,7 @@ afterEach(() => { server.resetHandlers() }) afterAll(() => { - jest.resetAllMocks() + vi.resetAllMocks() server.close() }) @@ -168,46 +168,47 @@ describe('FileView', () => { ) { useScrollToLine.mockImplementation(() => ({ lineRef: () => {}, - handleClick: jest.fn(), + handleClick: vi.fn(), targeted: false, })) server.use( - graphql.query('DetailOwner', (req, res, ctx) => - res(ctx.status(200), ctx.data({ owner: mockOwner })) - ), - graphql.query('CoverageForFile', (req, res, ctx) => - res(ctx.status(200), ctx.data({ owner: { repository: mockCoverage } })) - ), - graphql.query('GetRepoOverview', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockOverview)) - ), - graphql.query('BackfillFlagMemberships', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBackfillResponse)) + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ data: { owner: mockOwner } }) }), - graphql.query('FlagsSelect', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockFlagResponse)) + graphql.query('CoverageForFile', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockCoverage } }, + }) }), - graphql.query('OwnerTier', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: tierName } } }) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockOverview }) + }), + graphql.query('BackfillFlagMemberships', (info) => { + return HttpResponse.json({ data: mockBackfillResponse }) + }), + graphql.query('FlagsSelect', (info) => { + return HttpResponse.json({ data: mockFlagResponse }) + }), + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ + data: { owner: { plan: { tierName: tierName } } }, + }) }), - 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('GetBranchComponents', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockComponents)) + graphql.query('GetBranchComponents', (info) => { + return HttpResponse.json({ data: mockComponents }) }), - graphql.query('GetBranches', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({})) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ data: {} }) }), - graphql.query('GetRepoCoverage', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({})) + graphql.query('GetRepoCoverage', (info) => { + return HttpResponse.json({ data: {} }) }), - graphql.query('GetBranch', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({})) + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ data: {} }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.spec.jsx b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.test.jsx similarity index 76% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.spec.jsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.test.jsx index 00dc9f456b..7ad04a84b1 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.spec.jsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/Sunburst.test.jsx @@ -1,12 +1,12 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' -import { graphql, rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' import Sunburst from './Sunburst' -jest.mock('ui/SunburstChart', () => () => 'Chart Mocked') +vi.mock('ui/SunburstChart', () => ({ default: () => 'Chart Mocked' })) const queryClient = new QueryClient({ defaultOptions: { @@ -70,21 +70,18 @@ describe('Sunburst', () => { coverageTreeStatus = 200, }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(repoOverviewData)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: repoOverviewData }) }), - graphql.query('RepoConfig', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(repoConfigMock)) + graphql.query('RepoConfig', (info) => { + return HttpResponse.json({ data: repoConfigMock }) }), - rest.get( - '/internal/:provider/:owner/:repo/coverage/tree', - (req, res, ctx) => { - return res( - ctx.status(coverageTreeStatus), - ctx.json({ data: coverageTreeRes }) - ) - } - ) + http.get('/internal/:provider/:owner/:repo/coverage/tree', (info) => { + return HttpResponse.json( + { data: coverageTreeRes }, + { status: coverageTreeStatus } + ) + }) ) } @@ -108,8 +105,8 @@ describe('Sunburst', () => { describe('tree 500', () => { beforeEach(() => { - // disable intentional error in jest log - jest.spyOn(console, 'error').mockImplementation(() => {}) + // disable intentional error in vi log + vi.spyOn(console, 'error').mockImplementation(() => {}) setup({ repoOverviewData: overviewMock, diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.spec.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.test.jsx similarity index 95% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.spec.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.test.jsx index ba4b89ad11..aaa0a99cb6 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.spec.js +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useConvertD3ToBreadcrumbs.test.jsx @@ -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 useConvertD3ToBreadcrumbs from './useConvertD3ToBreadcrumbs' @@ -58,8 +58,8 @@ const overviewMock = { describe('useConvertD3ToBreadcrumbs', () => { function setup({ repoOverviewData }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(repoOverviewData)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: repoOverviewData }) }) ) } diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.spec.js b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.test.jsx similarity index 82% rename from src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.spec.js rename to src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.test.jsx index 2cae49dc5d..2697dd3ffc 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.spec.js +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/subroute/Sunburst/hooks/useSunburstChart.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, waitFor } from '@testing-library/react' -import { graphql, rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import qs from 'qs' import { MemoryRouter, Route } from 'react-router-dom' @@ -56,9 +56,9 @@ const overviewMock = { } describe('useSunburstChart', () => { - const mockDetectedBranch = jest.fn() - const mockDetectedFlags = jest.fn() - const mockDetectedComponents = jest.fn() + const mockDetectedBranch = vi.fn() + const mockDetectedFlags = vi.fn() + const mockDetectedComponents = vi.fn() function setup({ repoOverviewData, @@ -66,22 +66,21 @@ describe('useSunburstChart', () => { coverageTreeStatus = 200, }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(repoOverviewData)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: repoOverviewData }) }), - rest.get( - '/internal/:provider/:owner/:repo/coverage/tree', - (req, res, ctx) => { - mockDetectedBranch(req.url.searchParams.get('branch')) - mockDetectedFlags(req.url.searchParams.getAll('flags')) - mockDetectedComponents(req.url.searchParams.get('components')) - - return res( - ctx.status(coverageTreeStatus), - ctx.json({ data: coverageTreeRes }) - ) - } - ) + http.get('/internal/:provider/:owner/:repo/coverage/tree', (info) => { + const searchParams = new URL(info.request.url).searchParams + + mockDetectedBranch(searchParams.get('branch')) + mockDetectedFlags(searchParams.getAll('flags')) + mockDetectedComponents(searchParams.get('components')) + + return HttpResponse.json( + { data: coverageTreeRes }, + { status: coverageTreeStatus } + ) + }) ) } @@ -110,13 +109,13 @@ describe('useSunburstChart', () => { describe('unsuccessful call', () => { beforeEach(() => { - jest.spyOn(console, 'error') + vi.spyOn(console, 'error') setup({ repoOverviewData: overviewMock, coverageTreeStatus: 500, }) }) - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.clearAllMocks()) it('returns undefined data if no data is received from the server', async () => { const { result } = renderHook(() => useSunburstChart(), { @@ -137,7 +136,7 @@ describe('useSunburstChart', () => { coverageTreeStatus: 200, }) }) - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.clearAllMocks()) it('query using default branch', async () => { renderHook(() => useSunburstChart(), { @@ -159,7 +158,7 @@ describe('useSunburstChart', () => { coverageTreeStatus: 200, }) }) - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.clearAllMocks()) it('query uses current branch', async () => { renderHook(() => useSunburstChart(), { @@ -181,7 +180,7 @@ describe('useSunburstChart', () => { coverageTreeStatus: 200, }) }) - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.clearAllMocks()) it('query uses flags and components', async () => { const queryString = qs.stringify( diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.test.tsx similarity index 92% rename from src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.test.tsx index 31bea85d81..72604fdd18 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useCoverageRedirect.test.tsx @@ -4,20 +4,25 @@ import { RenderHookResult, waitFor, } from '@testing-library/react' -import { useLocation, useParams } from 'react-router-dom' import { useCoverageRedirect, UseCoverageRedirectState, } from './useCoverageRedirect' -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: jest.fn(), - useLocation: jest.fn(), +const mocks = vi.hoisted(() => ({ + useParams: vi.fn(), + useLocation: vi.fn(), })) -const mockedUseParams = useParams as jest.Mock -const mockedUseLocation = useLocation as jest.Mock + +vi.mock('react-router-dom', async () => { + const actual = vi.importActual('react-router-dom') + return { + ...actual, + useParams: mocks.useParams, + useLocation: mocks.useLocation, + } +}) describe('useCoverageRedirect', () => { let hookData: RenderHookResult< @@ -29,8 +34,8 @@ describe('useCoverageRedirect', () => { > function setup({ useParamsValue = {}, startingLocation = 'some/path' }) { - mockedUseParams.mockReturnValue(useParamsValue) - mockedUseLocation.mockReturnValue({ pathname: startingLocation }) + mocks.useParams.mockReturnValue(useParamsValue) + mocks.useLocation.mockReturnValue({ pathname: startingLocation }) // TODO: move this into the it() blocks rather than in setup function per RTL best practices. hookData = renderHook(() => useCoverageRedirect()) diff --git a/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.spec.tsx b/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.test.tsx similarity index 84% rename from src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.spec.tsx rename to src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.test.tsx index 2baabe51fa..4876298227 100644 --- a/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.spec.tsx +++ b/src/pages/RepoPage/CoverageTab/OverviewTab/summaryHooks/useSummary.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' @@ -124,45 +124,40 @@ afterAll(() => { describe('useSummary', () => { function setup({ hasNoBranches } = { hasNoBranches: false }) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranch(req.variables?.branch) } }) - ) - ), - graphql.query('GetBranches', (req, res, ctx) => { + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockBranch(info.variables?.branch) } }, + }) + }), + graphql.query('GetBranches', (info) => { if (hasNoBranches) { - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) } - 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 } }, + }) }), - graphql.query('GetRepoCoverage', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ owner: { repository: mockRepoCoverage } }) - ) + graphql.query('GetRepoCoverage', (info) => + HttpResponse.json({ + data: { owner: { repository: mockRepoCoverage } }, + }) ) ) } From 30a38a2ff398b2754ddb12dc0449a3ad009c8c97 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 10:12:27 -0300 Subject: [PATCH 41/44] chore: Update pages/RepoPage/CoverageOnboarding tests to Vitest (#3333) --- ...ner.spec.tsx => ActivationBanner.test.tsx} | 31 ++++---- ....tsx => ActivationRequiredBanner.test.tsx} | 0 ....tsx => FreePlanSeatsLimitBanner.test.tsx} | 0 ....tsx => PaidPlanSeatsLimitBanner.test.tsx} | 0 ....spec.tsx => TrialEligibleBanner.test.tsx} | 10 +-- .../{CircleCI.spec.tsx => CircleCI.test.tsx} | 43 ++++++----- ...leBlurb.spec.tsx => ExampleBlurb.test.tsx} | 21 +----- ...ctions.spec.tsx => GitHubActions.test.tsx} | 43 ++++++----- ...ewRepoTab.spec.tsx => NewRepoTab.test.tsx} | 71 ++++++++++--------- .../{OtherCI.spec.tsx => OtherCI.test.tsx} | 35 +++++---- ...onBox.spec.tsx => InstructionBox.test.tsx} | 4 +- 11 files changed, 135 insertions(+), 123 deletions(-) rename src/pages/RepoPage/CoverageOnboarding/ActivationBanner/{ActivationBanner.spec.tsx => ActivationBanner.test.tsx} (85%) rename src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationRequiredBanner/{ActivationRequiredBanner.spec.tsx => ActivationRequiredBanner.test.tsx} (100%) rename src/pages/RepoPage/CoverageOnboarding/ActivationBanner/FreePlanSeatsLimitBanner/{FreePlanSeatsLimitBanner.spec.tsx => FreePlanSeatsLimitBanner.test.tsx} (100%) rename src/pages/RepoPage/CoverageOnboarding/ActivationBanner/PaidPlanSeatsLimitBanner/{PaidPlanSeatsLimitBanner.spec.tsx => PaidPlanSeatsLimitBanner.test.tsx} (100%) rename src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/{TrialEligibleBanner.spec.tsx => TrialEligibleBanner.test.tsx} (90%) rename src/pages/RepoPage/CoverageOnboarding/CircleCI/{CircleCI.spec.tsx => CircleCI.test.tsx} (88%) rename src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/{ExampleBlurb.spec.tsx => ExampleBlurb.test.tsx} (65%) rename src/pages/RepoPage/CoverageOnboarding/GitHubActions/{GitHubActions.spec.tsx => GitHubActions.test.tsx} (94%) rename src/pages/RepoPage/CoverageOnboarding/{NewRepoTab.spec.tsx => NewRepoTab.test.tsx} (88%) rename src/pages/RepoPage/CoverageOnboarding/OtherCI/{OtherCI.spec.tsx => OtherCI.test.tsx} (92%) rename src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/{InstructionBox.spec.tsx => InstructionBox.test.tsx} (97%) diff --git a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.test.tsx similarity index 85% rename from src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.test.tsx index bef965aeb4..f6a571cd21 100644 --- a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationBanner.test.tsx @@ -1,15 +1,23 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, 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 ActivationBanner from './ActivationBanner' -jest.mock('./TrialEligibleBanner', () => () => 'TrialEligibleBanner') -jest.mock('./ActivationRequiredBanner', () => () => 'ActivationRequiredBanner') -jest.mock('./FreePlanSeatsLimitBanner', () => () => 'FreePlanSeatsLimitBanner') -jest.mock('./PaidPlanSeatsLimitBanner', () => () => 'PaidPlanSeatsLimitBanner') +vi.mock('./TrialEligibleBanner', () => ({ + default: () => 'TrialEligibleBanner', +})) +vi.mock('./ActivationRequiredBanner', () => ({ + default: () => 'ActivationRequiredBanner', +})) +vi.mock('./FreePlanSeatsLimitBanner', () => ({ + default: () => 'FreePlanSeatsLimitBanner', +})) +vi.mock('./PaidPlanSeatsLimitBanner', () => ({ + default: () => 'PaidPlanSeatsLimitBanner', +})) const queryClient = new QueryClient() @@ -58,10 +66,9 @@ describe('ActivationBanner', () => { hasSeatsLeft = true ) { server.use( - graphql.query('GetPlanData', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetPlanData', (info) => { + return HttpResponse.json({ + data: { owner: { hasPrivateRepos: privateRepos, plan: { @@ -79,8 +86,8 @@ describe('ActivationBanner', () => { value: 'users-basic', }, }, - }) - ) + }, + }) }) ) } diff --git a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationRequiredBanner/ActivationRequiredBanner.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationRequiredBanner/ActivationRequiredBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationRequiredBanner/ActivationRequiredBanner.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ActivationBanner/ActivationRequiredBanner/ActivationRequiredBanner.test.tsx diff --git a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/FreePlanSeatsLimitBanner/FreePlanSeatsLimitBanner.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/FreePlanSeatsLimitBanner/FreePlanSeatsLimitBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageOnboarding/ActivationBanner/FreePlanSeatsLimitBanner/FreePlanSeatsLimitBanner.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ActivationBanner/FreePlanSeatsLimitBanner/FreePlanSeatsLimitBanner.test.tsx diff --git a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/PaidPlanSeatsLimitBanner/PaidPlanSeatsLimitBanner.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/PaidPlanSeatsLimitBanner/PaidPlanSeatsLimitBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/CoverageOnboarding/ActivationBanner/PaidPlanSeatsLimitBanner/PaidPlanSeatsLimitBanner.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ActivationBanner/PaidPlanSeatsLimitBanner/PaidPlanSeatsLimitBanner.test.tsx diff --git a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.test.tsx similarity index 90% rename from src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.test.tsx index 91eedcd9ab..9db104c5ba 100644 --- a/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/ActivationBanner/TrialEligibleBanner/TrialEligibleBanner.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' import TrialEligibleBanner from './TrialEligibleBanner' @@ -35,10 +35,10 @@ describe('TrialEligibleBanner', () => { const mockTrialMutationVariables = jest.fn() const user = userEvent.setup() server.use( - graphql.mutation('startTrial', (req, res, ctx) => { - mockTrialMutationVariables(req?.variables) + graphql.mutation('startTrial', (info) => { + mockTrialMutationVariables(info?.variables) - return res(ctx.status(200)) + return HttpResponse.json({ data: { startTrial: null } }) }) ) diff --git a/src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.test.tsx similarity index 88% rename from src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.test.tsx index 797642ed26..4f34baa7db 100644 --- a/src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/CircleCI/CircleCI.test.tsx @@ -1,19 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' -import { useFlags } from 'shared/featureFlags' - import CircleCI from './CircleCI' -jest.mock('shared/featureFlags') -const mockedUseFlags = useFlags as jest.Mock<{ - newRepoFlag: boolean -}> +const mocks = vi.hoisted(() => ({ + useFlags: vi.fn(), +})) + +vi.mock('shared/featureFlags', async () => { + const actual = await vi.importActual('shared/featureFlags') + return { + ...actual, + useFlags: mocks.useFlags, + } +}) const mockGetRepo = { owner: { @@ -80,23 +85,23 @@ interface SetupArgs { describe('CircleCI', () => { function setup({ hasOrgUploadToken = false }: SetupArgs) { - mockedUseFlags.mockReturnValue({ + mocks.useFlags.mockReturnValue({ newRepoFlag: hasOrgUploadToken, }) - const mockMetricMutationVariables = jest.fn() - const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem') + const mockMetricMutationVariables = vi.fn() + const mockGetItem = vi.spyOn(window.localStorage.__proto__, 'getItem') mockGetItem.mockReturnValue(null) server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetOrgUploadToken)) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ data: mockGetOrgUploadToken }) }), - graphql.mutation('storeEventMetric', (req, res, ctx) => { - mockMetricMutationVariables(req?.variables) - return res(ctx.status(200), ctx.data({ storeEventMetric: null })) + graphql.mutation('storeEventMetric', (info) => { + mockMetricMutationVariables(info?.variables) + return HttpResponse.json({ data: { storeEventMetric: null } }) }) ) return { mockMetricMutationVariables } diff --git a/src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.test.tsx similarity index 65% rename from src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.test.tsx index 7862d53bdb..ba9e633473 100644 --- a/src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/ExampleBlurb/ExampleBlurb.test.tsx @@ -1,27 +1,12 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' -import { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' import ExampleBlurb from './ExampleBlurb' -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - suspense: true, - retry: false, - }, - }, -}) - const wrapper: React.FC = ({ children }) => ( - - - - {children} - - - + + {children} + ) describe('ExampleBlurb', () => { diff --git a/src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.test.tsx similarity index 94% rename from src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.test.tsx index d6a039e00f..e1253679f4 100644 --- a/src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/GitHubActions/GitHubActions.test.tsx @@ -1,19 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { MemoryRouter, Route } from 'react-router-dom' -import { useFlags } from 'shared/featureFlags' - import GitHubActions from './GitHubActions' -jest.mock('shared/featureFlags') -const mockedUseFlags = useFlags as jest.Mock<{ - newRepoFlag: boolean -}> +const mocks = vi.hoisted(() => ({ + useFlags: vi.fn(), +})) + +vi.mock('shared/featureFlags', async () => { + const actual = await vi.importActual('shared/featureFlags') + return { + ...actual, + useFlags: mocks.useFlags, + } +}) const mockGetRepo = { owner: { @@ -81,24 +86,24 @@ interface SetupArgs { describe('GitHubActions', () => { function setup({ hasOrgUploadToken = false }: SetupArgs) { - mockedUseFlags.mockReturnValue({ + mocks.useFlags.mockReturnValue({ newRepoFlag: hasOrgUploadToken, }) - const mockMetricMutationVariables = jest.fn() - const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem') + const mockMetricMutationVariables = vi.fn() + const mockGetItem = vi.spyOn(window.localStorage.__proto__, 'getItem') mockGetItem.mockReturnValue(null) server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetOrgUploadToken)) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ data: mockGetOrgUploadToken }) }), - graphql.mutation('storeEventMetric', (req, res, ctx) => { - mockMetricMutationVariables(req?.variables) - return res(ctx.status(200), ctx.data({ storeEventMetric: null })) + graphql.mutation('storeEventMetric', (info) => { + mockMetricMutationVariables(info?.variables) + return HttpResponse.json({ data: { storeEventMetric: null } }) }) ) const user = userEvent.setup() diff --git a/src/pages/RepoPage/CoverageOnboarding/NewRepoTab.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/NewRepoTab.test.tsx similarity index 88% rename from src/pages/RepoPage/CoverageOnboarding/NewRepoTab.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/NewRepoTab.test.tsx index 18caee2c33..e6a33ecf1a 100644 --- a/src/pages/RepoPage/CoverageOnboarding/NewRepoTab.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/NewRepoTab.test.tsx @@ -1,21 +1,29 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { PropsWithChildren, Suspense } from 'react' import { MemoryRouter, Route, useLocation } from 'react-router-dom' -import { useRedirect } from 'shared/useRedirect' - import NewRepoTab from './NewRepoTab' -jest.mock('shared/useRedirect') -const mockedUseRedirect = useRedirect as jest.Mock -jest.mock('./GitHubActions', () => () => 'GitHubActions') -jest.mock('./CircleCI', () => () => 'CircleCI') -jest.mock('./OtherCI', () => () => 'OtherCI') -jest.mock('./ActivationBanner', () => () => 'ActivationBanner') +const mocks = vi.hoisted(() => ({ + useRedirect: vi.fn(), +})) + +vi.mock('shared/useRedirect', async () => { + const actual = await vi.importActual('shared/useRedirect') + return { + ...actual, + useRedirect: mocks.useRedirect, + } +}) + +vi.mock('./GitHubActions', () => ({ default: () => 'GitHubActions' })) +vi.mock('./CircleCI', () => ({ default: () => 'CircleCI' })) +vi.mock('./OtherCI', () => ({ default: () => 'OtherCI' })) +vi.mock('./ActivationBanner', () => ({ default: () => 'ActivationBanner' })) const mockCurrentUser = { me: { @@ -112,34 +120,31 @@ describe('NewRepoTab', () => { isPrivate = false, }: SetupArgs) { const user = userEvent.setup() - const hardRedirect = jest.fn() - mockedUseRedirect.mockImplementation((data) => ({ + const hardRedirect = vi.fn() + mocks.useRedirect.mockImplementation((data) => ({ hardRedirect: () => hardRedirect(data), })) - const mockMetricMutationVariables = jest.fn() - const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem') + const mockMetricMutationVariables = vi.fn() + const mockGetItem = vi.spyOn(window.localStorage.__proto__, 'getItem') mockGetItem.mockReturnValue(null) server.use( - graphql.query('GetRepo', (req, res, ctx) => - res( - ctx.status(200), - ctx.data( - mockGetRepo( - noUploadToken, - hasCommits, - isCurrentUserActivated, - isPrivate - ) - ) - ) - ), - graphql.query('CurrentUser', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockCurrentUser)) - ), - graphql.mutation('storeEventMetric', (req, res, ctx) => { - mockMetricMutationVariables(req?.variables) - return res(ctx.status(200), ctx.data({ storeEventMetric: null })) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ + data: mockGetRepo( + noUploadToken, + hasCommits, + isCurrentUserActivated, + isPrivate + ), + }) + }), + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ data: mockCurrentUser }) + }), + graphql.mutation('storeEventMetric', (info) => { + mockMetricMutationVariables(info?.variables) + return HttpResponse.json({ data: { storeEventMetric: null } }) }) ) diff --git a/src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.test.tsx similarity index 92% rename from src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.test.tsx index 0b626cd52a..06b9a97b16 100644 --- a/src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/OtherCI/OtherCI.test.tsx @@ -1,18 +1,23 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { MemoryRouter, Route } from 'react-router-dom' -import { useFlags } from 'shared/featureFlags' - import OtherCI from './OtherCI' -jest.mock('shared/featureFlags') -const mockedUseFlags = useFlags as jest.Mock<{ - newRepoFlag: boolean -}> +const mocks = vi.hoisted(() => ({ + useFlags: vi.fn(), +})) + +vi.mock('shared/featureFlags', async () => { + const actual = await vi.importActual('shared/featureFlags') + return { + ...actual, + useFlags: mocks.useFlags, + } +}) const mockGetRepo = { owner: { @@ -81,16 +86,16 @@ interface SetupArgs { describe('OtherCI', () => { function setup({ hasOrgUploadToken = false }: SetupArgs) { const user = userEvent.setup() - - mockedUseFlags.mockReturnValue({ + mocks.useFlags.mockReturnValue({ newRepoFlag: hasOrgUploadToken, }) + server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetOrgUploadToken)) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ data: mockGetOrgUploadToken }) }) ) diff --git a/src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.spec.tsx b/src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.test.tsx similarity index 97% rename from src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.spec.tsx rename to src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.test.tsx index 7c7af10041..c2bdda8b30 100644 --- a/src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.spec.tsx +++ b/src/pages/RepoPage/CoverageOnboarding/OtherCI/TerminalInstructions/InstructionBox.test.tsx @@ -5,8 +5,8 @@ import config from 'config' import { InstructionBox } from './InstructionBox' -jest.mock('copy-to-clipboard', () => () => true) -jest.mock('config') +vi.mock('copy-to-clipboard', () => ({ default: () => true })) +vi.mock('config') describe('InstructionBox', () => { function setup({ isSelfHosted = false } = {}) { From 4218716d1799b73b8ffbb792cf6a9f067ed43292 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 10:31:53 -0300 Subject: [PATCH 42/44] chore: Update pages/RepoPage/ConfigTab tests to Vitest (#3332) --- ...{ConfigTab.spec.tsx => ConfigTab.test.tsx} | 17 ++-- .../{Badges.spec.tsx => Badges.test.tsx} | 91 +++++++++---------- .../Badges/{index.js => index.ts} | 0 ...b.spec.tsx => BadgesAndGraphsTab.test.tsx} | 28 +++--- .../{Graphs.spec.jsx => Graphs.test.jsx} | 0 .../BadgesAndGraphsTab/{index.js => index.ts} | 0 ...spec.tsx => ConfigurationManager.test.tsx} | 8 +- ...reGroup.spec.tsx => FeatureGroup.test.tsx} | 0 ...tureItem.spec.tsx => FeatureItem.test.tsx} | 0 ...sx => useRepoConfigurationStatus.test.tsx} | 16 ++-- ...ent.spec.jsx => EraseRepoContent.test.jsx} | 37 +++++--- ....spec.jsx => DeactivateRepoModal.test.jsx} | 28 +++--- ...{RepoState.spec.jsx => RepoState.test.jsx} | 52 ++++++----- ...on.spec.jsx => useRepoActivation.test.jsx} | 41 +++++---- ...Branch.spec.jsx => DefaultBranch.test.jsx} | 53 +++++++---- ...eneralTab.spec.jsx => GeneralTab.test.jsx} | 53 ++++++----- ...raphToken.spec.jsx => GraphToken.test.jsx} | 0 ....spec.jsx => ImpactAnalysisToken.test.jsx} | 52 ++++++----- ...oken.spec.jsx => RepoUploadToken.test.jsx} | 60 ++++++------ .../StaticAnalysisToken.jsx | 2 +- ....spec.jsx => StaticAnalysisToken.test.jsx} | 61 ++++++------- .../{Tokens.spec.js => Tokens.test.jsx} | 42 +++++---- ...TokensTeam.spec.js => TokensTeam.test.jsx} | 15 ++- ...spec.tsx => useRepoForTokensTeam.test.tsx} | 16 ++-- ....spec.jsx => CurrentRepoSettings.test.jsx} | 2 +- ...tString.spec.jsx => SecretString.test.jsx} | 64 ++++++++----- ...ateYaml.spec.jsx => ValidateYaml.test.jsx} | 0 .../YAML/{YAML.spec.jsx => YAML.test.jsx} | 10 +- .../{YamlTab.spec.jsx => YamlTab.test.jsx} | 17 +++- 29 files changed, 418 insertions(+), 347 deletions(-) rename src/pages/RepoPage/ConfigTab/{ConfigTab.spec.tsx => ConfigTab.test.tsx} (88%) rename src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/{Badges.spec.tsx => Badges.test.tsx} (81%) rename src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/{index.js => index.ts} (100%) rename src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/{BadgesAndGraphsTab.spec.tsx => BadgesAndGraphsTab.test.tsx} (87%) rename src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Graphs/{Graphs.spec.jsx => Graphs.test.jsx} (100%) rename src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/{index.js => index.ts} (100%) rename src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/{ConfigurationManager.spec.tsx => ConfigurationManager.test.tsx} (98%) rename src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureGroup/{FeatureGroup.spec.tsx => FeatureGroup.test.tsx} (100%) rename src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureItem/{FeatureItem.spec.tsx => FeatureItem.test.tsx} (100%) rename src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/{useRepoConfigurationStatus.spec.tsx => useRepoConfigurationStatus.test.tsx} (91%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/{EraseRepoContent.spec.jsx => EraseRepoContent.test.jsx} (90%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/{DeactivateRepoModal.spec.jsx => DeactivateRepoModal.test.jsx} (86%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/{RepoState.spec.jsx => RepoState.test.jsx} (89%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/{useRepoActivation.spec.jsx => useRepoActivation.test.jsx} (72%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/{DefaultBranch.spec.jsx => DefaultBranch.test.jsx} (88%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/{GeneralTab.spec.jsx => GeneralTab.test.jsx} (82%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/GraphToken/{GraphToken.spec.jsx => GraphToken.test.jsx} (100%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/{ImpactAnalysisToken.spec.jsx => ImpactAnalysisToken.test.jsx} (89%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/{RepoUploadToken.spec.jsx => RepoUploadToken.test.jsx} (87%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/{StaticAnalysisToken.spec.jsx => StaticAnalysisToken.test.jsx} (88%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/{Tokens.spec.js => Tokens.test.jsx} (84%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/{TokensTeam.spec.js => TokensTeam.test.jsx} (91%) rename src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/{useRepoForTokensTeam.spec.tsx => useRepoForTokensTeam.test.tsx} (92%) rename src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/{CurrentRepoSettings.spec.jsx => CurrentRepoSettings.test.jsx} (98%) rename src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/{SecretString.spec.jsx => SecretString.test.jsx} (87%) rename src/pages/RepoPage/ConfigTab/tabs/YamlTab/ValidateYaml/{ValidateYaml.spec.jsx => ValidateYaml.test.jsx} (100%) rename src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/{YAML.spec.jsx => YAML.test.jsx} (86%) rename src/pages/RepoPage/ConfigTab/tabs/YamlTab/{YamlTab.spec.jsx => YamlTab.test.jsx} (87%) diff --git a/src/pages/RepoPage/ConfigTab/ConfigTab.spec.tsx b/src/pages/RepoPage/ConfigTab/ConfigTab.test.tsx similarity index 88% rename from src/pages/RepoPage/ConfigTab/ConfigTab.spec.tsx rename to src/pages/RepoPage/ConfigTab/ConfigTab.test.tsx index 9714cefc4d..e5d9df5319 100644 --- a/src/pages/RepoPage/ConfigTab/ConfigTab.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/ConfigTab.test.tsx @@ -1,14 +1,19 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' -import { useOwner } from 'services/user' - import ConfigTab from './ConfigTab' -jest.mock('services/user') -const mockedUseOwner = useOwner as jest.Mock +const mocks = vi.hoisted(() => ({ + useOwner: vi.fn(), +})) + +vi.mock('services/user', () => ({ + useOwner: mocks.useOwner, +})) -jest.mock('./tabs/ConfigurationManager', () => () => 'Configuration Manager') +vi.mock('./tabs/ConfigurationManager', () => ({ + default: () => 'Configuration Manager', +})) const wrapper: (initialEntries?: string) => React.FC = (initialEntries = '/gh/codecov/codecov-client/config') => @@ -24,7 +29,7 @@ interface SetupArgs { describe('ConfigTab', () => { function setup({ isCurrentUserPartOfOrg = true }: SetupArgs) { - mockedUseOwner.mockReturnValue({ data: { isCurrentUserPartOfOrg } }) + mocks.useOwner.mockReturnValue({ data: { isCurrentUserPartOfOrg } }) } describe('Render for a repo', () => { diff --git a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.test.tsx similarity index 81% rename from src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.test.tsx index 6077b2b5a4..a32bb7bc50 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/Badges.test.tsx @@ -1,23 +1,26 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { - render, - screen, - waitFor, - waitForElementToBeRemoved, -} from '@testing-library/react' +import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' -import { useIntersection } from 'react-use' import config from 'config' import Badges from './Badges' -jest.mock('config') -jest.mock('react-use/lib/useIntersection') -const mockedUseIntersection = useIntersection as jest.Mock +const mocks = vi.hoisted(() => ({ + useIntersection: vi.fn().mockReturnValue({ isIntersecting: false }), +})) + +vi.mock('config') +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) const mockNoBranches = { __typename: 'Repository', @@ -37,9 +40,7 @@ const mockBranches = (hasNextPage = false) => ({ { node: { name: 'branch-1', - head: { - commitid: 'asdf123', - }, + head: { commitid: 'asdf123' }, }, }, { @@ -80,12 +81,12 @@ const queryClient = new QueryClient({ }) beforeAll(() => { - jest.clearAllMocks() server.listen() }) afterEach(() => { queryClient.clear() server.resetHandlers() + vi.clearAllMocks() }) afterAll(() => { server.close() @@ -98,34 +99,32 @@ type SetupArgs = { describe('Badges', () => { function setup({ noBranches = false, hasNextPage = false }: SetupArgs) { - const fetchNextPage = jest.fn() - const mockSearching = jest.fn() + const fetchNextPage = vi.fn() + const mockSearching = vi.fn() config.BASE_URL = 'https://stage-web.codecov.dev' server.use( - graphql.query('GetBranches', (req, res, ctx) => { - if (req.variables?.after) { - fetchNextPage() + graphql.query('GetBranches', (info) => { + if (!!info.variables?.after) { + fetchNextPage(info.variables?.after) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } if (noBranches) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: mockNoBranches }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) }, - }) - ) + }, + }) }) ) @@ -203,12 +202,10 @@ describe('Badges', () => { const button = await screen.findByText('Default branch') expect(button).toBeInTheDocument() - user.click(button) + await user.click(button) const branch = await screen.findByText('branch-2') - user.click(branch) - - await waitForElementToBeRemoved(branch) + await user.click(branch) const baseUrl = await screen.findByText( '[![codecov](https://stage-web.codecov.dev/gh/codecov/codecov-client/branch/branch-2/graph/badge.svg?token=WIO9JXFGE)](https://stage-web.codecov.dev/gh/codecov/codecov-client)' @@ -224,7 +221,7 @@ describe('Badges', () => { const button = await screen.findByText('Default branch') expect(button).toBeInTheDocument() - user.click(button) + await user.click(button) const loading = await screen.findByText('Loading more items...') expect(loading).toBeInTheDocument() @@ -238,7 +235,7 @@ describe('Badges', () => { const button = await screen.findByText('Default branch') expect(button).toBeInTheDocument() - user.click(button) + await user.click(button) await waitFor(() => expect(screen.queryAllByText('Default branch')).toHaveLength(2) @@ -246,7 +243,7 @@ describe('Badges', () => { }) it('tries to load more', async () => { - mockedUseIntersection.mockReturnValue({ isIntersecting: true }) + mocks.useIntersection.mockReturnValue({ isIntersecting: true }) const { user, fetchNextPage } = setup({ hasNextPage: true }) render(, { wrapper, @@ -254,24 +251,22 @@ describe('Badges', () => { const button = await screen.findByText('Default branch') expect(button).toBeInTheDocument() - user.click(button) - - expect(await screen.findByText('Search')).toBeInTheDocument() + await user.click(button) - await waitFor(() => expect(fetchNextPage).toHaveBeenCalled()) + await waitFor(() => + expect(fetchNextPage).toHaveBeenCalledWith('end-cursor') + ) }) it('handles searching', async () => { - const { user, mockSearching } = setup({ hasNextPage: true }) + const { user, mockSearching } = setup({ hasNextPage: false }) render(, { wrapper, }) const button = await screen.findByText('Default branch') expect(button).toBeInTheDocument() - user.click(button) - - expect(await screen.findByText('Search')).toBeInTheDocument() + await user.click(button) const searchField = await screen.findByPlaceholderText('Search') await user.type(searchField, 'branch-3') diff --git a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/index.js b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/index.ts similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/index.js rename to src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Badges/index.ts diff --git a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.test.tsx similarity index 87% rename from src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.test.tsx index 985c12cf40..18276115e6 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/BadgesAndGraphsTab.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 BadgesAndGraphsTab from './BadgesAndGraphsTab' @@ -21,7 +21,7 @@ const wrapper: React.FC = ({ children }) => ( ) beforeAll(() => { - jest.clearAllMocks() + vi.clearAllMocks() server.listen() console.error = () => {} }) @@ -34,10 +34,9 @@ afterAll(() => server.close()) describe('BadgesAndGraphsTab', () => { function setup({ graphToken }: { graphToken: string | null }) { server.use( - graphql.query('GetBranches', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { branches: { @@ -45,13 +44,12 @@ describe('BadgesAndGraphsTab', () => { }, }, }, - }) - ) + }, + }) }), - graphql.query('GetRepoSettings', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoSettings', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -68,8 +66,8 @@ describe('BadgesAndGraphsTab', () => { staticAnalysisToken: null, }, }, - }) - ) + }, + }) }) ) } diff --git a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Graphs/Graphs.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Graphs/Graphs.test.jsx similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Graphs/Graphs.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/Graphs/Graphs.test.jsx diff --git a/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/index.js b/src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/index.ts similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/index.js rename to src/pages/RepoPage/ConfigTab/tabs/BadgesAndGraphsTab/index.ts diff --git a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.test.tsx similarity index 98% rename from src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.test.tsx index b4f1107539..d8931a5439 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/ConfigurationManager.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, 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' import { TierNames, TTierNames } from 'services/tier' @@ -83,8 +83,8 @@ interface SetupArgs { describe('Configuration Manager', () => { function setup({ repoConfig = mockRepoConfig({}) }: SetupArgs) { server.use( - graphql.query('GetRepoConfigurationStatus', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: repoConfig })) + graphql.query('GetRepoConfigurationStatus', (info) => { + return HttpResponse.json({ data: { owner: repoConfig } }) }) ) } diff --git a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureGroup/FeatureGroup.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureGroup/FeatureGroup.test.tsx similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureGroup/FeatureGroup.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureGroup/FeatureGroup.test.tsx diff --git a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureItem/FeatureItem.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureItem/FeatureItem.test.tsx similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureItem/FeatureItem.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/components/FeatureItem/FeatureItem.test.tsx diff --git a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.test.tsx similarity index 91% rename from src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.test.tsx index 7b41099239..aca10751c5 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/tabs/ConfigurationManager/hooks/useRepoConfigurationStatus/useRepoConfigurationStatus.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 { useRepoConfigurationStatus } from './useRepoConfigurationStatus' @@ -82,17 +82,17 @@ describe('useRepoConfigurationStatus', () => { nullOwner: nullResponse = false, }: SetupArgs) { server.use( - graphql.query('GetRepoConfigurationStatus', (req, res, ctx) => { + graphql.query('GetRepoConfigurationStatus', (info) => { if (badResponse) { - return res(ctx.status(200), ctx.data({})) + return HttpResponse.json({}) } else if (repoNotFound) { - return res(ctx.status(200), ctx.data(mockRepoNotFound)) + return HttpResponse.json({ data: mockRepoNotFound }) } else if (ownerNotActivated) { - return res(ctx.status(200), ctx.data(mockOwnerNotActivated)) + return HttpResponse.json({ data: mockOwnerNotActivated }) } else if (nullResponse) { - return res(ctx.status(200), ctx.data(mockNullOwner)) + return HttpResponse.json({ data: mockNullOwner }) } - return res(ctx.status(200), ctx.data(mockGoodResponse)) + return HttpResponse.json({ data: mockGoodResponse }) }) ) } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.test.jsx similarity index 90% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.test.jsx index d72235cbd4..6bba824d16 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/EraseRepoContent/EraseRepoContent.test.jsx @@ -2,15 +2,23 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import userEvent from '@testing-library/user-event' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { delay, graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import EraseRepoContent from './EraseRepoContent' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -70,24 +78,25 @@ describe('EraseRepoContent', () => { } ) { const user = userEvent.setup() - const mutate = jest.fn() - const addNotification = jest.fn() - useAddNotification.mockReturnValue(addNotification) + const mutate = vi.fn() + const addNotification = vi.fn() + mocks.useAddNotification.mockReturnValue(addNotification) server.use( - graphql.mutation('EraseRepository', (req, res, ctx) => { + graphql.mutation('EraseRepository', async (info) => { mutate() if (isLoading) { - // https://cathalmacdonnacha.com/mocking-error-empty-and-loading-states-with-msw - return res(ctx.status(200), ctx.data(mockResponse), ctx.delay(100)) + // https://mswjs.io/docs/api/delay/ + await delay('infinite') + return HttpResponse.json({ data: mockResponse }) } if (failedMutation) { - return res(ctx.status(200), ctx.data(mockErrorResponse)) + return HttpResponse.json({ data: mockErrorResponse }) } if (unauthorized) { - return res(ctx.status(200), ctx.data(mockUnauthorized)) + return HttpResponse.json({ data: mockUnauthorized }) } - return res(ctx.status(200), ctx.data(mockResponse)) + return HttpResponse.json({ data: mockResponse }) }) ) diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.test.jsx similarity index 86% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.test.jsx index c41157ccdd..58c30a4164 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/DeactivateRepoModal/DeactivateRepoModal.test.jsx @@ -12,8 +12,8 @@ describe('DeactivateRepoModal component', () => { } describe('renders the component correctly', () => { it('renders modal title', () => { - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { }) it('renders modal body', () => { - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { }) it('renders cancel button', () => { - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { }) it('renders deactivate button', () => { - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { it('closes modal when cancel is clicked', async () => { const { user } = setup() - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { it('calls deactivate when deactivate button is clicked', async () => { const { user } = setup() - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( { it('renders correctly when repo is deactivated', async () => { const { user } = setup() - const closeModalMock = jest.fn() - const deactivateRepoMock = jest.fn() + const closeModalMock = vi.fn() + const deactivateRepoMock = vi.fn() render( ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -37,14 +45,13 @@ afterAll(() => server.close()) describe('RepoState', () => { function setup({ activated = false, failMutation = false } = {}) { const user = userEvent.setup() - const mutate = jest.fn() - const addNotification = jest.fn() + const mutate = vi.fn() + const addNotification = vi.fn() server.use( - graphql.query('GetRepoSettings', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoSettings', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -61,24 +68,21 @@ describe('RepoState', () => { staticAnalysisToken: null, }, }, - }) - ) + }, + }) }), - rest.patch( - '/internal/github/codecov/repos/codecov-client/', - (req, res, ctx) => { - mutate() - - if (failMutation) { - return res(ctx.status(500)) - } + http.patch('/internal/github/codecov/repos/codecov-client/', (info) => { + mutate() - return res(ctx.status(200), ctx.json({})) + if (failMutation) { + return HttpResponse.error(500) } - ) + + return HttpResponse.json({}) + }) ) - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) return { mutate, addNotification, user } } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.test.jsx similarity index 72% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.test.jsx index 4bf58d8a1e..b67cec4428 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DangerZone/RepoState/hooks/useRepoActivation.test.jsx @@ -1,14 +1,22 @@ 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 { useAddNotification } from 'services/toastNotification' - import { useRepoActivation } from './useRepoActivation' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -34,26 +42,23 @@ afterEach(() => { afterAll(() => server.close()) describe('useRepoActivation', () => { - const mutate = jest.fn() - const addNotification = jest.fn() + const mutate = vi.fn() + const addNotification = vi.fn() function setup({ failMutation = false } = {}) { server.use( - rest.patch( - '/internal/github/codecov/repos/codecov-client/', - (req, res, ctx) => { - mutate() + http.patch('/internal/github/codecov/repos/codecov-client/', (info) => { + mutate() - if (failMutation) { - return res(ctx.status(500)) - } - - return res(ctx.status(200), ctx.json({})) + if (failMutation) { + return HttpResponse.error(500) } - ) + + return HttpResponse.json({}) + }) ) - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) } describe('when mutation is successful', () => { diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.test.jsx similarity index 88% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.test.jsx index c08c3edfdf..e48d7164de 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/DefaultBranch/DefaultBranch.test.jsx @@ -1,17 +1,31 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { graphql, rest } from 'msw' -import { setupServer } from 'msw/node' +import { graphql, http, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { MemoryRouter, Route } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' - -import { useAddNotification } from 'services/toastNotification' import DefaultBranch from './DefaultBranch' -jest.mock('services/toastNotification') -jest.mock('react-use/lib/useIntersection') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), + useIntersection: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) +vi.mock('react-use', async () => { + const actual = await vi.importActual('react-use') + return { + ...actual, + useIntersection: mocks.useIntersection, + } +}) const mockBranches = (hasNextPage = false) => ({ owner: { @@ -121,38 +135,37 @@ describe('DefaultBranch', () => { const fetchFilters = jest.fn() server.use( - graphql.query('GetBranches', (req, res, ctx) => { - const afterCursorPassed = !!req.variables?.after + graphql.query('GetBranches', (info) => { + const afterCursorPassed = !!info.variables?.after if (afterCursorPassed) { fetchesNextPage() const data = mockNextBranches(false) - return res(ctx.status(200), ctx.data(data)) + return HttpResponse.json({ data }) } - fetchFilters(req.variables?.filters) + fetchFilters(info.variables?.filters) const data = mockBranches(hasNextPage) - return res(ctx.status(200), ctx.data(data)) + return HttpResponse.json({ data }) }), - - rest.patch( + http.patch( '/internal/github/codecov/repos/codecov-client/', - async (req, res, ctx) => { - const data = await req?.json() + async (info) => { + const data = await info.request.json() mutate() if (failMutation) { - return res(ctx.status(500)) + return HttpResponse.error(500) } - return res(ctx.status(200), ctx.json(data)) + return HttpResponse.json(data) } ) ) - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) - useIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: isIntersecting, }) diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.test.jsx similarity index 82% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.test.jsx index 62b1fdfcd4..2ddfe30905 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/GeneralTab.test.jsx @@ -1,17 +1,25 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { TierNames } from 'services/tier' import GeneralTab from './GeneralTab' -jest.mock('./Tokens/TokensTeam', () => () => 'Tokens Team Component') -jest.mock('./Tokens/Tokens', () => () => 'Tokens Component') -jest.mock('./DangerZone', () => () => 'DangerZone Component') -jest.mock('./DefaultBranch', () => () => 'Default Branch') +vi.mock('./Tokens/TokensTeam', () => ({ + default: () => 'Tokens Team Component', +})) +vi.mock('./Tokens/Tokens', () => ({ + default: () => 'Tokens Component', +})) +vi.mock('./DangerZone', () => ({ + default: () => 'DangerZone Component', +})) +vi.mock('./DefaultBranch', () => ({ + default: () => 'Default Branch', +})) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -48,11 +56,10 @@ describe('GeneralTab', () => { } ) { server.use( - graphql.query('RepoDataTokensTeam', (req, res, ctx) => { + graphql.query('RepoDataTokensTeam', (info) => { if (hasDefaultBranch) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -60,12 +67,11 @@ describe('GeneralTab', () => { private: isPrivate, }, }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -73,17 +79,18 @@ describe('GeneralTab', () => { private: isPrivate, }, }, - }) - ) + }, + }) }), - graphql.query('OwnerTier', (req, res, ctx) => { + graphql.query('OwnerTier', (info) => { if (tierValue === TierNames.TEAM) { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.TEAM } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.TEAM } } }, + }) } - return res(ctx.status(200), ctx.data({ tierName: TierNames.PRO })) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.PRO } } }, + }) }) ) } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/GraphToken/GraphToken.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/GraphToken/GraphToken.test.jsx similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/GraphToken/GraphToken.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/GraphToken/GraphToken.test.jsx diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.test.jsx similarity index 89% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.test.jsx index d2d2d512ec..de52530306 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/ImpactAnalysisToken/ImpactAnalysisToken.test.jsx @@ -2,16 +2,24 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 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 { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import ImpactAnalysisToken from './ImpactAnalysisToken' -jest.mock('copy-to-clipboard', () => () => true) -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) +vi.mock('copy-to-clipboard', () => ({ default: () => true })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -31,7 +39,7 @@ beforeAll(() => server.listen()) afterEach(() => { queryClient.clear() server.resetHandlers() - jest.resetAllMocks() + vi.resetAllMocks() }) afterAll(() => server.close()) @@ -42,30 +50,28 @@ describe('ImpactAnalysisToken', () => { } ) { const user = userEvent.setup() - const addNotification = jest.fn() - const mutate = jest.fn() + const addNotification = vi.fn() + const mutate = vi.fn() - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) server.use( - graphql.query('CurrentUser', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ + data: { me: { id: 1, trackingMetadata: { ownerid: 1, }, }, - }) - ) + }, + }) }), - graphql.mutation('RegenerateRepositoryToken', (req, res, ctx) => { - mutate(req) - return res( - ctx.status(200), - ctx.data({ + graphql.mutation('RegenerateRepositoryToken', (info) => { + mutate(info.request) + return HttpResponse.json({ + data: { data: { regenerateRepositoryToken: { profilingToken: 'new token', @@ -74,8 +80,8 @@ describe('ImpactAnalysisToken', () => { }, }, }, - }) - ) + }, + }) }) ) return { addNotification, mutate, user } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.test.jsx similarity index 87% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.test.jsx index c86e0919d2..857862fd1b 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/RepoUploadToken/RepoUploadToken.test.jsx @@ -2,15 +2,23 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 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 { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import RepoUploadToken from './RepoUploadToken' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -34,7 +42,7 @@ beforeAll(() => { afterEach(() => { queryClient.clear() server.resetHandlers() - jest.resetAllMocks() + vi.resetAllMocks() }) afterAll(() => { server.close() @@ -48,35 +56,33 @@ describe('RepoUploadToken', () => { } ) { const user = userEvent.setup() - const mutate = jest.fn() - const addNotification = jest.fn() + const mutate = vi.fn() + const addNotification = vi.fn() - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) server.use( - graphql.mutation('RegenerateRepositoryUploadToken', (req, res, ctx) => { - mutate(req.variables) + graphql.mutation('RegenerateRepositoryUploadToken', (info) => { + mutate(info.request.variables) if (triggerError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { regenerateRepositoryUploadToken: { error: { __typename: 'ValidationError', }, }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { regenerateRepositoryUploadToken: { value: 'test', }, - }) - ) + }, + }) }) ) @@ -85,7 +91,7 @@ describe('RepoUploadToken', () => { describe('renders RepoUploadToken component', () => { beforeEach(() => setup()) - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('renders title', () => { render(, { wrapper }) @@ -124,7 +130,7 @@ describe('RepoUploadToken', () => { }) describe('when the user clicks on regenerate button', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('displays the regenerate upload token modal', async () => { const { user } = setup() @@ -152,7 +158,7 @@ describe('RepoUploadToken', () => { }) describe('when user clicks on Cancel button', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('does not call the mutation', async () => { const { mutate, user } = setup() @@ -178,7 +184,7 @@ describe('RepoUploadToken', () => { }) describe('when user clicks on Generate New Token button', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('calls the mutation', async () => { const tokenName = 'new token' @@ -213,7 +219,7 @@ describe('RepoUploadToken', () => { }) describe('when mutation is not successful', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('adds an error notification', async () => { const tokenName = 'new token' @@ -241,7 +247,7 @@ describe('RepoUploadToken', () => { }) describe('when render with no token', () => { - afterEach(() => jest.resetAllMocks()) + afterEach(() => vi.resetAllMocks()) it('does not render component', () => { render(, { wrapper }) diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.jsx index 341ca323ce..ff8ff2ba8a 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.jsx @@ -10,7 +10,7 @@ import RegenerateStaticTokenModal from './RegenerateStaticTokenModal' function StaticAnalysisToken({ staticAnalysisToken }) { const [showModal, setShowModal] = useState(false) - if (!staticAnalysisToken) { + if (typeof staticAnalysisToken !== 'string') { return null } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.test.jsx similarity index 88% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.test.jsx index 248555a001..0deabd5a7a 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/StaticAnalysisToken/StaticAnalysisToken.test.jsx @@ -2,16 +2,24 @@ import { render, screen, waitFor } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 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 { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import StaticAnalysisToken from './StaticAnalysisToken' -jest.mock('copy-to-clipboard', () => () => true) -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) +vi.mock('copy-to-clipboard', () => ({ default: () => true })) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -31,7 +39,7 @@ beforeAll(() => server.listen()) afterEach(() => { queryClient.clear() server.resetHandlers() - jest.resetAllMocks() + vi.clearAllMocks() }) afterAll(() => server.close()) @@ -42,40 +50,29 @@ describe('StaticAnalysisToken', () => { } ) { const user = userEvent.setup() - const addNotification = jest.fn() - const mutate = jest.fn() + const addNotification = vi.fn() + const mutate = vi.fn() - useAddNotification.mockReturnValue(addNotification) + mocks.useAddNotification.mockReturnValue(addNotification) server.use( - graphql.query('CurrentUser', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ - me: { - id: 1, - trackingMetadata: { - ownerid: 1, - }, - }, - }) - ) + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ + data: { me: { id: 1, trackingMetadata: { ownerid: 1 } } }, + }) }), - graphql.mutation('RegenerateRepositoryToken', (req, res, ctx) => { - mutate(req) - return res( - ctx.status(200), - ctx.data({ + graphql.mutation('RegenerateRepositoryToken', (info) => { + mutate(info.request) + return HttpResponse.json({ + data: { data: { regenerateRepositoryToken: { token: 'new token', - error: { - __typename: error, - }, + error: { __typename: error }, }, }, - }) - ) + }, + }) }) ) return { addNotification, mutate, user } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.spec.js b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.test.jsx similarity index 84% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.spec.js rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.test.jsx index e073fbdc3f..40e4fdc11f 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.spec.js +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/Tokens.test.jsx @@ -1,14 +1,22 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { useFlags } from 'shared/featureFlags' - import Tokens from './Tokens' -jest.mock('shared/featureFlags') +const mocks = vi.hoisted(() => ({ + useFlags: vi.fn(), +})) + +vi.mock('shared/featureFlags', async () => { + const actual = await vi.importActual('shared/featureFlags') + return { + ...actual, + useFlags: mocks.useFlags, + } +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -30,20 +38,20 @@ beforeAll(() => { afterEach(() => { queryClient.clear() server.resetHandlers() + vi.clearAllMocks() }) afterAll(() => server.close()) describe('Tokens', () => { function setup({ showStaticAnalysis = true } = { showStaticAnalysis: true }) { - useFlags.mockReturnValue({ + mocks.useFlags.mockReturnValue({ staticAnalysisToken: showStaticAnalysis, }) server.use( graphql.query('GetRepoSettings', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', @@ -60,18 +68,15 @@ describe('Tokens', () => { staticAnalysisToken: 'static analysis token', }, }, - }) - ) + }, + }) }) ) } describe('when rendered', () => { - beforeEach(() => { - setup() - }) - it('renders Repository upload token component', async () => { + setup() render(, { wrapper }) const title = await screen.findByText(/Repository upload token/) @@ -79,6 +84,7 @@ describe('Tokens', () => { }) it('renders impact analysis component', async () => { + setup() render(, { wrapper }) const title = await screen.findByText(/Impact analysis token/) @@ -86,6 +92,7 @@ describe('Tokens', () => { }) it('renders static token component', async () => { + setup() render(, { wrapper }) const title = await screen.findByText(/Static analysis token/) @@ -94,11 +101,8 @@ describe('Tokens', () => { }) describe('when static analysis flag is disabled', () => { - beforeEach(() => { - setup({ showStaticAnalysis: false }) - }) - it('does not render static token component', () => { + setup({ showStaticAnalysis: false }) render(, { wrapper }) const title = screen.queryByText(/Static analysis token/) diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.spec.js b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.test.jsx similarity index 91% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.spec.js rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.test.jsx index d4d1f937c0..d038a8fb3d 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.spec.js +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/Tokens/TokensTeam/TokensTeam.test.jsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 Tokens from './TokensTeam' @@ -32,10 +32,9 @@ afterAll(() => server.close()) describe('TokensTeam', () => { function setup() { server.use( - graphql.query('GetRepoSettingsTeam', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoSettingsTeam', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserPartOfOrg: true, repository: { @@ -53,8 +52,8 @@ describe('TokensTeam', () => { }, }, }, - }) - ) + }, + }) }) ) } diff --git a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.spec.tsx b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.test.tsx similarity index 92% rename from src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.spec.tsx rename to src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.test.tsx index 9d5f3de077..234d97e12e 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.spec.tsx +++ b/src/pages/RepoPage/ConfigTab/tabs/GeneralTab/hooks/useRepoForTokensTeam.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 { useRepoForTokensTeam } from './useRepoForTokensTeam' @@ -76,17 +76,17 @@ describe('useRepoForTokensTeam', () => { isNullOwner = false, }: SetupArgs) { server.use( - graphql.query('RepoDataTokensTeam', (req, res, ctx) => { + graphql.query('RepoDataTokensTeam', (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(mockRepoData)) + return HttpResponse.json({ data: mockRepoData }) } }) ) diff --git a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.test.jsx similarity index 98% rename from src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.test.jsx index e54ff90e73..191f5140f6 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/CurrentRepoSettings/CurrentRepoSettings.test.jsx @@ -4,7 +4,7 @@ import { MemoryRouter, Route } from 'react-router-dom' import CurrentRepoSettings from './CurrentRepoSettings' -jest.mock('services/repo') +vi.mock('services/repo') const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, diff --git a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.test.jsx similarity index 87% rename from src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.test.jsx index 00a6043945..83012ae12c 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/SecretString/SecretString.test.jsx @@ -1,22 +1,37 @@ -import { render, screen, waitFor } from 'custom-testing-library' - import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' -import { useAddNotification } from 'services/toastNotification' - import SecretString from './SecretString' -jest.mock('services/toastNotification') +const mocks = vi.hoisted(() => ({ + useAddNotification: vi.fn(), +})) + +vi.mock('services/toastNotification', async () => { + const actual = await vi.importActual('services/toastNotification') + return { + ...actual, + useAddNotification: mocks.useAddNotification, + } +}) const server = setupServer() +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +afterAll(() => { + server.close() +}) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -33,33 +48,32 @@ const wrapper = ({ children }) => ( describe('SecretString', () => { function setup(value = '', isError = false) { const user = userEvent.setup() - const addNotification = jest.fn() - const mutation = jest.fn() + const addNotification = vi.fn() + const mutation = vi.fn() + + mocks.useAddNotification.mockReturnValue(addNotification) - useAddNotification.mockReturnValue(addNotification) server.use( - graphql.mutation('EncodeSecretString', (req, res, ctx) => { - mutation(req.variables) + graphql.mutation('EncodeSecretString', (info) => { + mutation(info.variables) if (isError) { - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { encodeSecretString: { error: { __typename: 'ValidationError', }, }, - }) - ) + }, + }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { encodeSecretString: { value, }, - }) - ) + }, + }) }) ) diff --git a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/ValidateYaml/ValidateYaml.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/ValidateYaml/ValidateYaml.test.jsx similarity index 100% rename from src/pages/RepoPage/ConfigTab/tabs/YamlTab/ValidateYaml/ValidateYaml.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/YamlTab/ValidateYaml/ValidateYaml.test.jsx diff --git a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.test.jsx similarity index 86% rename from src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.test.jsx index c581cedd74..6638eb8640 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YAML/YAML.test.jsx @@ -5,10 +5,12 @@ import { MemoryRouter, Route } from 'react-router-dom' import YAML from './YAML' -jest.mock('react-ace', () => (props) => ) -jest.mock('ace-builds/src-noconflict/theme-github', () => {}) -jest.mock('ace-builds/src-noconflict/mode-yaml', () => {}) -jest.mock('services/repo') +vi.mock('react-ace', () => ({ + default: (props) => , +})) +vi.mock('ace-builds/src-noconflict/theme-github', () => ({ default: '' })) +vi.mock('ace-builds/src-noconflict/mode-yaml', () => ({ default: '' })) +vi.mock('services/repo') const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, diff --git a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.spec.jsx b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.test.jsx similarity index 87% rename from src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.spec.jsx rename to src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.test.jsx index 51dd537b8f..a87b5df856 100644 --- a/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.spec.jsx +++ b/src/pages/RepoPage/ConfigTab/tabs/YamlTab/YamlTab.test.jsx @@ -2,18 +2,25 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import { MemoryRouter, Route } from 'react-router-dom' -import { useEncodeString, useRepoSettings } from 'services/repo' - import YamlTab from './YamlTab' -jest.mock('services/repo') +const mocks = vi.hoisted(() => ({ + useEncodeString: vi.fn(), + useRepoSettings: vi.fn(), +})) + +vi.mock('services/repo', () => ({ + useEncodeString: mocks.useEncodeString, + useRepoSettings: mocks.useRepoSettings, +})) + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) describe('YamlTab', () => { function setup() { - useRepoSettings.mockReturnValue({ + mocks.useRepoSettings.mockReturnValue({ data: { repository: { yaml: 'test', @@ -23,7 +30,7 @@ describe('YamlTab', () => { }, }) - useEncodeString.mockReturnValue({ + mocks.useEncodeString.mockReturnValue({ data: { value: '', }, From 583136452bd4bf53e54336b59246b57caba069fe Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 10:46:54 -0300 Subject: [PATCH 43/44] chore: Update pages/RepoPage/BundlesTab tests to Vitest (#3328) --- ...etsTable.spec.tsx => AssetsTable.test.tsx} | 103 +++++------------- ...mptyTable.spec.tsx => EmptyTable.test.tsx} | 0 ...esTable.spec.tsx => ModulesTable.test.tsx} | 10 +- ...pers.spec.ts => assetTableHelpers.test.ts} | 0 ...spec.tsx => useBundleAssetsTable.test.tsx} | 14 +-- ...dleChart.spec.tsx => BundleChart.test.tsx} | 12 +- ...a.spec.tsx => useBundleChartData.test.tsx} | 29 ++--- ...ontent.spec.tsx => BundleContent.test.tsx} | 34 +++--- ...etails.spec.tsx => BundleDetails.test.tsx} | 20 ++-- ...ector.spec.tsx => BranchSelector.test.tsx} | 78 ++++++------- ...tion.spec.tsx => BundleSelection.test.tsx} | 41 ++++--- ...ector.spec.tsx => BundleSelector.test.tsx} | 25 +++-- ...elector.spec.tsx => LoadSelector.test.tsx} | 41 ++++--- ...elector.spec.tsx => TypeSelector.test.tsx} | 41 ++++--- ...orBanner.spec.tsx => ErrorBanner.test.tsx} | 0 ...nfoBanner.spec.tsx => InfoBanner.test.tsx} | 0 ...opdown.spec.tsx => TrendDropdown.test.tsx} | 0 ...ing.spec.tsx => BundleOnboarding.test.tsx} | 45 +++++--- ...rding.spec.tsx => NuxtOnboarding.test.tsx} | 62 +++++++---- ...ding.spec.tsx => RemixOnboarding.test.tsx} | 62 +++++++---- ...ing.spec.tsx => RollupOnboarding.test.tsx} | 62 +++++++---- ...spec.tsx => SolidStartOnboarding.test.tsx} | 62 +++++++---- ....spec.tsx => SvelteKitOnboarding.test.tsx} | 62 +++++++---- ...rding.spec.tsx => ViteOnboarding.test.tsx} | 63 +++++++---- ...ng.spec.tsx => WebpackOnboarding.test.tsx} | 60 ++++++---- ...undlesTab.spec.tsx => BundlesTab.test.tsx} | 39 +++---- 26 files changed, 515 insertions(+), 450 deletions(-) rename src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/{AssetsTable.spec.tsx => AssetsTable.test.tsx} (86%) rename src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/{EmptyTable.spec.tsx => EmptyTable.test.tsx} (100%) rename src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/{ModulesTable.spec.tsx => ModulesTable.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/{assetTableHelpers.spec.ts => assetTableHelpers.test.ts} (100%) rename src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/{useBundleAssetsTable.spec.tsx => useBundleAssetsTable.test.tsx} (95%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/{BundleChart.spec.tsx => BundleChart.test.tsx} (90%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/{useBundleChartData.spec.tsx => useBundleChartData.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleContent/{BundleContent.spec.tsx => BundleContent.test.tsx} (93%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/{BundleDetails.spec.tsx => BundleDetails.test.tsx} (93%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/{BranchSelector.spec.tsx => BranchSelector.test.tsx} (87%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/{BundleSelection.spec.tsx => BundleSelection.test.tsx} (91%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/{BundleSelector.spec.tsx => BundleSelector.test.tsx} (94%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/{LoadSelector.spec.tsx => LoadSelector.test.tsx} (88%) rename src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/{TypeSelector.spec.tsx => TypeSelector.test.tsx} (88%) rename src/pages/RepoPage/BundlesTab/BundleContent/ErrorBanner/{ErrorBanner.spec.tsx => ErrorBanner.test.tsx} (100%) rename src/pages/RepoPage/BundlesTab/BundleContent/InfoBanner/{InfoBanner.spec.tsx => InfoBanner.test.tsx} (100%) rename src/pages/RepoPage/BundlesTab/BundleContent/{TrendDropdown.spec.tsx => TrendDropdown.test.tsx} (100%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/{BundleOnboarding.spec.tsx => BundleOnboarding.test.tsx} (96%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/{NuxtOnboarding.spec.tsx => NuxtOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/{RemixOnboarding.spec.tsx => RemixOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/{RollupOnboarding.spec.tsx => RollupOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/{SolidStartOnboarding.spec.tsx => SolidStartOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/{SvelteKitOnboarding.spec.tsx => SvelteKitOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/{ViteOnboarding.spec.tsx => ViteOnboarding.test.tsx} (91%) rename src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/{WebpackOnboarding.spec.tsx => WebpackOnboarding.test.tsx} (92%) rename src/pages/RepoPage/BundlesTab/{BundlesTab.spec.tsx => BundlesTab.test.tsx} (79%) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.test.tsx similarity index 86% rename from src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.test.tsx index 8997d201db..76d37917ac 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/AssetsTable.test.tsx @@ -1,8 +1,8 @@ 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 } 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' @@ -13,21 +13,11 @@ const mockAssets = (hasNextPage = true) => { name: 'asset-1', extension: 'js', bundleData: { - loadTime: { - threeG: 2000, - highSpeed: 2000, - }, - size: { - uncompress: 4000, - gzip: 400, - }, + loadTime: { threeG: 2000, highSpeed: 2000 }, + size: { uncompress: 4000, gzip: 400 }, }, measurements: { - change: { - size: { - uncompress: 5, - }, - }, + change: { size: { uncompress: 5 } }, measurements: [ { timestamp: '2022-10-10T11:59:59', avg: 6 }, { timestamp: '2022-10-11T11:59:59', avg: null }, @@ -39,21 +29,11 @@ const mockAssets = (hasNextPage = true) => { name: 'asset-2', extension: 'js', bundleData: { - loadTime: { - threeG: 2000, - highSpeed: 2000, - }, - size: { - uncompress: 2000, - gzip: 200, - }, + loadTime: { threeG: 2000, highSpeed: 2000 }, + size: { uncompress: 2000, gzip: 200 }, }, measurements: { - change: { - size: { - uncompress: -5, - }, - }, + change: { size: { uncompress: -5 } }, measurements: [ { timestamp: '2022-10-10T11:59:59', avg: 6 }, { timestamp: '2022-10-11T11:59:59', avg: null }, @@ -65,14 +45,8 @@ const mockAssets = (hasNextPage = true) => { name: 'asset-3', extension: 'js', bundleData: { - loadTime: { - threeG: 2000, - highSpeed: 2000, - }, - size: { - uncompress: 2000, - gzip: 200, - }, + loadTime: { threeG: 2000, highSpeed: 2000 }, + size: { uncompress: 2000, gzip: 200 }, }, measurements: null, } @@ -86,16 +60,10 @@ const mockAssets = (hasNextPage = true) => { bundleAnalysisReport: { __typename: 'BundleAnalysisReport', bundle: { - bundleData: { - size: { - uncompress: 6000, - }, - }, + bundleData: { size: { uncompress: 6000 } }, assetsPaginated: { edges: [ - { - node: asset1, - }, + { node: asset1 }, ...(hasNextPage ? [{ node: asset2 }, { node: asset3 }] : []), @@ -125,14 +93,8 @@ const mockBundleAssetModules = { bundleAnalysisReport: { __typename: 'BundleAnalysisReport', bundle: { - bundleData: { - size: { - uncompress: 12, - }, - }, - asset: { - modules: [], - }, + bundleData: { size: { uncompress: 12 } }, + asset: { modules: [] }, }, }, }, @@ -150,17 +112,10 @@ const mockEmptyAssets = { bundleAnalysisReport: { __typename: 'BundleAnalysisReport', bundle: { - bundleData: { - size: { - uncompress: 12, - }, - }, + bundleData: { size: { uncompress: 12 } }, assetsPaginated: { edges: [], - pageInfo: { - hasNextPage: false, - endCursor: null, - }, + pageInfo: { hasNextPage: false, endCursor: null }, }, }, }, @@ -253,32 +208,32 @@ describe('AssetsTable', () => { const mockOrderingDirection = jest.fn() server.use( - graphql.query('BundleAssets', (req, res, ctx) => { + graphql.query('BundleAssets', (info) => { if (isEmptyBundles) { - return res(ctx.status(200), ctx.data(mockEmptyAssets)) + return HttpResponse.json({ data: mockEmptyAssets }) } else if (isMissingHeadReport) { - return res(ctx.status(200), ctx.data(mockMissingHeadReport)) + return HttpResponse.json({ data: mockMissingHeadReport }) } - if (req.variables?.ordering) { - mockOrdering(req.variables.ordering) + if (info.variables?.ordering) { + mockOrdering(info.variables.ordering) } - if (req.variables?.orderingDirection) { - mockOrderingDirection(req.variables.orderingDirection) + if (info.variables?.orderingDirection) { + mockOrderingDirection(info.variables.orderingDirection) } - if (multipleAssets && req.variables?.after) { + if (multipleAssets && info.variables?.after) { multipleAssets = true } - return res(ctx.status(200), ctx.data(mockAssets(multipleAssets))) + return HttpResponse.json({ data: mockAssets(multipleAssets) }) }), - graphql.query('BundleAssetModules', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBundleAssetModules)) + graphql.query('BundleAssetModules', (info) => { + return HttpResponse.json({ data: mockBundleAssetModules }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/EmptyTable.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/EmptyTable.test.tsx similarity index 100% rename from src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/EmptyTable.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/EmptyTable.test.tsx diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.test.tsx index 889c0e1af5..b85595c3f5 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/ModulesTable.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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' @@ -100,12 +100,12 @@ interface SetupArgs { describe('ModulesTable', () => { function setup({ noAssets = false }: SetupArgs) { server.use( - graphql.query('BundleAssetModules', (req, res, ctx) => { + graphql.query('BundleAssetModules', (info) => { if (noAssets) { - 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 }) }) ) } diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/assetTableHelpers.spec.ts b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/assetTableHelpers.test.ts similarity index 100% rename from src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/assetTableHelpers.spec.ts rename to src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/assetTableHelpers.test.ts diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.test.tsx similarity index 95% rename from src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.test.tsx index d1320c68d4..346a810757 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/AssetsTable/useBundleAssetsTable.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 qs from 'qs' import { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -125,12 +125,12 @@ describe('useBundleAssetsTable', () => { const queryVarMock = jest.fn() server.use( - graphql.query('BundleAssets', (req, res, ctx) => { - queryVarMock(req.variables) - return res(ctx.status(200), ctx.data(mockedBundleAssets)) + graphql.query('BundleAssets', (info) => { + queryVarMock(info.variables) + return HttpResponse.json({ data: mockedBundleAssets }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.test.tsx similarity index 90% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.test.tsx index 9c233d7b5a..b2858bd786 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/BundleChart.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 { BundleChart } from './BundleChart' @@ -101,11 +101,11 @@ afterAll(() => { describe('BundleChart', () => { function setup() { server.use( - graphql.query('GetBundleTrend', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBundleTrendData)) + graphql.query('GetBundleTrend', (info) => { + return HttpResponse.json({ data: mockBundleTrendData }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) } diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.test.tsx index 4d1c182f03..62c72dfa87 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleChart/useBundleChartData.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 qs from 'qs' import { MemoryRouter, Route } from 'react-router-dom' @@ -131,15 +131,15 @@ afterAll(() => { describe('useBundleChartData', () => { function setup() { - const queryVarMock = jest.fn() + const queryVarMock = vi.fn() server.use( - graphql.query('GetBundleTrend', (req, res, ctx) => { - queryVarMock(req.variables) - return res(ctx.status(200), ctx.data(mockBundleTrendData)) + graphql.query('GetBundleTrend', (info) => { + queryVarMock(info.variables) + return HttpResponse.json({ data: mockBundleTrendData }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockRepoOverview)) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) @@ -160,9 +160,6 @@ describe('useBundleChartData', () => { { wrapper: wrapper() } ) - await waitFor(() => expect(result.current.isLoading).toBeTruthy()) - await waitFor(() => expect(result.current.isLoading).toBeFalsy()) - const expectedResult = { isLoading: false, maxY: 32, @@ -194,12 +191,16 @@ describe('useBundleChartData', () => { }, ], } - expect(result.current).toStrictEqual(expectedResult) + await waitFor(() => expect(result.current).toStrictEqual(expectedResult)) }) describe('trend param is set', () => { beforeEach(() => { - jest.useFakeTimers().setSystemTime(new Date('2024-07-01')) + vi.useFakeTimers().setSystemTime(new Date('2024-07-01')) + }) + + afterEach(() => { + vi.useRealTimers() }) it('should use the trend param to set the query args', async () => { @@ -241,7 +242,7 @@ describe('useBundleChartData', () => { describe('types param', () => { beforeEach(() => { - jest.useFakeTimers().setSystemTime(new Date('2024-07-01')) + vi.useFakeTimers().setSystemTime(new Date('2024-07-01')) }) describe('no param set', () => { diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.test.tsx similarity index 93% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.test.tsx index 35f2338c9c..56a5b2bfaf 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleContent.test.tsx @@ -1,14 +1,16 @@ import * as Sentry from '@sentry/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, 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' import BundleContent from './BundleContent' -jest.mock('./BundleSelection', () => () =>
    BundleSelection
    ) +vi.mock('./BundleSelection', () => ({ + default: () =>
    BundleSelection
    , +})) const mockRepoOverview = { owner: { @@ -279,29 +281,29 @@ describe('BundleContent', () => { isEmptyBundleSelection = false, }: SetupArgs) { server.use( - graphql.query('BranchBundleSummaryData', (req, res, ctx) => { + graphql.query('BranchBundleSummaryData', (info) => { if (isBundleError) { - return res(ctx.status(200), ctx.data(mockBranchBundlesError)) + return HttpResponse.json({ data: mockBranchBundlesError }) } else if (isEmptyBundleSelection) { - return res(ctx.status(200), ctx.data(mockEmptyBundleSelection)) + return HttpResponse.json({ data: mockEmptyBundleSelection }) } - 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 }) }), - graphql.query('BundleAssets', (req, res, ctx) => { + graphql.query('BundleAssets', (info) => { if (isBundleError) { - return res(ctx.status(200), ctx.data(mockMissingHeadReportAssets)) + return HttpResponse.json({ data: mockMissingHeadReportAssets }) } - return res(ctx.status(200), ctx.data(mockAssets)) + return HttpResponse.json({ data: mockAssets }) }), - graphql.query('GetBundleTrend', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBundleTrendData)) + graphql.query('GetBundleTrend', (info) => { + return HttpResponse.json({ data: mockBundleTrendData }) }), - graphql.query('BundleSummary', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBundleSummary)) + graphql.query('BundleSummary', (info) => { + return HttpResponse.json({ data: mockBundleSummary }) }) ) } diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.test.tsx similarity index 93% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.test.tsx index 7bef1df684..f8f5c12214 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleDetails/BundleDetails.test.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, 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 qs from 'qs' import { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' @@ -93,21 +93,21 @@ interface SetupArgs { describe('BundleDetails', () => { function setup({ noSummary = false }: SetupArgs) { - const queryVars = jest.fn() + const queryVars = vi.fn() server.use( - graphql.query('BundleSummary', (req, res, ctx) => { + graphql.query('BundleSummary', (info) => { if (noSummary) { - return res(ctx.status(200), ctx.data(mockNoSummary)) + return HttpResponse.json({ data: mockNoSummary }) } - if (req.variables) { - queryVars(req.variables) + if (info.variables) { + queryVars(info.variables) } - 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', () => { + return HttpResponse.json({ data: mockRepoOverview }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.test.tsx similarity index 87% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.test.tsx index 9e19fa6c1a..87e4c2ccb0 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BranchSelector.test.tsx @@ -1,18 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' -import useIntersection from 'react-use/lib/useIntersection' import BranchSelector from './BranchSelector' -jest.mock('react-use/lib/useIntersection') -const mockedUseIntersection = useIntersection as unknown as jest.Mock<{ - isIntersecting: boolean -}> +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 mockRepoOverview = { __typename: 'Repository', @@ -157,25 +163,24 @@ describe('BranchSelector', () => { }) server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { if (nullOverview) { - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) + }, + }) }), - graphql.query('GetBranch', (req, res, ctx) => { + graphql.query('GetBranch', (info) => { let branch = 'main' - if (req.variables?.branch) { - branch = req.variables?.branch + if (info.variables?.branch) { + branch = info.variables?.branch } let mockedBranch = mockBranch(branch) @@ -183,35 +188,32 @@ describe('BranchSelector', () => { mockedBranch = mockBranch(branch, null) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockedBranch }, }, - }) - ) + }, + }) }), - 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 === 'main') { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockMainBranchSearch } }) - ) + if (info.variables?.filters?.searchValue === 'main') { + return HttpResponse.json({ + data: { owner: { repository: mockMainBranchSearch } }, + }) } - if (req.variables?.filters?.searchValue) { - mockSearching(req.variables?.filters?.searchValue) + if (info.variables?.filters?.searchValue) { + mockSearching(info.variables?.filters?.searchValue) } - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches(hasNextPage) } }) - ) + return HttpResponse.json({ + data: { owner: { repository: mockBranches(hasNextPage) } }, + }) }) ) @@ -334,7 +336,7 @@ describe('BranchSelector', () => { hasNextPage: false, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) @@ -358,7 +360,7 @@ describe('BranchSelector', () => { hasNextPage: true, }) - mockedUseIntersection.mockReturnValue({ + mocks.useIntersection.mockReturnValue({ isIntersecting: true, }) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.test.tsx similarity index 91% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.test.tsx index 0e6c8739b6..7f519be1a8 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelection.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route } from 'react-router-dom' @@ -120,35 +120,32 @@ describe('BundleSelection', () => { const user = userEvent.setup() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch }, }, - }) - ) + }, + }) }), - graphql.query('GetBranches', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches } }) - ) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockBranches } }, + }) }), - graphql.query('BranchBundlesNames', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBranchBundles)) + graphql.query('BranchBundlesNames', (info) => { + return HttpResponse.json({ data: mockBranchBundles }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.test.tsx similarity index 94% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.test.tsx index f495f92f5e..8e6beb602b 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/BundleSelector.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -117,25 +117,26 @@ describe('BundleSelector', () => { const mockFilterReset = jest.fn() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { + graphql.query('GetRepoOverview', (info) => { if (nullOverview) { - return res(ctx.status(200), ctx.data({ owner: null })) + return HttpResponse.json({ data: { owner: null } }) } - return res( - ctx.status(200), - ctx.data({ + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) + }, + }) }), - graphql.query('BranchBundlesNames', (req, res, ctx) => { + graphql.query('BranchBundlesNames', (info) => { if (missingHeadReport) { - return res(ctx.status(200), ctx.data(mockBadBundles)) - } else return res(ctx.status(200), ctx.data(mockBundles)) + return HttpResponse.json({ data: mockBadBundles }) + } + + return HttpResponse.json({ data: mockBundles }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.test.tsx similarity index 88% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.test.tsx index 9ae40e4ea0..9e8cc964e4 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/LoadSelector.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 qs from 'qs' import { Suspense } from 'react' import { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -133,35 +133,32 @@ describe('LoadSelector', () => { const user = userEvent.setup() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch }, }, - }) - ) + }, + }) }), - graphql.query('GetBranches', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches } }) - ) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockBranches } }, + }) }), - graphql.query('BranchBundlesNames', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBranchBundles(noBundles))) + graphql.query('BranchBundlesNames', (info) => { + return HttpResponse.json({ data: mockBranchBundles(noBundles) }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.test.tsx similarity index 88% rename from src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.test.tsx index f94b249e8b..17fbbc549b 100644 --- a/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleContent/BundleSelection/TypeSelector.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 qs from 'qs' import { Suspense } from 'react' import { MemoryRouter, Route, useLocation } from 'react-router-dom' @@ -133,35 +133,32 @@ describe('TypeSelector', () => { const user = userEvent.setup() server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserActivated: true, repository: mockRepoOverview, }, - }) - ) - ), - graphql.query('GetBranch', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + }, + }) + }), + graphql.query('GetBranch', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { __typename: 'Repository', ...mockBranch }, }, - }) - ) + }, + }) }), - graphql.query('GetBranches', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ owner: { repository: mockBranches } }) - ) + graphql.query('GetBranches', (info) => { + return HttpResponse.json({ + data: { owner: { repository: mockBranches } }, + }) }), - graphql.query('BranchBundlesNames', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockBranchBundles(noBundles))) + graphql.query('BranchBundlesNames', (info) => { + return HttpResponse.json({ data: mockBranchBundles(noBundles) }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/ErrorBanner/ErrorBanner.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/ErrorBanner/ErrorBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/BundlesTab/BundleContent/ErrorBanner/ErrorBanner.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/ErrorBanner/ErrorBanner.test.tsx diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/InfoBanner/InfoBanner.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/InfoBanner/InfoBanner.test.tsx similarity index 100% rename from src/pages/RepoPage/BundlesTab/BundleContent/InfoBanner/InfoBanner.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/InfoBanner/InfoBanner.test.tsx diff --git a/src/pages/RepoPage/BundlesTab/BundleContent/TrendDropdown.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleContent/TrendDropdown.test.tsx similarity index 100% rename from src/pages/RepoPage/BundlesTab/BundleContent/TrendDropdown.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleContent/TrendDropdown.test.tsx diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.test.tsx similarity index 96% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.test.tsx index 5975b9a547..3ee9923c5f 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/BundleOnboarding.test.tsx @@ -1,17 +1,24 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' -import { useRedirect } from 'shared/useRedirect' - import BundleOnboarding from './BundleOnboarding' -jest.mock('shared/useRedirect') -const mockedUseRedirect = useRedirect as jest.Mock +const mocks = vi.hoisted(() => ({ + useRedirect: vi.fn(), +})) + +vi.mock('shared/useRedirect', async () => { + const actual = await vi.importActual('shared/useRedirect') + return { + ...actual, + useRedirect: mocks.useRedirect, + } +}) const mockGetRepo = (hasUploadToken: boolean, isActive: boolean) => ({ owner: { @@ -112,24 +119,26 @@ describe('BundleOnboarding', () => { } ) { const user = userEvent.setup() - const hardRedirect = jest.fn() - mockedUseRedirect.mockImplementation((data) => ({ + const hardRedirect = vi.fn() + mocks.useRedirect.mockImplementation((data) => ({ hardRedirect: () => hardRedirect(data), })) - const mockMetricMutationVariables = jest.fn() - const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem') + const mockMetricMutationVariables = vi.fn() + const mockGetItem = vi.spyOn(window.localStorage.__proto__, 'getItem') mockGetItem.mockReturnValue(null) server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo(hasUploadToken, hasCommits))) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockGetOrgUploadToken)) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ + data: mockGetRepo(hasUploadToken, hasCommits), + }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ data: mockGetOrgUploadToken }) }), - graphql.mutation('storeEventMetric', (req, res, ctx) => { - mockMetricMutationVariables(req?.variables) - return res(ctx.status(200), ctx.data({ storeEventMetric: null })) + graphql.mutation('storeEventMetric', (info) => { + mockMetricMutationVariables(info.variables) + return HttpResponse.json({ data: { storeEventMetric: null } }) }) ) diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.test.tsx index bdc33eead3..28c513909a 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/NuxtOnboarding/NuxtOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import NuxtOnboarding from './NuxtOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading
    }>{children} + ) @@ -70,18 +87,17 @@ afterAll(() => { describe('NuxtOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('NuxtOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'nuxt' } } @@ -153,7 +169,7 @@ describe('NuxtOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'nuxt' } } @@ -187,7 +203,7 @@ describe('NuxtOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'nuxt' } } @@ -221,7 +237,7 @@ describe('NuxtOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'nuxt' } } @@ -292,7 +308,7 @@ describe('NuxtOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'nuxt' } } @@ -348,7 +364,7 @@ describe('NuxtOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'nuxt' } } @@ -405,7 +421,7 @@ describe('NuxtOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'nuxt' } } @@ -460,7 +476,7 @@ describe('NuxtOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'nuxt' } } @@ -492,7 +508,7 @@ describe('NuxtOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'nuxt' } } @@ -524,7 +540,7 @@ describe('NuxtOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'nuxt' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.test.tsx index 94f1216e06..b166061cb0 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/RemixOnboarding/RemixOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import RemixOnboarding from './RemixOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading
    }>{children} + ) @@ -70,18 +87,17 @@ afterAll(() => { describe('RemixOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('RemixOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'remix' } } @@ -153,7 +169,7 @@ describe('RemixOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'remix' } } @@ -187,7 +203,7 @@ describe('RemixOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'remix' } } @@ -221,7 +237,7 @@ describe('RemixOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'remix' } } @@ -292,7 +308,7 @@ describe('RemixOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'remix' } } @@ -348,7 +364,7 @@ describe('RemixOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'remix' } } @@ -405,7 +421,7 @@ describe('RemixOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'remix' } } @@ -460,7 +476,7 @@ describe('RemixOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'remix' } } @@ -492,7 +508,7 @@ describe('RemixOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'remix' } } @@ -524,7 +540,7 @@ describe('RemixOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'remix' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.test.tsx index 22ca1a19c6..6df8a39e1b 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/RollupOnboarding/RollupOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import RollupOnboarding from './RollupOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading
    }>{children} + ) @@ -70,18 +87,17 @@ afterAll(() => { describe('RollupOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('RollupOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'rollup' } } @@ -153,7 +169,7 @@ describe('RollupOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'rollup' } } @@ -187,7 +203,7 @@ describe('RollupOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'rollup' } } @@ -221,7 +237,7 @@ describe('RollupOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'rollup' } } @@ -292,7 +308,7 @@ describe('RollupOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'rollup' } } @@ -348,7 +364,7 @@ describe('RollupOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'rollup' } } @@ -405,7 +421,7 @@ describe('RollupOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'rollup' } } @@ -460,7 +476,7 @@ describe('RollupOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'rollup' } } @@ -492,7 +508,7 @@ describe('RollupOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'rollup' } } @@ -524,7 +540,7 @@ describe('RollupOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'rollup' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.test.tsx index 640611835e..ed70ef15b9 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/SolidStartOnboarding/SolidStartOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import SolidStartOnboarding from './SolidStartOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading
    }>{children} +
    ) @@ -70,18 +87,17 @@ afterAll(() => { describe('SolidStartOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('SolidStartOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'solidstart' } } @@ -155,7 +171,7 @@ describe('SolidStartOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'solidstart' } } @@ -191,7 +207,7 @@ describe('SolidStartOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'solidstart' } } @@ -227,7 +243,7 @@ describe('SolidStartOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'solidstart' } } @@ -298,7 +314,7 @@ describe('SolidStartOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'solidstart' } } @@ -356,7 +372,7 @@ describe('SolidStartOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'solidstart' } } @@ -415,7 +431,7 @@ describe('SolidStartOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'solidstart' } } @@ -472,7 +488,7 @@ describe('SolidStartOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'solidstart' } } @@ -506,7 +522,7 @@ describe('SolidStartOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'solidstart' } } @@ -540,7 +556,7 @@ describe('SolidStartOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'solidstart' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.test.tsx index 32565c07d1..6e36980dc7 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/SvelteKitOnboarding/SvelteKitOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import SvelteKitOnboarding from './SvelteKitOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading}>{children} + ) @@ -70,18 +87,17 @@ afterAll(() => { describe('SvelteKitOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('SvelteKitOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'sveltekit' } } @@ -155,7 +171,7 @@ describe('SvelteKitOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'sveltekit' } } @@ -191,7 +207,7 @@ describe('SvelteKitOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'sveltekit' } } @@ -227,7 +243,7 @@ describe('SvelteKitOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'sveltekit' } } @@ -298,7 +314,7 @@ describe('SvelteKitOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'sveltekit' } } @@ -356,7 +372,7 @@ describe('SvelteKitOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'sveltekit' } } @@ -415,7 +431,7 @@ describe('SvelteKitOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'sveltekit' } } @@ -472,7 +488,7 @@ describe('SvelteKitOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'sveltekit' } } @@ -506,7 +522,7 @@ describe('SvelteKitOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'sveltekit' } } @@ -540,7 +556,7 @@ describe('SvelteKitOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'sveltekit' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.test.tsx similarity index 91% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.test.tsx index 3303ef41e8..da1465530b 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/ViteOnboarding/ViteOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import ViteOnboarding from './ViteOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading}>{children} + ) @@ -61,6 +78,7 @@ beforeAll(() => { afterEach(() => { queryClient.clear() server.resetHandlers() + vi.clearAllMocks() }) afterAll(() => { @@ -70,18 +88,17 @@ afterAll(() => { describe('ViteOnboarding', () => { function setup(hasOrgUploadToken: boolean | null) { // mock out to clear error - window.prompt = jest.fn() + window.prompt = vi.fn() const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +111,7 @@ describe('ViteOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'vite' } } @@ -153,7 +170,7 @@ describe('ViteOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'vite' } } @@ -187,7 +204,7 @@ describe('ViteOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'vite' } } @@ -221,7 +238,7 @@ describe('ViteOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'vite' } } @@ -292,7 +309,7 @@ describe('ViteOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'vite' } } @@ -348,7 +365,7 @@ describe('ViteOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'vite' } } @@ -405,7 +422,7 @@ describe('ViteOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'vite' } } @@ -460,7 +477,7 @@ describe('ViteOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'vite' } } @@ -492,7 +509,7 @@ describe('ViteOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'vite' } } @@ -524,7 +541,7 @@ describe('ViteOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'vite' } } diff --git a/src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.spec.tsx b/src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.test.tsx similarity index 92% rename from src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.test.tsx index 855d1bbe13..bb49b36da2 100644 --- a/src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundleOnboarding/WebpackOnboarding/WebpackOnboarding.test.tsx @@ -1,13 +1,28 @@ -import * as Sentry from '@sentry/react' 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 } 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' import WebpackOnboarding from './WebpackOnboarding' +const mocks = vi.hoisted(() => ({ + increment: vi.fn(), +})) + +vi.mock('@sentry/react', async () => { + const originalModule = await vi.importActual('@sentry/react') + + return { + ...originalModule, + metrics: { + increment: mocks.increment, + }, + } +}) + const mockGetRepo = { owner: { isCurrentUserPartOfOrg: true, @@ -49,7 +64,9 @@ const server = setupServer() const wrapper: React.FC = ({ children }) => ( - {children} + + Loading}>{children} + ) @@ -74,14 +91,13 @@ describe('WebpackOnboarding', () => { const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res(ctx.status(200), ctx.data(mockGetRepo)) - ), - graphql.query('GetOrgUploadToken', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockGetOrgUploadToken(hasOrgUploadToken)) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockGetRepo }) + }), + graphql.query('GetOrgUploadToken', (info) => { + return HttpResponse.json({ + data: mockGetOrgUploadToken(hasOrgUploadToken), + }) }) ) @@ -94,7 +110,7 @@ describe('WebpackOnboarding', () => { render(, { wrapper }) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.visited_page', 1, { tags: { bundler: 'webpack' } } @@ -153,7 +169,7 @@ describe('WebpackOnboarding', () => { await user.click(npmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'npm', bundler: 'webpack' } } @@ -189,7 +205,7 @@ describe('WebpackOnboarding', () => { await user.click(yarnInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'yarn', bundler: 'webpack' } } @@ -225,7 +241,7 @@ describe('WebpackOnboarding', () => { await user.click(pnpmInstallCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.install_command', 1, { tags: { package_manager: 'pnpm', bundler: 'webpack' } } @@ -296,7 +312,7 @@ describe('WebpackOnboarding', () => { await user.click(uploadTokenCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.token', 1, { tags: { bundler: 'webpack' } } @@ -352,7 +368,7 @@ describe('WebpackOnboarding', () => { await user.click(pluginConfigCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.config', 1, { tags: { bundler: 'webpack' } } @@ -411,7 +427,7 @@ describe('WebpackOnboarding', () => { await user.click(commitCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.commit', 1, { tags: { bundler: 'webpack' } } @@ -466,7 +482,7 @@ describe('WebpackOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'npm', bundler: 'webpack' } } @@ -498,7 +514,7 @@ describe('WebpackOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'yarn', bundler: 'webpack' } } @@ -530,7 +546,7 @@ describe('WebpackOnboarding', () => { await user.click(buildCommandCopy) await waitFor(() => - expect(Sentry.metrics.increment).toHaveBeenCalledWith( + expect(mocks.increment).toHaveBeenCalledWith( 'bundles_tab.onboarding.copied.build_command', 1, { tags: { package_manager: 'pnpm', bundler: 'webpack' } } diff --git a/src/pages/RepoPage/BundlesTab/BundlesTab.spec.tsx b/src/pages/RepoPage/BundlesTab/BundlesTab.test.tsx similarity index 79% rename from src/pages/RepoPage/BundlesTab/BundlesTab.spec.tsx rename to src/pages/RepoPage/BundlesTab/BundlesTab.test.tsx index 4d80b1be0c..1b128d916d 100644 --- a/src/pages/RepoPage/BundlesTab/BundlesTab.spec.tsx +++ b/src/pages/RepoPage/BundlesTab/BundlesTab.test.tsx @@ -1,19 +1,16 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { - render, - screen, - waitFor, - waitForElementToBeRemoved, -} from '@testing-library/react' -import { graphql } from 'msw' -import { setupServer } from 'msw/node' +import { render, screen, waitFor } from '@testing-library/react' +import { graphql, HttpResponse } from 'msw2' +import { setupServer } from 'msw2/node' import { Suspense } from 'react' import { MemoryRouter, Route, useLocation } from 'react-router-dom' import BundlesTab from './BundlesTab' -jest.mock('./BundleContent', () => () =>
    BundleContent
    ) -jest.mock('./BundleOnboarding', () => () =>
    BundleOnboarding
    ) +vi.mock('./BundleContent', () => ({ default: () =>
    BundleContent
    })) +vi.mock('./BundleOnboarding', () => ({ + default: () =>
    BundleOnboarding
    , +})) const mockRepoOverview = ({ coverageEnabled = true, @@ -99,17 +96,14 @@ describe('BundlesTab', () => { language, }: SetupArgs) { server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data( - mockRepoOverview({ - coverageEnabled, - bundleAnalysisEnabled, - language, - }) - ) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview({ + coverageEnabled, + bundleAnalysisEnabled, + language, + }), + }) }) ) } @@ -133,9 +127,6 @@ describe('BundlesTab', () => { wrapper: wrapper(), }) - const loader = await screen.findByText('Loading') - await waitForElementToBeRemoved(loader) - await waitFor(() => expect(testLocation.pathname).toBe('/gh/test-owner/test-repo') ) From 403a1ec71ce5ed435b10675c13d9650558fce683 Mon Sep 17 00:00:00 2001 From: nicholas-codecov Date: Wed, 2 Oct 2024 11:05:47 -0300 Subject: [PATCH 44/44] chore: Update pages/RepoPage tests to Vitest (#3327) --- ...igured.spec.tsx => ATSConfigured.test.tsx} | 25 ++-- .../RepoPage/ATSTab/ATSNotConfigured.spec.tsx | 47 -------- .../RepoPage/ATSTab/ATSNotConfigured.test.tsx | 50 ++++++++ ...lert.spec.tsx => ActivationAlert.test.tsx} | 31 +++-- ...c.tsx => ActivationRequiredAlert.test.tsx} | 5 +- ...c.tsx => FreePlanSeatsTakenAlert.test.tsx} | 5 +- ...c.tsx => PaidPlanSeatsTakenAlert.test.tsx} | 5 +- ...c.tsx => UnauthorizedRepoDisplay.test.tsx} | 5 +- ...Repo.spec.jsx => DeactivatedRepo.test.tsx} | 19 ++-- ...eactivatedRepo.jsx => DeactivatedRepo.tsx} | 19 +++- .../DeactivatedRepo/{index.js => index.ts} | 0 .../{RepoPage.spec.tsx => RepoPage.test.tsx} | 107 ++++++++---------- ...ageTabs.spec.tsx => RepoPageTabs.test.tsx} | 87 +++++--------- .../{context.spec.tsx => context.test.tsx} | 17 ++- .../RepoPage/hooks/{index.js => index.ts} | 0 ...ks.spec.tsx => pathMatchersHooks.test.tsx} | 0 ...ec.tsx => useJSorTSPendoTracking.test.tsx} | 30 ++--- .../utils/{paths.spec.ts => paths.test.ts} | 0 18 files changed, 216 insertions(+), 236 deletions(-) rename src/pages/RepoPage/ATSTab/{ATSConfigured.spec.tsx => ATSConfigured.test.tsx} (71%) delete mode 100644 src/pages/RepoPage/ATSTab/ATSNotConfigured.spec.tsx create mode 100644 src/pages/RepoPage/ATSTab/ATSNotConfigured.test.tsx rename src/pages/RepoPage/ActivationAlert/{ActivationAlert.spec.tsx => ActivationAlert.test.tsx} (83%) rename src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/{ActivationRequiredAlert.spec.tsx => ActivationRequiredAlert.test.tsx} (91%) rename src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/{FreePlanSeatsTakenAlert.spec.tsx => FreePlanSeatsTakenAlert.test.tsx} (91%) rename src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/{PaidPlanSeatsTakenAlert.spec.tsx => PaidPlanSeatsTakenAlert.test.tsx} (91%) rename src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/{UnauthorizedRepoDisplay.spec.tsx => UnauthorizedRepoDisplay.test.tsx} (91%) rename src/pages/RepoPage/DeactivatedRepo/{DeactivatedRepo.spec.jsx => DeactivatedRepo.test.tsx} (88%) rename src/pages/RepoPage/DeactivatedRepo/{DeactivatedRepo.jsx => DeactivatedRepo.tsx} (73%) rename src/pages/RepoPage/DeactivatedRepo/{index.js => index.ts} (100%) rename src/pages/RepoPage/{RepoPage.spec.tsx => RepoPage.test.tsx} (92%) rename src/pages/RepoPage/{RepoPageTabs.spec.tsx => RepoPageTabs.test.tsx} (94%) rename src/pages/RepoPage/{context.spec.tsx => context.test.tsx} (94%) rename src/pages/RepoPage/hooks/{index.js => index.ts} (100%) rename src/pages/RepoPage/hooks/{pathMatchersHooks.spec.tsx => pathMatchersHooks.test.tsx} (100%) rename src/pages/RepoPage/hooks/{useJSorTSPendoTracking.spec.tsx => useJSorTSPendoTracking.test.tsx} (89%) rename src/pages/RepoPage/utils/{paths.spec.ts => paths.test.ts} (100%) diff --git a/src/pages/RepoPage/ATSTab/ATSConfigured.spec.tsx b/src/pages/RepoPage/ATSTab/ATSConfigured.test.tsx similarity index 71% rename from src/pages/RepoPage/ATSTab/ATSConfigured.spec.tsx rename to src/pages/RepoPage/ATSTab/ATSConfigured.test.tsx index b74f02cf39..42daa2f2a1 100644 --- a/src/pages/RepoPage/ATSTab/ATSConfigured.spec.tsx +++ b/src/pages/RepoPage/ATSTab/ATSConfigured.test.tsx @@ -3,33 +3,30 @@ import { MemoryRouter } from 'react-router-dom' import ATSConfigured from './ATSConfigured' -const wrapper: React.FC = () => ( +const wrapper: React.FC = ({ children }) => ( - + {children} ) -function setup() { - render(, { wrapper: wrapper }) -} - -beforeEach(() => { - setup() -}) - describe('ATSConfigured', () => { it('renders header', () => { - expect( - screen.getByText('Automated Test Selection Configured') - ).toBeInTheDocument() + render(, { wrapper: wrapper }) + + const header = screen.getByText('Automated Test Selection Configured') + expect(header).toBeInTheDocument() }) it('displays the beta badge', () => { + render(, { wrapper: wrapper }) + const betaBadge = screen.getByText('BETA') expect(betaBadge).toBeInTheDocument() }) it('displays the feedback link with correct text', () => { + render(, { wrapper: wrapper }) + const feedbackLink = screen.getByText('here') expect(feedbackLink).toBeInTheDocument() expect(feedbackLink).toHaveAttribute( @@ -39,6 +36,8 @@ describe('ATSConfigured', () => { }) it('renders the Read Documentation button', () => { + render(, { wrapper: wrapper }) + const readDocButton = screen.getByText('Read Documentation') expect(readDocButton).toBeInTheDocument() expect(readDocButton).toHaveAttribute( diff --git a/src/pages/RepoPage/ATSTab/ATSNotConfigured.spec.tsx b/src/pages/RepoPage/ATSTab/ATSNotConfigured.spec.tsx deleted file mode 100644 index aa09916c77..0000000000 --- a/src/pages/RepoPage/ATSTab/ATSNotConfigured.spec.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { render, screen } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ATSNotConfigured from './ATSNotConfigured' - -const wrapper: React.FC = () => ( - - - -) - -function setup() { - render(, { wrapper: wrapper }) -} - -beforeEach(() => { - setup() -}) - -describe('ATSNotConfigured', () => { - it('renders header', () => { - expect( - screen.getByText('Automated Test Selection Not Yet Configured') - ).toBeInTheDocument() - }) - - it('renders sub header', () => { - expect( - screen.getByText(/Ready to Accelerate Your CI\/CD Pipeline?/) - ).toBeInTheDocument() - }) - - it('renders paragraph', () => { - expect( - screen.getByText('Automated Test Selection is waiting to be set up!') - ).toBeInTheDocument() - }) - - it('renders the Read Documentation button', () => { - const readDocButton = screen.getByText('Read the Documentation and Set Up') - expect(readDocButton).toBeInTheDocument() - expect(readDocButton).toHaveAttribute( - 'href', - 'https://docs.codecov.com/docs/automated-test-selection' - ) - }) -}) diff --git a/src/pages/RepoPage/ATSTab/ATSNotConfigured.test.tsx b/src/pages/RepoPage/ATSTab/ATSNotConfigured.test.tsx new file mode 100644 index 0000000000..b7cf8d2427 --- /dev/null +++ b/src/pages/RepoPage/ATSTab/ATSNotConfigured.test.tsx @@ -0,0 +1,50 @@ +import { render, screen } from '@testing-library/react' +import { MemoryRouter } from 'react-router-dom' + +import ATSNotConfigured from './ATSNotConfigured' + +const wrapper: React.FC = ({ children }) => ( + + {children} + +) + +describe('ATSNotConfigured', () => { + it('renders header', () => { + render(, { wrapper: wrapper }) + + const header = screen.getByText( + 'Automated Test Selection Not Yet Configured' + ) + expect(header).toBeInTheDocument() + }) + + it('renders sub header', () => { + render(, { wrapper: wrapper }) + + const subHeader = screen.getByText( + /Ready to Accelerate Your CI\/CD Pipeline?/ + ) + expect(subHeader).toBeInTheDocument() + }) + + it('renders paragraph', () => { + render(, { wrapper: wrapper }) + + const paragraph = screen.getByText( + 'Automated Test Selection is waiting to be set up!' + ) + expect(paragraph).toBeInTheDocument() + }) + + it('renders the Read Documentation button', () => { + render(, { wrapper: wrapper }) + + const readDocButton = screen.getByText('Read the Documentation and Set Up') + expect(readDocButton).toBeInTheDocument() + expect(readDocButton).toHaveAttribute( + 'href', + 'https://docs.codecov.com/docs/automated-test-selection' + ) + }) +}) diff --git a/src/pages/RepoPage/ActivationAlert/ActivationAlert.spec.tsx b/src/pages/RepoPage/ActivationAlert/ActivationAlert.test.tsx similarity index 83% rename from src/pages/RepoPage/ActivationAlert/ActivationAlert.spec.tsx rename to src/pages/RepoPage/ActivationAlert/ActivationAlert.test.tsx index 8336afe72f..ed010a562f 100644 --- a/src/pages/RepoPage/ActivationAlert/ActivationAlert.spec.tsx +++ b/src/pages/RepoPage/ActivationAlert/ActivationAlert.test.tsx @@ -1,15 +1,23 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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 ActivationAlert from './ActivationAlert' -jest.mock('./FreePlanSeatsTakenAlert', () => () => 'FreePlanSeatsTakenAlert') -jest.mock('./PaidPlanSeatsTakenAlert', () => () => 'PaidPlanSeatsTakenAlert') -jest.mock('./ActivationRequiredAlert', () => () => 'ActivationRequiredAlert') -jest.mock('./UnauthorizedRepoDisplay', () => () => 'UnauthorizedRepoDisplay') +vi.mock('./FreePlanSeatsTakenAlert', () => ({ + default: () => 'FreePlanSeatsTakenAlert', +})) +vi.mock('./PaidPlanSeatsTakenAlert', () => ({ + default: () => 'PaidPlanSeatsTakenAlert', +})) +vi.mock('./ActivationRequiredAlert', () => ({ + default: () => 'ActivationRequiredAlert', +})) +vi.mock('./UnauthorizedRepoDisplay', () => ({ + default: () => 'UnauthorizedRepoDisplay', +})) const queryClient = new QueryClient() @@ -57,10 +65,9 @@ describe('ActivationAlert', () => { hasSeatsLeft = true ) { server.use( - graphql.query('GetPlanData', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data({ + graphql.query('GetPlanData', (info) => { + return HttpResponse.json({ + data: { owner: { hasPrivateRepos: privateRepos, plan: { @@ -77,8 +84,8 @@ describe('ActivationAlert', () => { value: 'users-basic', }, }, - }) - ) + }, + }) }) ) } diff --git a/src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.spec.tsx b/src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.test.tsx similarity index 91% rename from src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.spec.tsx rename to src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.test.tsx index ecb489e191..86a10833d3 100644 --- a/src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.spec.tsx +++ b/src/pages/RepoPage/ActivationAlert/ActivationRequiredAlert/ActivationRequiredAlert.test.tsx @@ -43,6 +43,9 @@ describe('ActivationRequiredAlert', () => { const img = screen.getByAltText('Forbidden') expect(img).toBeInTheDocument() - expect(img).toHaveAttribute('src', 'error-upsidedown-umbrella.svg') + expect(img).toHaveAttribute( + 'src', + '/src/layouts/shared/NetworkErrorBoundary/assets/error-upsidedown-umbrella.svg' + ) }) }) diff --git a/src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.spec.tsx b/src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.test.tsx similarity index 91% rename from src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.spec.tsx rename to src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.test.tsx index 0b3ad5049e..19a75f507a 100644 --- a/src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.spec.tsx +++ b/src/pages/RepoPage/ActivationAlert/FreePlanSeatsTakenAlert/FreePlanSeatsTakenAlert.test.tsx @@ -43,6 +43,9 @@ describe('FreePlanSeatsTakenAlert', () => { const img = screen.getByAltText('Forbidden') expect(img).toBeInTheDocument() - expect(img).toHaveAttribute('src', 'error-upsidedown-umbrella.svg') + expect(img).toHaveAttribute( + 'src', + '/src/layouts/shared/NetworkErrorBoundary/assets/error-upsidedown-umbrella.svg' + ) }) }) diff --git a/src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.spec.tsx b/src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.test.tsx similarity index 91% rename from src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.spec.tsx rename to src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.test.tsx index bc6c47a81b..8f20e63a3b 100644 --- a/src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.spec.tsx +++ b/src/pages/RepoPage/ActivationAlert/PaidPlanSeatsTakenAlert/PaidPlanSeatsTakenAlert.test.tsx @@ -43,6 +43,9 @@ describe('PaidPlanSeatsTakenAlert', () => { const img = screen.getByAltText('Forbidden') expect(img).toBeInTheDocument() - expect(img).toHaveAttribute('src', 'error-upsidedown-umbrella.svg') + expect(img).toHaveAttribute( + 'src', + '/src/layouts/shared/NetworkErrorBoundary/assets/error-upsidedown-umbrella.svg' + ) }) }) diff --git a/src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.spec.tsx b/src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.test.tsx similarity index 91% rename from src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.spec.tsx rename to src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.test.tsx index 69629bdbbd..31fc13969d 100644 --- a/src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.spec.tsx +++ b/src/pages/RepoPage/ActivationAlert/UnauthorizedRepoDisplay/UnauthorizedRepoDisplay.test.tsx @@ -43,6 +43,9 @@ describe('UnauthorizedRepoDisplay', () => { const img = screen.getByAltText('Forbidden') expect(img).toBeInTheDocument() - expect(img).toHaveAttribute('src', 'error-upsidedown-umbrella.svg') + expect(img).toHaveAttribute( + 'src', + '/src/layouts/shared/NetworkErrorBoundary/assets/error-upsidedown-umbrella.svg' + ) }) }) diff --git a/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.spec.jsx b/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.test.tsx similarity index 88% rename from src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.spec.jsx rename to src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.test.tsx index 53192f8702..eaa0d82cc0 100644 --- a/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.spec.jsx +++ b/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.test.tsx @@ -1,8 +1,8 @@ import { render, screen } from 'custom-testing-library' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -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 DeactivatedRepo from './DeactivatedRepo' @@ -12,7 +12,7 @@ const queryClient = new QueryClient({ }) const server = setupServer() -const wrapper = ({ children }) => ( +const wrapper: React.FC = ({ children }) => ( {children} @@ -34,10 +34,9 @@ afterAll(() => { describe('DeactivatedRepo', () => { function setup(isCurrentUserPartOfOrg = true) { server.use( - graphql.query('GetRepo', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ + data: { owner: { isCurrentUserPartOfOrg, isAdmin: null, @@ -55,9 +54,9 @@ describe('DeactivatedRepo', () => { isFirstPullRequest: false, }, }, - }) - ) - ) + }, + }) + }) ) } diff --git a/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.jsx b/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.tsx similarity index 73% rename from src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.jsx rename to src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.tsx index dabfee8721..b218b6438c 100644 --- a/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.jsx +++ b/src/pages/RepoPage/DeactivatedRepo/DeactivatedRepo.tsx @@ -5,8 +5,14 @@ import A from 'ui/A' import deactivatedRepo from './assets/deactivatedRepo.svg' +interface URLParams { + provider: string + owner: string + repo: string +} + function DeactivatedRepo() { - const { provider, owner, repo } = useParams() + const { provider, owner, repo } = useParams() const { data: repoData } = useRepo({ provider, owner, @@ -28,8 +34,15 @@ function DeactivatedRepo() { {isCurrentUserPartOfOrg ? ( <> To reactivate the repo go to{' '} - Settings or upload a - coverage report and it will be automatically re-activated. + + Settings{' '} + {' '} + or upload a coverage report and it will be automatically + re-activated. ) : ( 'Contact an administrator of your git organization to grant write-permissions in your git-provider for this repository.' diff --git a/src/pages/RepoPage/DeactivatedRepo/index.js b/src/pages/RepoPage/DeactivatedRepo/index.ts similarity index 100% rename from src/pages/RepoPage/DeactivatedRepo/index.js rename to src/pages/RepoPage/DeactivatedRepo/index.ts diff --git a/src/pages/RepoPage/RepoPage.spec.tsx b/src/pages/RepoPage/RepoPage.test.tsx similarity index 92% rename from src/pages/RepoPage/RepoPage.spec.tsx rename to src/pages/RepoPage/RepoPage.test.tsx index d8eca107df..df0715896f 100644 --- a/src/pages/RepoPage/RepoPage.spec.tsx +++ b/src/pages/RepoPage/RepoPage.test.tsx @@ -1,33 +1,28 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } 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 { MemoryRouter, Route, useLocation } from 'react-router-dom' import NetworkErrorBoundary from 'layouts/shared/NetworkErrorBoundary' import { TierNames } from 'services/tier' -import { useFlags } from 'shared/featureFlags' import { RepoBreadcrumbProvider } from './context' import RepoPage from './RepoPage' -jest.mock('./BundlesTab', () => () => 'BundlesTab') -jest.mock('./BundlesTab/BundleOnboarding', () => () => 'BundleOnboarding') -jest.mock('./CommitsTab', () => () => 'CommitsTab') -jest.mock('./CoverageTab', () => () => 'CoverageTab') -jest.mock('./CoverageOnboarding', () => () => 'CoverageOnboarding') -jest.mock('./PullsTab', () => () => 'PullsTab') -jest.mock('./ConfigTab', () => () => 'ConfigurationTab') -jest.mock('shared/featureFlags') -jest.mock('./ActivationAlert', () => () => 'ActivationAlert') -jest.mock('./FailedTestsTab', () => () => 'FailedTestsTab') - -jest.mock('shared/featureFlags') -const mockedUseFlags = useFlags as jest.Mock<{ - componentTab: boolean -}> +vi.mock('./BundlesTab', () => ({ default: () => 'BundlesTab' })) +vi.mock('./BundlesTab/BundleOnboarding', () => ({ + default: () => 'BundleOnboarding', +})) +vi.mock('./CommitsTab', () => ({ default: () => 'CommitsTab' })) +vi.mock('./CoverageTab', () => ({ default: () => 'CoverageTab' })) +vi.mock('./CoverageOnboarding', () => ({ default: () => 'CoverageOnboarding' })) +vi.mock('./PullsTab', () => ({ default: () => 'PullsTab' })) +vi.mock('./ConfigTab', () => ({ default: () => 'ConfigurationTab' })) +vi.mock('./ActivationAlert', () => ({ default: () => 'ActivationAlert' })) +vi.mock('./FailedTestsTab', () => ({ default: () => 'FailedTestsTab' })) const mockGetRepo = ({ noUploadToken = false, @@ -239,10 +234,6 @@ describe('RepoPage', () => { bundleAnalysisEnabled: true, } ) { - mockedUseFlags.mockReturnValue({ - componentTab: true, - }) - const user = userEvent.setup() const queryClient = new QueryClient({ defaultOptions: { @@ -254,55 +245,47 @@ describe('RepoPage', () => { }) server.use( - graphql.query('GetRepo', (req, res, ctx) => { + graphql.query('GetRepo', (info) => { if (hasRepoData) { - return res( - ctx.status(200), - ctx.data( - mockGetRepo({ - noUploadToken, - isRepoActive, - isRepoPrivate, - isRepoActivated, - isCurrentUserPartOfOrg, - isCurrentUserActivated, - }) - ) - ) + return HttpResponse.json({ + data: mockGetRepo({ + noUploadToken, + isRepoActive, + isRepoPrivate, + isRepoActivated, + isCurrentUserPartOfOrg, + isCurrentUserActivated, + }), + }) } - return res(ctx.status(200), ctx.data({ owner: {} })) + return HttpResponse.json({ data: { owner: {} } }) }), - graphql.query('OwnerTier', (req, res, ctx) => { + graphql.query('OwnerTier', (info) => { if (tierValue === TierNames.TEAM) { - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.TEAM } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.TEAM } } }, + }) } - return res( - ctx.status(200), - ctx.data({ owner: { plan: { tierName: TierNames.PRO } } }) - ) + return HttpResponse.json({ + data: { owner: { plan: { tierName: TierNames.PRO } } }, + }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data( - mockRepoOverview({ - coverageEnabled, - bundleAnalysisEnabled, - testAnalyticsEnabled, - language, - }) - ) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview({ + coverageEnabled, + bundleAnalysisEnabled, + testAnalyticsEnabled, + language, + }), + }) }), - graphql.query('DetailOwner', (req, res, ctx) => { - return res(ctx.data({ owner: mockOwner })) + graphql.query('DetailOwner', (info) => { + return HttpResponse.json({ data: { owner: mockOwner } }) }), - graphql.query('CurrentUser', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockUser)) + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ data: mockUser }) }) ) diff --git a/src/pages/RepoPage/RepoPageTabs.spec.tsx b/src/pages/RepoPage/RepoPageTabs.test.tsx similarity index 94% rename from src/pages/RepoPage/RepoPageTabs.spec.tsx rename to src/pages/RepoPage/RepoPageTabs.test.tsx index be6a30e211..d059ece6d9 100644 --- a/src/pages/RepoPage/RepoPageTabs.spec.tsx +++ b/src/pages/RepoPage/RepoPageTabs.test.tsx @@ -6,21 +6,15 @@ import { waitFor, 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 { Suspense } from 'react' import { MemoryRouter, Route } from 'react-router-dom' import { TierNames, TTierNames } from 'services/tier' -import { useFlags } from 'shared/featureFlags' import RepoPageTabs, { useRepoTabs } from './RepoPageTabs' -jest.mock('shared/featureFlags') -const mockedUseFlags = useFlags as jest.Mock<{ - componentTab?: boolean -}> - const mockRepoOverview = ({ language = '', isRepoPrivate = false, @@ -144,33 +138,24 @@ describe('RepoPageTabs', () => { componentTab = true, testAnalyticsEnabled = false, }: SetupArgs) { - mockedUseFlags.mockReturnValue({ - componentTab, - }) - server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data( - mockRepoOverview({ - language, - isRepoPrivate, - coverageEnabled, - bundleAnalysisEnabled, - testAnalyticsEnabled, - }) - ) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview({ + language, + isRepoPrivate, + coverageEnabled, + bundleAnalysisEnabled, + testAnalyticsEnabled, + }), + }) }), - graphql.query('OwnerTier', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: { plan: { tierName } } })) + + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ data: { owner: { plan: { tierName } } } }) }), - graphql.query('GetRepo', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepo({ isCurrentUserPartOfOrg })) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockRepo({ isCurrentUserPartOfOrg }) }) }) ) } @@ -460,33 +445,23 @@ describe('useRepoTabs', () => { tierName = TierNames.PRO, isCurrentUserPartOfOrg = true, }: SetupArgs) { - mockedUseFlags.mockReturnValue({ - componentTab: true, - }) - server.use( - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data( - mockRepoOverview({ - language, - isRepoPrivate, - coverageEnabled, - bundleAnalysisEnabled, - testAnalyticsEnabled, - }) - ) - ) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ + data: mockRepoOverview({ + language, + isRepoPrivate, + coverageEnabled, + bundleAnalysisEnabled, + testAnalyticsEnabled, + }), + }) }), - graphql.query('OwnerTier', (req, res, ctx) => { - return res(ctx.status(200), ctx.data({ owner: { plan: { tierName } } })) + graphql.query('OwnerTier', (info) => { + return HttpResponse.json({ data: { owner: { plan: { tierName } } } }) }), - graphql.query('GetRepo', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.data(mockRepo({ isCurrentUserPartOfOrg })) - ) + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ data: mockRepo({ isCurrentUserPartOfOrg }) }) }) ) } diff --git a/src/pages/RepoPage/context.spec.tsx b/src/pages/RepoPage/context.test.tsx similarity index 94% rename from src/pages/RepoPage/context.spec.tsx rename to src/pages/RepoPage/context.test.tsx index 97fd1fae83..dcfd702a9e 100644 --- a/src/pages/RepoPage/context.spec.tsx +++ b/src/pages/RepoPage/context.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } 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, useLayoutEffect } from 'react' import { MemoryRouter, Route, useParams } from 'react-router-dom' @@ -79,19 +79,18 @@ describe('Repo breadcrumb context', () => { const user = userEvent.setup() server.use( - graphql.query('GetRepo', (req, res, ctx) => - res( - ctx.status(200), - ctx.data({ + graphql.query('GetRepo', (info) => { + return HttpResponse.json({ + data: { owner: { repository: { private: false, isFirstPullRequest: false, }, }, - }) - ) - ) + }, + }) + }) ) return { user } diff --git a/src/pages/RepoPage/hooks/index.js b/src/pages/RepoPage/hooks/index.ts similarity index 100% rename from src/pages/RepoPage/hooks/index.js rename to src/pages/RepoPage/hooks/index.ts diff --git a/src/pages/RepoPage/hooks/pathMatchersHooks.spec.tsx b/src/pages/RepoPage/hooks/pathMatchersHooks.test.tsx similarity index 100% rename from src/pages/RepoPage/hooks/pathMatchersHooks.spec.tsx rename to src/pages/RepoPage/hooks/pathMatchersHooks.test.tsx diff --git a/src/pages/RepoPage/hooks/useJSorTSPendoTracking.spec.tsx b/src/pages/RepoPage/hooks/useJSorTSPendoTracking.test.tsx similarity index 89% rename from src/pages/RepoPage/hooks/useJSorTSPendoTracking.spec.tsx rename to src/pages/RepoPage/hooks/useJSorTSPendoTracking.test.tsx index 2c32cedc0f..9d00a18865 100644 --- a/src/pages/RepoPage/hooks/useJSorTSPendoTracking.spec.tsx +++ b/src/pages/RepoPage/hooks/useJSorTSPendoTracking.test.tsx @@ -1,8 +1,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { renderHook, screen, waitFor } 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 { Link, MemoryRouter, Route } from 'react-router-dom' import { useJSorTSPendoTracking } from './useJSorTSPendoTracking' @@ -124,28 +124,18 @@ interface SetupArgs { describe('useJSorTSPendoTracking', () => { function setup({ enablePendo = false, language = 'javascript' }: SetupArgs) { server.use( - graphql.query('CurrentUser', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockUser)) + graphql.query('CurrentUser', (info) => { + return HttpResponse.json({ data: mockUser }) }), - graphql.query('GetRepoOverview', (req, res, ctx) => { - return res(ctx.status(200), ctx.data(mockOverview(language))) + graphql.query('GetRepoOverview', (info) => { + return HttpResponse.json({ data: mockOverview(language) }) }), - graphql.query('DetailOwner', (req, res, ctx) => { - if (req.variables.username === 'second-owner') { - return res( - ctx.status(200), - ctx.data({ - owner: mockOwner2, - }) - ) + graphql.query('DetailOwner', (info) => { + if (info.variables.username === 'second-owner') { + return HttpResponse.json({ data: { owner: mockOwner2 } }) } - return res( - ctx.status(200), - ctx.data({ - owner: mockOwner1, - }) - ) + return HttpResponse.json({ data: { owner: mockOwner1 } }) }) ) diff --git a/src/pages/RepoPage/utils/paths.spec.ts b/src/pages/RepoPage/utils/paths.test.ts similarity index 100% rename from src/pages/RepoPage/utils/paths.spec.ts rename to src/pages/RepoPage/utils/paths.test.ts