diff --git a/src/pages/PullRequestPage/Header/Header.spec.tsx b/src/pages/PullRequestPage/Header/Header.spec.tsx new file mode 100644 index 0000000000..4feae8255e --- /dev/null +++ b/src/pages/PullRequestPage/Header/Header.spec.tsx @@ -0,0 +1,99 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { render, screen } from '@testing-library/react' +import { graphql } from 'msw' +import { setupServer } from 'msw/node' +import { MemoryRouter, Route } from 'react-router-dom' + +import { TierNames } from 'services/tier' +import { useFlags } from 'shared/featureFlags' + +import Header from './Header' + +jest.mock('./HeaderDefault', () => () => 'Default Header') +jest.mock('./HeaderTeam', () => () => 'Team Header') +jest.mock('shared/featureFlags') +const mockedUseFlags = useFlags as jest.Mock<{ multipleTiers: boolean }> + +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) +const server = setupServer() +const wrapper: React.FC = ({ children }) => ( + + + {children} + + +) + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +interface SetupArgs { + multipleTiers: boolean +} + +describe('Header', () => { + function setup({ multipleTiers = false }: SetupArgs) { + mockedUseFlags.mockReturnValue({ + multipleTiers, + }) + + server.use( + graphql.query('OwnerTier', (req, res, ctx) => { + if (multipleTiers) { + return res( + ctx.status(200), + ctx.data({ owner: { plan: { tierName: TierNames.TEAM } } }) + ) + } + return res( + ctx.status(200), + ctx.data({ owner: { plan: { tierName: TierNames.PRO } } }) + ) + }) + ) + } + + describe('when rendered and customer is not team tier', () => { + beforeEach(() => { + setup({ multipleTiers: false }) + }) + + it('renders the default header component', async () => { + render(
, { wrapper }) + + const defaultHeader = await screen.findByText(/Default Header/) + expect(defaultHeader).toBeInTheDocument() + + const teamHeader = screen.queryByText(/Team Header/) + expect(teamHeader).not.toBeInTheDocument() + }) + }) + + describe('when rendered and customer has team tier', () => { + beforeEach(() => { + setup({ multipleTiers: true }) + }) + + it('renders the team header component', async () => { + render(
, { wrapper }) + + const teamHeader = await screen.findByText(/Team Header/) + expect(teamHeader).toBeInTheDocument() + + const defaultHeader = screen.queryByText(/Default Header/) + expect(defaultHeader).not.toBeInTheDocument() + }) + }) +}) diff --git a/src/pages/PullRequestPage/Header/Header.tsx b/src/pages/PullRequestPage/Header/Header.tsx new file mode 100644 index 0000000000..c013d82ba0 --- /dev/null +++ b/src/pages/PullRequestPage/Header/Header.tsx @@ -0,0 +1,28 @@ +import { useParams } from 'react-router-dom' + +import { TierNames, useTier } from 'services/tier' +import { useFlags } from 'shared/featureFlags' + +import HeaderDefault from './HeaderDefault' +import HeaderTeam from './HeaderTeam' + +interface URLParams { + provider: string + owner: string +} + +function Header() { + const { provider, owner } = useParams() + const { data: tierData } = useTier({ provider, owner }) + const { multipleTiers } = useFlags({ + multipleTiers: false, + }) + + if (multipleTiers && tierData === TierNames.TEAM) { + return + } + + return +} + +export default Header diff --git a/src/pages/PullRequestPage/Header/Header.jsx b/src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.jsx similarity index 65% rename from src/pages/PullRequestPage/Header/Header.jsx rename to src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.jsx index fb9e6d148f..0d855b1bce 100644 --- a/src/pages/PullRequestPage/Header/Header.jsx +++ b/src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.jsx @@ -9,57 +9,53 @@ import CIStatusLabel from 'ui/CIStatus' import Icon from 'ui/Icon' import { usePullHeadData } from './hooks' -import PendoLink from './PendoLink' -const pullStateToColor = { - OPEN: 'bg-ds-primary-green', - CLOSED: 'bg-ds-primary-red', - MERGED: 'bg-ds-primary-purple', -} +import { pullStateToColor } from '../constants' +import PendoLink from '../PendoLink' -function Header() { +function HeaderDefault() { const { provider, owner, repo, pullId } = useParams() const { data } = usePullHeadData({ provider, owner, repo, pullId }) + const pull = data?.pull + return (

- {data?.pull?.title} + {pull?.title} - {capitalize(data?.pull?.state)} + {capitalize(pull?.state)}

- {data?.pull?.updatestamp && - formatTimeToNow(data?.pull?.updatestamp)}{' '} - {data?.pull?.author?.username}{' '} - authored{' '} - {data?.pull?.pullId && ( + {pull?.updatestamp && formatTimeToNow(pull?.updatestamp)}{' '} + {pull?.author?.username} authored{' '} + {pull?.pullId && ( - #{data?.pull?.pullId} + #{pull?.pullId} )} - + - {data?.pull?.head?.branchName} + {pull?.head?.branchName}

@@ -67,5 +63,4 @@ function Header() {
) } - -export default Header +export default HeaderDefault diff --git a/src/pages/PullRequestPage/Header/Header.spec.jsx b/src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.spec.jsx similarity index 96% rename from src/pages/PullRequestPage/Header/Header.spec.jsx rename to src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.spec.jsx index 68ae87ca20..9beaaf94b0 100644 --- a/src/pages/PullRequestPage/Header/Header.spec.jsx +++ b/src/pages/PullRequestPage/Header/HeaderDefault/HeaderDefault.spec.jsx @@ -4,9 +4,7 @@ import { graphql } from 'msw' import { setupServer } from 'msw/node' import { MemoryRouter, Route } from 'react-router-dom' -import Header from './Header' - -jest.mock('shared/featureFlags') +import Header from './HeaderDefault' const mockPullData = { owner: { diff --git a/src/pages/PullRequestPage/Header/hooks/index.js b/src/pages/PullRequestPage/Header/HeaderDefault/hooks/index.js similarity index 100% rename from src/pages/PullRequestPage/Header/hooks/index.js rename to src/pages/PullRequestPage/Header/HeaderDefault/hooks/index.js diff --git a/src/pages/PullRequestPage/Header/hooks/usePullHeadData.spec.tsx b/src/pages/PullRequestPage/Header/HeaderDefault/hooks/usePullHeadData.spec.tsx similarity index 100% rename from src/pages/PullRequestPage/Header/hooks/usePullHeadData.spec.tsx rename to src/pages/PullRequestPage/Header/HeaderDefault/hooks/usePullHeadData.spec.tsx diff --git a/src/pages/PullRequestPage/Header/hooks/usePullHeadData.tsx b/src/pages/PullRequestPage/Header/HeaderDefault/hooks/usePullHeadData.tsx similarity index 100% rename from src/pages/PullRequestPage/Header/hooks/usePullHeadData.tsx rename to src/pages/PullRequestPage/Header/HeaderDefault/hooks/usePullHeadData.tsx diff --git a/src/pages/PullRequestPage/Header/HeaderDefault/index.js b/src/pages/PullRequestPage/Header/HeaderDefault/index.js new file mode 100644 index 0000000000..a6b9f99db2 --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderDefault/index.js @@ -0,0 +1 @@ +export { default } from './HeaderDefault' diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.jsx b/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.jsx new file mode 100644 index 0000000000..c6675c2a2a --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.jsx @@ -0,0 +1,79 @@ +import cs from 'classnames' +import capitalize from 'lodash/capitalize' +import { useParams } from 'react-router-dom' + +import { formatTimeToNow } from 'shared/utils/dates' +import { getProviderPullURL } from 'shared/utils/provider' +import A from 'ui/A' +import CIStatusLabel from 'ui/CIStatus' +import Icon from 'ui/Icon' +import TotalsNumber from 'ui/TotalsNumber' + +import { usePullHeadDataTeam } from './hooks' + +import { pullStateToColor } from '../constants' +import PendoLink from '../PendoLink' + +function HeaderTeam() { + const { provider, owner, repo, pullId } = useParams() + const { data } = usePullHeadDataTeam({ provider, owner, repo, pullId }) + + const pull = data?.pull + + return ( +
+
+
+

+ {pull?.title} + + {capitalize(pull?.state)} + +

+

+ + {pull?.updatestamp && formatTimeToNow(pull?.updatestamp)}{' '} + {pull?.author?.username} authored{' '} + {pull?.pullId && ( + + #{pull?.pullId} + + )} + + + + + {pull?.head?.branchName} + +

+
+
+

+ Patch Coverage +

+ +
+
+ +
+ ) +} +export default HeaderTeam diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.spec.jsx b/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.spec.jsx new file mode 100644 index 0000000000..b01c6e4841 --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/HeaderTeam.spec.jsx @@ -0,0 +1,106 @@ +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 { MemoryRouter, Route } from 'react-router-dom' + +import Header from './HeaderTeam' + +const mockPullData = { + owner: { + repository: { + __typename: 'Repository', + pull: { + pullId: 1, + title: 'Cool Pull Request', + state: 'OPEN', + author: { + username: 'cool-user', + }, + head: { + branchName: 'cool-branch', + ciPassed: true, + }, + updatestamp: '2020-01-01T12:00:00.000000', + compareWithBase: { + __typename: 'Comparison', + patchTotals: { + percentCovered: 35.45, + }, + }, + }, + }, + }, +} + +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) +const server = setupServer() +const wrapper = ({ children }) => ( + + + {children} + + +) + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +describe('Header', () => { + function setup() { + server.use( + graphql.query('PullHeadDataTeam', (req, res, ctx) => + res(ctx.status(200), ctx.data(mockPullData)) + ) + ) + } + + describe('when rendered', () => { + beforeEach(() => { + setup() + }) + + it('renders the pr overview', async () => { + render(
, { wrapper }) + + await waitFor(() => queryClient.isFetching) + await waitFor(() => !queryClient.isFetching) + + const heading = await screen.findByRole('heading', { + name: /Cool Pull Request/, + }) + expect(heading).toBeInTheDocument() + + const open = await screen.findByText(/open/i) + expect(open).toBeInTheDocument() + + const prNumber = await screen.findByText(/#1/i) + expect(prNumber).toBeInTheDocument() + }) + + it('renders the patch coverage', async () => { + render(
, { wrapper }) + + await waitFor(() => queryClient.isFetching) + await waitFor(() => !queryClient.isFetching) + + const patchCoverage = await screen.findByText(/Patch Coverage/) + expect(patchCoverage).toBeInTheDocument() + + const patchCoverageValue = await screen.findByText(/35.45/) + expect(patchCoverageValue).toBeInTheDocument() + }) + }) +}) diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/hooks/index.js b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/index.js new file mode 100644 index 0000000000..144634b355 --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/index.js @@ -0,0 +1 @@ +export * from './usePullHeadDataTeam' diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.spec.tsx b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.spec.tsx new file mode 100644 index 0000000000..1c0d57b51a --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.spec.tsx @@ -0,0 +1,299 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { renderHook, waitFor } from '@testing-library/react' +import { graphql } from 'msw' +import { setupServer } from 'msw/node' + +import { usePullHeadDataTeam } from './usePullHeadDataTeam' + +const mockPullData = { + owner: { + repository: { + __typename: 'Repository', + pull: { + pullId: 1, + title: 'Cool Pull Request', + state: 'OPEN', + author: { + username: 'cool-user', + }, + head: { + branchName: 'cool-branch', + ciPassed: true, + }, + updatestamp: '', + compareWithBase: { + __typename: 'Comparison', + patchTotals: { + percentCovered: 35.45, + }, + }, + }, + }, + }, +} + +const mockNotFoundError = { + owner: { + repository: { + __typename: 'NotFoundError', + message: 'commit not found', + }, + }, +} + +const mockOwnerNotActivatedError = { + owner: { + repository: { + __typename: 'OwnerNotActivatedError', + message: 'owner not activated', + }, + }, +} + +const mockNullOwner = { + owner: null, +} + +const mockUnsuccessfulParseError = {} + +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, +}) +const server = setupServer() + +const wrapper: React.FC = ({ children }) => ( + {children} +) + +beforeAll(() => { + server.listen() +}) + +afterEach(() => { + queryClient.clear() + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) + +interface SetupArgs { + isNotFoundError?: boolean + isOwnerNotActivatedError?: boolean + isUnsuccessfulParseError?: boolean + isNullOwner?: boolean +} + +describe('usePullHeadDataTeam', () => { + function setup({ + isNotFoundError = false, + isOwnerNotActivatedError = false, + isUnsuccessfulParseError = false, + isNullOwner = false, + }: SetupArgs) { + server.use( + graphql.query('PullHeadDataTeam', (req, res, ctx) => { + if (isNotFoundError) { + return res(ctx.status(200), ctx.data(mockNotFoundError)) + } else if (isOwnerNotActivatedError) { + return res(ctx.status(200), ctx.data(mockOwnerNotActivatedError)) + } else if (isUnsuccessfulParseError) { + return res(ctx.status(200), ctx.data(mockUnsuccessfulParseError)) + } else if (isNullOwner) { + return res(ctx.status(200), ctx.data(mockNullOwner)) + } else { + return res(ctx.status(200), ctx.data(mockPullData)) + } + }) + ) + } + + describe('calling hook', () => { + describe('returns Repository __typename', () => { + describe('there is data', () => { + it('returns the correct data', async () => { + setup({}) + const { result } = renderHook( + () => + usePullHeadDataTeam({ + provider: 'gh', + owner: 'codecov', + repo: 'cool-repo', + pullId: '1', + }), + { + wrapper, + } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.data).toStrictEqual({ + pull: { + pullId: 1, + title: 'Cool Pull Request', + state: 'OPEN', + author: { + username: 'cool-user', + }, + head: { + branchName: 'cool-branch', + ciPassed: true, + }, + updatestamp: '', + compareWithBase: { + __typename: 'Comparison', + patchTotals: { + percentCovered: 35.45, + }, + }, + }, + }) + ) + }) + }) + + describe('there is a null owner', () => { + it('returns null data', async () => { + setup({ isNullOwner: true }) + const { result } = renderHook( + () => + usePullHeadDataTeam({ + provider: 'gh', + owner: 'codecov', + repo: 'cool-repo', + pullId: '1', + }), + { + wrapper, + } + ) + + await waitFor(() => result.current.isLoading) + await waitFor(() => !result.current.isLoading) + + await waitFor(() => + expect(result.current.data).toStrictEqual({ + pull: null, + }) + ) + }) + }) + }) + + describe('returns NotFoundError __typename', () => { + let oldConsoleError = console.error + + beforeEach(() => { + console.error = () => null + }) + + afterEach(() => { + console.error = oldConsoleError + }) + + it('throws a 404', async () => { + setup({ isNotFoundError: true }) + + const { result } = renderHook( + () => + usePullHeadDataTeam({ + provider: 'gh', + owner: 'codecov', + repo: 'cool-repo', + pullId: '1', + }), + { + wrapper, + } + ) + + await waitFor(() => expect(result.current.isError).toBeTruthy()) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + }) + ) + ) + }) + }) + + describe('returns OwnerNotActivatedError __typename', () => { + let oldConsoleError = console.error + + beforeEach(() => { + console.error = () => null + }) + + afterEach(() => { + console.error = oldConsoleError + }) + + it('throws a 403', async () => { + setup({ isOwnerNotActivatedError: true }) + const { result } = renderHook( + () => + usePullHeadDataTeam({ + provider: 'gh', + owner: 'codecov', + repo: 'cool-repo', + pullId: '1', + }), + { + wrapper, + } + ) + + await waitFor(() => expect(result.current.isError).toBeTruthy()) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 403, + }) + ) + ) + }) + }) + + 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( + () => + usePullHeadDataTeam({ + provider: 'gh', + owner: 'codecov', + repo: 'cool-repo', + pullId: '1', + }), + { + wrapper, + } + ) + + await waitFor(() => expect(result.current.isError).toBeTruthy()) + await waitFor(() => + expect(result.current.error).toEqual( + expect.objectContaining({ + status: 404, + }) + ) + ) + }) + }) + }) +}) diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.tsx b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.tsx new file mode 100644 index 0000000000..eed39917b3 --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/hooks/usePullHeadDataTeam.tsx @@ -0,0 +1,200 @@ +import { useQuery } from '@tanstack/react-query' +import { z } from 'zod' + +import { + FirstPullRequestSchema, + MissingBaseCommitSchema, + MissingBaseReportSchema, + MissingComparisonSchema, + MissingHeadCommitSchema, + MissingHeadReportSchema, +} from 'services/comparison/schemas' +import { + RepoNotFoundErrorSchema, + RepoOwnerNotActivatedErrorSchema, +} from 'services/repo' +import Api from 'shared/api' +import A from 'ui/A' + +const CoverageObjSchema = z.object({ + percentCovered: z.number().nullable(), +}) + +const ComparisonSchema = z.object({ + __typename: z.literal('Comparison'), + patchTotals: CoverageObjSchema.nullable(), +}) + +const CompareWithBaseSchema = z.discriminatedUnion('__typename', [ + ComparisonSchema, + FirstPullRequestSchema, + MissingBaseCommitSchema, + MissingBaseReportSchema, + MissingComparisonSchema, + MissingHeadCommitSchema, + MissingHeadReportSchema, +]) + +const RepositorySchema = z.object({ + __typename: z.literal('Repository'), + pull: z + .object({ + pullId: z.number().nullable(), + title: z.string().nullable(), + state: z + .union([z.literal('OPEN'), z.literal('CLOSED'), z.literal('MERGED')]) + .nullable(), + author: z + .object({ + username: z.string().nullable(), + }) + .nullable(), + head: z + .object({ + branchName: z.string().nullable(), + ciPassed: z.boolean().nullable(), + }) + .nullable(), + updatestamp: z.string().nullable(), + compareWithBase: CompareWithBaseSchema.nullable(), + }) + .nullable(), +}) + +const PullHeadDataSchema = z.object({ + owner: z + .object({ + repository: z + .discriminatedUnion('__typename', [ + RepositorySchema, + RepoNotFoundErrorSchema, + RepoOwnerNotActivatedErrorSchema, + ]) + .nullable(), + }) + .nullable(), +}) + +const query = ` + query PullHeadDataTeam($owner: String!, $repo: String!, $pullId: Int!) { + owner(username: $owner) { + repository(name: $repo) { + __typename + ... on Repository { + pull(id: $pullId) { + pullId + title + state + author { + username + } + head { + branchName + ciPassed + } + updatestamp + compareWithBase { + __typename + ... on Comparison { + patchTotals { + percentCovered + } + } + ... on FirstPullRequest { + message + } + ... on MissingBaseCommit { + message + } + ... on MissingHeadCommit { + message + } + ... on MissingComparison { + message + } + ... on MissingBaseReport { + message + } + ... on MissingHeadReport { + message + } + } + } + } + ... on NotFoundError { + message + } + ... on OwnerNotActivatedError { + message + } + } + } + } +` + +interface UsePullHeadDataTeamArgs { + provider: string + owner: string + repo: string + pullId: string +} + +export const usePullHeadDataTeam = ({ + provider, + owner, + repo, + pullId, +}: UsePullHeadDataTeamArgs) => + useQuery({ + queryKey: ['PullHeaderTeam', provider, owner, repo, pullId, query], + queryFn: ({ signal }) => + Api.graphql({ + provider, + query, + signal, + variables: { + provider, + owner, + repo, + pullId: parseInt(pullId, 10), + }, + }).then((res) => { + const parsedData = PullHeadDataSchema.safeParse(res?.data) + + if (!parsedData.success) { + return Promise.reject({ + status: 404, + data: {}, + }) + } + + const data = parsedData.data + + if (data?.owner?.repository?.__typename === 'NotFoundError') { + return Promise.reject({ + status: 404, + data: {}, + }) + } + + if (data?.owner?.repository?.__typename === 'OwnerNotActivatedError') { + return Promise.reject({ + status: 403, + data: { + detail: ( +

+ Activation is required to view this repo, please{' '} + {/* @ts-expect-error */} + click here to activate + your account. +

+ ), + }, + }) + } + + return { + pull: data?.owner?.repository?.pull ?? null, + } + }), + }) diff --git a/src/pages/PullRequestPage/Header/HeaderTeam/index.js b/src/pages/PullRequestPage/Header/HeaderTeam/index.js new file mode 100644 index 0000000000..7dbc94a63d --- /dev/null +++ b/src/pages/PullRequestPage/Header/HeaderTeam/index.js @@ -0,0 +1 @@ +export { default } from './HeaderTeam' diff --git a/src/pages/PullRequestPage/Header/PendoLink.spec.tsx b/src/pages/PullRequestPage/Header/PendoLink/PendoLink.spec.tsx similarity index 100% rename from src/pages/PullRequestPage/Header/PendoLink.spec.tsx rename to src/pages/PullRequestPage/Header/PendoLink/PendoLink.spec.tsx diff --git a/src/pages/PullRequestPage/Header/PendoLink.tsx b/src/pages/PullRequestPage/Header/PendoLink/PendoLink.tsx similarity index 100% rename from src/pages/PullRequestPage/Header/PendoLink.tsx rename to src/pages/PullRequestPage/Header/PendoLink/PendoLink.tsx diff --git a/src/pages/PullRequestPage/Header/PendoLink/index.js b/src/pages/PullRequestPage/Header/PendoLink/index.js new file mode 100644 index 0000000000..ad5ec74121 --- /dev/null +++ b/src/pages/PullRequestPage/Header/PendoLink/index.js @@ -0,0 +1 @@ +export { default } from './PendoLink' diff --git a/src/pages/PullRequestPage/Header/constants.ts b/src/pages/PullRequestPage/Header/constants.ts new file mode 100644 index 0000000000..decc047a32 --- /dev/null +++ b/src/pages/PullRequestPage/Header/constants.ts @@ -0,0 +1,5 @@ +export const pullStateToColor = { + OPEN: 'bg-ds-primary-green', + CLOSED: 'bg-ds-primary-red', + MERGED: 'bg-ds-primary-purple', +} as const diff --git a/src/pages/PullRequestPage/PullRequestPage.spec.jsx b/src/pages/PullRequestPage/PullRequestPage.spec.jsx index 314bb30cf4..dc9e8bb1db 100644 --- a/src/pages/PullRequestPage/PullRequestPage.spec.jsx +++ b/src/pages/PullRequestPage/PullRequestPage.spec.jsx @@ -9,6 +9,7 @@ import PullRequestPage from './PullRequestPage' jest.mock('shared/featureFlags') +jest.mock('./Header', () => () => 'Header') jest.mock('./Summary', () => () => 'CompareSummary') jest.mock('./PullRequestPageContent', () => () => 'PullRequestPageContent') jest.mock('./PullRequestPageTabs', () => () => 'PullRequestPageTabs') @@ -124,10 +125,8 @@ describe('PullRequestPage', () => { it('renders header', async () => { render(, { wrapper: wrapper() }) - const title = await screen.findByRole('heading', { - name: /Cool New Pull Request/, - }) - expect(title).toBeInTheDocument() + const header = await screen.findByText(/Header/) + expect(header).toBeInTheDocument() }) it('renders compare summary', async () => {