Skip to content

Commit

Permalink
Add unit tests for RateSummary, add test for explainMissingData behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
haworku committed Nov 7, 2023
1 parent 580b9bc commit 26a504a
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { SingleRateSummarySection } from './SingleRateSummarySection'
import {
fetchCurrentUserMock,
mockValidCMSUser,
mockValidStateUser,
rateDataMock,
} from '../../../testHelpers/apolloMocks'
import { screen, waitFor, within } from '@testing-library/react'
import {
screen,
waitFor,
waitForElementToBeRemoved,
within,
} from '@testing-library/react'
import { packageName } from '../../../common-code/healthPlanFormDataType'
import { RateRevision } from '../../../gen/gqlClient'

describe('SingleRateSummarySection', () => {
it('can render rate details without errors', async () => {
Expand Down Expand Up @@ -126,7 +133,8 @@ describe('SingleRateSummarySection', () => {
})

// Wait for all the documents to be in the table
await waitFor(() => {
await waitFor(async () => {
await waitForElementToBeRemoved(() => screen.findByText('loading'))
expect(
screen.getByRole('link', {
name: 'Download all rate documents',
Expand Down Expand Up @@ -194,4 +202,63 @@ describe('SingleRateSummarySection', () => {
)
).toBeInTheDocument()
})

it('should not display missing field text to CMS users', () => {
const rateData = rateDataMock({
rateType: undefined,
rateDateCertified: undefined,
} as unknown as Partial<RateRevision>)
renderWithProviders(
<SingleRateSummarySection
rate={rateData}
isSubmitted={false}
statePrograms={rateData.state.programs}
/>,
{
apolloProvider: {
mocks: [
fetchCurrentUserMock({
statusCode: 200,
user: mockValidCMSUser(),
}),
],
},
}
)

expect(
screen.queryByText(/You must provide this information/)
).toBeNull()
})

it('should display missing field text to state users', async () => {
const rateData = rateDataMock(
{
rateType: undefined,
rateDateCertified: undefined,
} as unknown as Partial<RateRevision>,
{ status: 'UNLOCKED' }
)
renderWithProviders(
<SingleRateSummarySection
rate={rateData}
isSubmitted={false}
statePrograms={rateData.state.programs}
/>,
{
apolloProvider: {
mocks: [
fetchCurrentUserMock({
statusCode: 200,
user: mockValidStateUser(),
}),
],
},
}
)

expect(
await screen.findAllByText(/You must provide this information/)
).toHaveLength(2)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,8 @@ export const SingleRateSummarySection = ({
)
if (zippedURL instanceof Error) {
const msg = `ERROR: getBulkDlURL failed to generate URL for a rate. ID: ${rate?.id} Message: ${zippedURL}`
console.info(msg)

setDocumentError(true)

recordJSException(msg)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { screen, waitFor } from '@testing-library/react'
import { renderWithProviders, testS3Client } from '../../../testHelpers'
import {
fetchCurrentUserMock,
fetchRateMockSuccess,
mockValidCMSUser,
} from '../../../testHelpers/apolloMocks'
import { RateSummary } from './RateSummary'
import { RoutesRecord } from '../../../constants'
import { Route, Routes } from 'react-router-dom'

// Wrap test component in some top level routes to allow getParams to be tested
const wrapInRoutes = (children: React.ReactNode) => {
return (
<Routes>
<Route path={RoutesRecord.RATES_SUMMARY} element={children} />
</Routes>
)
}

describe('RateSummary', () => {
afterAll(() => jest.clearAllMocks())
it('renders without errors', async () => {
renderWithProviders(wrapInRoutes(<RateSummary />), {
apolloProvider: {
mocks: [
fetchCurrentUserMock({
user: mockValidCMSUser(),
statusCode: 200,
}),
fetchRateMockSuccess({ rate: { id: '7a' } }),
],
},
routerProvider: {
route: '/rates/7a',
},
})

expect(
await screen.findByText('Programs this rate certification covers')
).toBeInTheDocument()
})

it('renders document download warning banner when download fails', async () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => {
// mock expected console error to keep test output clear
})

const s3Provider = {
...testS3Client(),
getBulkDlURL: async (
keys: string[],
fileName: string
): Promise<string | Error> => {
return new Error('Error: getBulkDlURL encountered an error')
},
}
renderWithProviders(wrapInRoutes(<RateSummary />), {
apolloProvider: {
mocks: [
fetchCurrentUserMock({
user: mockValidCMSUser(),
statusCode: 200,
}),
fetchRateMockSuccess({ rate: { id: '7a' } }),
],
},
routerProvider: {
route: '/rates/7a',
},
s3Provider,
})

await waitFor(() => {
expect(screen.getByTestId('warning-alert')).toBeInTheDocument()
expect(screen.getByTestId('warning-alert')).toHaveClass(
'usa-alert--warning'
)
expect(screen.getByTestId('warning-alert')).toHaveTextContent(
'Document download unavailable'
)
expect(error).toHaveBeenCalled()
})
})

it('renders back to dashboard link for CMS users', async () => {
renderWithProviders(wrapInRoutes(<RateSummary />), {
apolloProvider: {
mocks: [
fetchCurrentUserMock({
user: mockValidCMSUser(),
statusCode: 200,
}),
fetchRateMockSuccess({ rate: { id: '7a' } }),
],
},
routerProvider: {
route: '/rates/7a',
},
})

const backLink = await screen.findByRole('link', {
name: /Back to dashboard/,
})
expect(backLink).toBeInTheDocument()

expect(backLink).toHaveAttribute('href', '/dashboard/rate-reviews')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { GridContainer, Link } from '@trussworks/react-uswds'
import React, { useEffect, useState } from 'react'
import { NavLink, useParams } from 'react-router-dom'
import sprite from 'uswds/src/img/sprite.svg'
import { Loading } from '../../components'
import { usePage } from '../../contexts/PageContext'
import { useFetchRateQuery } from '../../gen/gqlClient'
import styles from './SubmissionSummary.module.scss'
import { GenericErrorPage } from '../Errors/GenericErrorPage'
import { RoutesRecord } from '../../constants'
import { SingleRateSummarySection } from '../../components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection'
import { Loading } from '../../../components'
import { usePage } from '../../../contexts/PageContext'
import { useFetchRateQuery } from '../../../gen/gqlClient'
import styles from '../SubmissionSummary.module.scss'
import { GenericErrorPage } from '../../Errors/GenericErrorPage'
import { RoutesRecord } from '../../../constants'
import { SingleRateSummarySection } from '../../../components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection'

type RouteParams = {
id: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RateSummary } from './RateSummary'
1 change: 1 addition & 0 deletions services/app-web/src/pages/SubmissionSummary/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { SubmissionSummary } from './SubmissionSummary'
export { RateSummary } from './RateSummary'
2 changes: 2 additions & 0 deletions services/app-web/src/testHelpers/apolloMocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {

export {
fetchCurrentUserMock,
mockValidStateUser,
mockValidCMSUser,
mockValidUser,
mockValidAdminUser,
Expand All @@ -55,3 +56,4 @@ export { rateDataMock } from './rateDataMock'
export { indexRatesMockSuccess, indexRatesMockFailure } from './rateGQLMocks'

export { updateUserMockError, updateUserMockSuccess } from './updateUserMock'
export { fetchRateMockSuccess } from './rateGQLMocks'
106 changes: 57 additions & 49 deletions services/app-web/src/testHelpers/apolloMocks/rateDataMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ const contractRevisionOnRateDataMock = (
})
const rateRevisionDataMock = (data?: Partial<RateRevision>): RateRevision => {
return {
__typename: 'RateRevision',
id: uuidv4(),
id: data?.id ?? uuidv4(),
createdAt: '2023-10-16T19:01:21.389Z',
updatedAt: '2023-10-16T19:02:26.767Z',
unlockInfo: null,
Expand All @@ -90,7 +89,6 @@ const rateRevisionDataMock = (data?: Partial<RateRevision>): RateRevision => {
updatedReason: 'Initial submission',
},
formData: {
__typename: 'RateFormData',
rateType: 'AMENDMENT',
rateCapitationType: 'RATE_CELL',
rateDocuments: [
Expand Down Expand Up @@ -152,56 +150,66 @@ const rateRevisionDataMock = (data?: Partial<RateRevision>): RateRevision => {
packageStatus: 'SUBMITTED',
},
],
...data,
__typename: 'RateFormData',
},
contractRevisions: [contractRevisionOnRateDataMock()],
...data,
__typename: 'RateRevision',
}
}

const rateDataMock = (rateData?: Partial<Rate>): Rate => ({
__typename: 'Rate',
id: uuidv4(),
createdAt: '2023-10-16T19:01:21.389Z',
updatedAt: '2023-10-16T19:01:21.389Z',
stateCode: 'MN',
stateNumber: 10,
state: mockMNState(),
status: 'RESUBMITTED',
initiallySubmittedAt: '2023-10-16',
draftRevision: null,
revisions: [
rateRevisionDataMock({
unlockInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:05:26.585Z',
updatedBy: 'zuko@example.com',
updatedReason: 'Unlock',
},
submitInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:06:20.581Z',
updatedBy: 'aang@example.com',
updatedReason: 'Resubmit',
},
contractRevisions: [
contractRevisionOnRateDataMock({
submitInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:06:20.643Z',
updatedBy: 'aang@example.com',
updatedReason: 'Resubmit',
},
unlockInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:05:26.660Z',
updatedBy: 'zuko@example.com',
updatedReason: 'Unlock',
},
}),
],
}),
rateRevisionDataMock(),
],
})
const rateDataMock = (
revision?: Partial<RateRevision>,
rate?: Partial<Rate>
): Rate => {
const rateID = rate?.id ?? uuidv4()
return {
__typename: 'Rate',
createdAt: '2023-10-16T19:01:21.389Z',
updatedAt: '2023-10-16T19:01:21.389Z',
stateCode: 'MN',
stateNumber: 10,
state: mockMNState(),
status: 'RESUBMITTED',
initiallySubmittedAt: '2023-10-16',
draftRevision: null,
...rate,
id: rateID,
revisions: [
rateRevisionDataMock({
unlockInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:05:26.585Z',
updatedBy: 'zuko@example.com',
updatedReason: 'Unlock',
},
submitInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:06:20.581Z',
updatedBy: 'aang@example.com',
updatedReason: 'Resubmit',
},
contractRevisions: [
contractRevisionOnRateDataMock({
submitInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:06:20.643Z',
updatedBy: 'aang@example.com',
updatedReason: 'Resubmit',
},
unlockInfo: {
__typename: 'UpdateInformation',
updatedAt: '2023-10-16T19:05:26.660Z',
updatedBy: 'zuko@example.com',
updatedReason: 'Unlock',
},
}),
],
...revision,
}),
rateRevisionDataMock(),
],
}
}

export { rateDataMock, rateRevisionDataMock }
Loading

0 comments on commit 26a504a

Please sign in to comment.