From bd7d9b2142f2ddc94919657dea34ba1d574c05cb Mon Sep 17 00:00:00 2001
From: Jason Lin <98117700+JasonLin0991@users.noreply.github.com>
Date: Wed, 18 Oct 2023 16:40:47 -0400
Subject: [PATCH 1/7] Rate dashboard, rate table, and rate summary tests
(#1987)
* Copy contractsWithSharedRateRevision when unlocking rate.
* Remove duplicate mock function.
* Add test for SingleRateSummarySection and rate data mock.
* Remove hard coded ids.
* Add mock rate GQL requests.
* Add RateReviewDashboard tests.
* Put it back because backend API uses this file.
* Add rate table tests and move file location.
* Add another test.
* Fix jest warnings.
---
.../ProgramSelect/ProgramSelect.test.tsx | 6 +-
.../RateDetailsSummarySection.test.tsx | 182 +++++++++++----
.../SingleRateSummarySection.test.tsx | 197 +++++++++++++++++
.../RateReviewsDashboard.test.tsx | 58 +++++
.../RateReviewsDashboard.tsx | 2 +-
.../RateReviewsTable.test.tsx | 125 +++++++++++
.../RateReviewsTable.tsx | 10 +-
.../src/testHelpers/apolloMocks/index.ts | 4 +
.../testHelpers/apolloMocks/rateDataMock.ts | 207 ++++++++++++++++++
.../testHelpers/apolloMocks/rateGQLMocks.ts | 51 +++++
10 files changed, 789 insertions(+), 53 deletions(-)
create mode 100644 services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx
create mode 100644 services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.test.tsx
create mode 100644 services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.test.tsx
rename services/app-web/src/pages/CMSDashboard/{ => RateReviewsDashboard}/RateReviewsTable.tsx (98%)
create mode 100644 services/app-web/src/testHelpers/apolloMocks/rateDataMock.ts
create mode 100644 services/app-web/src/testHelpers/apolloMocks/rateGQLMocks.ts
diff --git a/services/app-web/src/components/Select/ProgramSelect/ProgramSelect.test.tsx b/services/app-web/src/components/Select/ProgramSelect/ProgramSelect.test.tsx
index 7ee3e52d72..d74633c368 100644
--- a/services/app-web/src/components/Select/ProgramSelect/ProgramSelect.test.tsx
+++ b/services/app-web/src/components/Select/ProgramSelect/ProgramSelect.test.tsx
@@ -1,11 +1,13 @@
import { renderWithProviders } from '../../../testHelpers/jestHelpers'
import { ProgramSelect } from './ProgramSelect'
-import { fetchCurrentUserMock } from '../../../testHelpers/apolloMocks'
+import {
+ fetchCurrentUserMock,
+ mockMNState,
+} from '../../../testHelpers/apolloMocks'
import { screen, waitFor } from '@testing-library/react'
import selectEvent from 'react-select-event'
import userEvent from '@testing-library/user-event'
import * as useStatePrograms from '../../../hooks/useStatePrograms'
-import { mockMNState } from '../../../common-code/healthPlanFormDataMocks/healthPlanFormData'
const mockOnChange = jest.fn()
const mockSetValue = jest.fn()
diff --git a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/RateDetailsSummarySection.test.tsx b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/RateDetailsSummarySection.test.tsx
index 9483824f33..a0474913b7 100644
--- a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/RateDetailsSummarySection.test.tsx
+++ b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/RateDetailsSummarySection.test.tsx
@@ -3,6 +3,9 @@ import {
mockContractAndRatesDraft,
mockStateSubmission,
mockMNState,
+ fetchCurrentUserMock,
+ mockValidCMSUser,
+ indexHealthPlanPackagesMockSuccess,
} from '../../../testHelpers/apolloMocks'
import { renderWithProviders } from '../../../testHelpers/jestHelpers'
import * as usePreviousSubmission from '../../../hooks/usePreviousSubmission'
@@ -77,6 +80,16 @@ describe('RateDetailsSummarySection', () => {
},
]
+ const apolloProvider = {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ indexHealthPlanPackagesMockSuccess(),
+ ],
+ }
+
afterEach(() => jest.clearAllMocks())
it('can render draft submission without errors', () => {
@@ -87,7 +100,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
@@ -108,7 +124,10 @@ describe('RateDetailsSummarySection', () => {
submission={stateSubmission}
submissionName="MN-MSHO-0003"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
@@ -141,7 +160,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
screen.getByRole('definition', { name: 'Rate certification type' })
@@ -168,21 +190,28 @@ describe('RateDetailsSummarySection', () => {
).toBeInTheDocument()
})
- it('can render correct rate name for new rate submission', () => {
+ it('can render correct rate name for new rate submission', async () => {
const submission = mockStateSubmission()
submission.rateInfos[0].rateCertificationName =
'MCR-MN-0005-SNBC-RATE-20221013-20221013-CERTIFICATION-20221013'
const statePrograms = mockMNState().programs
- renderWithProviders(
-
- )
+ await waitFor(() => {
+ renderWithProviders(
+ ,
+ {
+ apolloProvider,
+ }
+ )
+ })
const rateName =
'MCR-MN-0005-SNBC-RATE-20221013-20221013-CERTIFICATION-20221013'
expect(screen.getByText(rateName)).toBeInTheDocument()
@@ -212,7 +241,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
const rateName =
@@ -221,18 +253,26 @@ describe('RateDetailsSummarySection', () => {
expect(screen.getByText(rateName)).toBeInTheDocument()
})
- it('can render all rate details fields for new rate certification submission', () => {
+ it('can render all rate details fields for new rate certification submission', async () => {
const statePrograms = mockMNState().programs
stateSubmission.rateInfos[0].rateCertificationName =
'MCR-MN-0005-SNBC-RATE-20221014-20221014-CERTIFICATION-20221014'
- renderWithProviders(
-
- )
+
+ await waitFor(() => {
+ renderWithProviders(
+ ,
+ {
+ apolloProvider,
+ }
+ )
+ })
const rateName =
'MCR-MN-0005-SNBC-RATE-20221014-20221014-CERTIFICATION-20221014'
@@ -289,6 +329,7 @@ describe('RateDetailsSummarySection', () => {
},
],
}
+
renderWithProviders(
{
navigateTo="/rate-details'"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
@@ -346,7 +390,10 @@ describe('RateDetailsSummarySection', () => {
submission={draftSubmission}
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
@@ -356,15 +403,23 @@ describe('RateDetailsSummarySection', () => {
).toBeNull()
})
- it('does not render download all button when on previous submission', () => {
- renderWithProviders(
-
+ it('does not render download all button when on previous submission', async () => {
+ await waitFor(() =>
+ renderWithProviders(
+ ,
+ {
+ apolloProvider,
+ }
+ )
)
+
expect(
screen.queryByRole('button', {
name: 'Download all rate documents',
@@ -380,7 +435,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
screen.getByRole('definition', {
@@ -404,7 +462,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(
screen.getByRole('definition', {
@@ -431,7 +492,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
const programElement = screen.getByRole('definition', {
name: 'Programs this rate certification covers',
@@ -455,7 +519,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
const programElement = screen.getByRole('definition', {
name: 'Programs this rate certification covers',
@@ -475,7 +542,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
const programList = screen.getAllByRole('definition', {
name: 'Programs this rate certification covers',
@@ -495,7 +565,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
const certType = screen.getAllByRole('definition', {
name: 'Rate certification type',
@@ -515,7 +588,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
const rateDocsTables = screen.getAllByRole('table', {
@@ -545,7 +621,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
const certifyingActuary = screen.getAllByRole('definition', {
@@ -621,7 +700,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
const rateDocsTable = screen.getByRole('table', {
@@ -722,7 +804,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
const rateDocsTable = screen.getByRole('table', {
@@ -789,7 +874,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
await waitFor(() => {
const rateDocsTable = screen.getByRole('table', {
@@ -812,7 +900,10 @@ describe('RateDetailsSummarySection', () => {
navigateTo="rate-details"
submissionName="MN-PMAP-0001"
statePrograms={statePrograms}
- />
+ />,
+ {
+ apolloProvider,
+ }
)
expect(screen.queryByRole('link', { name: 'Edit' })).toBeNull()
@@ -841,6 +932,7 @@ describe('RateDetailsSummarySection', () => {
/>,
{
s3Provider,
+ apolloProvider,
}
)
diff --git a/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx
new file mode 100644
index 0000000000..d71a7b1e54
--- /dev/null
+++ b/services/app-web/src/components/SubmissionSummarySection/RateDetailsSummarySection/SingleRateSummarySection.test.tsx
@@ -0,0 +1,197 @@
+import { renderWithProviders } from '../../../testHelpers/jestHelpers'
+import { SingleRateSummarySection } from './SingleRateSummarySection'
+import {
+ fetchCurrentUserMock,
+ mockValidCMSUser,
+ rateDataMock,
+} from '../../../testHelpers/apolloMocks'
+import { screen, waitFor, within } from '@testing-library/react'
+import { packageName } from '../../../common-code/healthPlanFormDataType'
+
+describe('SingleRateSummarySection', () => {
+ it('can render rate details without errors', async () => {
+ const rateData = rateDataMock()
+ await waitFor(() => {
+ renderWithProviders(
+ ,
+ {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ ],
+ },
+ }
+ )
+ })
+
+ const rateName = rateData.revisions[0].formData
+ .rateCertificationName as string
+
+ expect(screen.getByText(rateName)).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Programs this rate certification covers',
+ })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', { name: 'Rate certification type' })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Rating period of original rate certification',
+ })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Date certified for rate amendment',
+ })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Rate amendment effective dates',
+ })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', { name: 'Certifying actuary' })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Does the actuary certify capitation rates specific to each rate cell or a rate range?',
+ })
+ ).toBeInTheDocument()
+ expect(
+ screen.getByRole('definition', {
+ name: 'Submission this rate was submitted with',
+ })
+ ).toBeInTheDocument()
+
+ expect(
+ screen.getByRole('heading', { name: 'Rate documents' })
+ ).toBeInTheDocument()
+ })
+ it('renders documents with linked submissions correctly', async () => {
+ const rateData = rateDataMock()
+ const parentContractRev = rateData.revisions[0].contractRevisions[0]
+ const rateDoc = rateData.revisions[0].formData.rateDocuments[0]
+ const supportingDoc =
+ rateData.revisions[0].formData.supportingDocuments[0]
+ const linkedSubmissionOne =
+ rateData.revisions[0].formData.packagesWithSharedRateCerts[0]
+ const linkedSubmissionTwo =
+ rateData.revisions[0].formData.packagesWithSharedRateCerts[1]
+
+ const contractPackageName = packageName(
+ parentContractRev.contract.stateCode,
+ parentContractRev.contract.stateNumber,
+ parentContractRev.formData.programIDs,
+ rateData.state.programs
+ )
+
+ await waitFor(() => {
+ renderWithProviders(
+ ,
+ {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ ],
+ },
+ }
+ )
+ })
+
+ expect(
+ screen.getByRole('heading', { name: 'Rate documents' })
+ ).toBeInTheDocument()
+
+ const rateDocsTable = screen.getByRole('table', {
+ name: /Rate certification/,
+ })
+ const supportingDocsTable = screen.getByRole('table', {
+ name: /Rate supporting documents/,
+ })
+
+ // Wait for all the documents to be in the table
+ await waitFor(() => {
+ expect(
+ screen.getByRole('link', {
+ name: 'Download all rate documents',
+ })
+ ).toBeInTheDocument()
+ expect(rateDocsTable).toBeInTheDocument()
+ expect(supportingDocsTable).toBeInTheDocument()
+ })
+
+ const parentContractSubmission = screen.getByRole('definition', {
+ name: 'Submission this rate was submitted with',
+ })
+
+ // Expect submissions this rate was submitted with link to exists
+ expect(parentContractSubmission).toBeInTheDocument()
+ expect(
+ within(parentContractSubmission).getByRole('link', {
+ name: contractPackageName,
+ })
+ ).toBeInTheDocument()
+ expect(
+ within(parentContractSubmission).getByRole('link', {
+ name: contractPackageName,
+ })
+ ).toHaveAttribute(
+ 'href',
+ `/submissions/${parentContractRev.contract.id}`
+ )
+
+ // Expect rate certification document and linked submissions
+ expect(
+ within(rateDocsTable).getByText(rateDoc.name)
+ ).toBeInTheDocument()
+ expect(
+ within(within(rateDocsTable).getByTestId('tag')).getByText('SHARED')
+ ).toBeInTheDocument()
+ expect(
+ within(rateDocsTable).getByText(
+ `${linkedSubmissionOne.packageName} (Draft)`
+ )
+ ).toBeInTheDocument()
+ expect(
+ within(rateDocsTable).getByText(
+ `${linkedSubmissionTwo.packageName}`
+ )
+ ).toBeInTheDocument()
+
+ // Expect supporting document and linked submissions
+ expect(
+ within(supportingDocsTable).getByText(supportingDoc.name)
+ ).toBeInTheDocument()
+ expect(
+ within(within(supportingDocsTable).getByTestId('tag')).getByText(
+ 'SHARED'
+ )
+ ).toBeInTheDocument()
+ expect(
+ within(supportingDocsTable).getByText(
+ `${linkedSubmissionOne.packageName} (Draft)`
+ )
+ ).toBeInTheDocument()
+ expect(
+ within(supportingDocsTable).getByText(
+ `${linkedSubmissionTwo.packageName}`
+ )
+ ).toBeInTheDocument()
+ })
+})
diff --git a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.test.tsx b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.test.tsx
new file mode 100644
index 0000000000..f4ca865618
--- /dev/null
+++ b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.test.tsx
@@ -0,0 +1,58 @@
+import { ldUseClientSpy, renderWithProviders } from '../../../testHelpers'
+import { RateReviewsDashboard } from './RateReviewsDashboard'
+import {
+ fetchCurrentUserMock,
+ indexRatesMockFailure,
+ mockValidCMSUser,
+} from '../../../testHelpers/apolloMocks'
+import { indexRatesMockSuccess } from '../../../testHelpers/apolloMocks'
+import { screen, waitFor } from '@testing-library/react'
+
+describe('RateReviewsDashboard', () => {
+ it('renders dashboard with rates correctly', async () => {
+ ldUseClientSpy({
+ 'rate-reviews-dashboard': true,
+ 'rate-filters': true,
+ })
+ renderWithProviders(, {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ indexRatesMockSuccess(),
+ ],
+ },
+ })
+
+ // Wait for accordion and table components to load on page
+ await waitFor(() => {
+ expect(screen.queryByTestId('accordion')).toBeInTheDocument()
+ expect(screen.queryByTestId('table')).toBeInTheDocument()
+ })
+
+ // Expect 3 rates to be displayed
+ expect(screen.getByText('Displaying 3 of 3 rates')).toBeInTheDocument()
+ })
+
+ it('renders error failed request page', async () => {
+ renderWithProviders(, {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ indexRatesMockFailure(),
+ ],
+ },
+ })
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText("We're having trouble loading this page.")
+ ).toBeInTheDocument()
+ })
+ })
+})
diff --git a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.tsx b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.tsx
index 2172acb3d7..2fb0028afe 100644
--- a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.tsx
+++ b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsDashboard.tsx
@@ -6,7 +6,7 @@ import styles from '../../StateDashboard/StateDashboard.module.scss'
import { recordJSException } from '../../../otelHelpers/tracingHelper'
import { Loading } from '../../../components'
-import { RateInDashboardType, RateReviewsTable } from '../RateReviewsTable'
+import { RateInDashboardType, RateReviewsTable } from './RateReviewsTable'
import { useLDClient } from 'launchdarkly-react-client-sdk'
import { featureFlags } from '../../../common-code/featureFlags'
import { ErrorFailedRequestPage } from '../../Errors/ErrorFailedRequestPage'
diff --git a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.test.tsx b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.test.tsx
new file mode 100644
index 0000000000..82a3044563
--- /dev/null
+++ b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.test.tsx
@@ -0,0 +1,125 @@
+import { renderWithProviders } from '../../../testHelpers'
+import { RateInDashboardType } from './RateReviewsTable'
+import {
+ fetchCurrentUserMock,
+ mockMNState,
+ mockValidCMSUser,
+} from '../../../testHelpers/apolloMocks'
+import { RateReviewsTable } from './RateReviewsTable'
+import { waitFor, screen, within } from '@testing-library/react'
+
+describe('RateReviewsTable', () => {
+ const statePrograms = mockMNState().programs
+ const tableData = (): RateInDashboardType[] => [
+ {
+ id: 'rate-1-id',
+ name: 'rate-1-certification-name',
+ programs: [statePrograms[0]],
+ submittedAt: '2023-10-16',
+ rateDateStart: new Date('2023-10-16'),
+ rateDateEnd: new Date('2024-10-16'),
+ status: 'SUBMITTED',
+ updatedAt: new Date('2023-10-16'),
+ rateType: 'NEW',
+ stateName: 'Minnesota',
+ contractRevisions: [],
+ },
+ {
+ id: 'rate-2-id',
+ name: 'rate-2-certification-name',
+ programs: [statePrograms[0]],
+ submittedAt: '2023-11-18',
+ rateDateStart: new Date('2023-11-18'),
+ rateDateEnd: new Date('2024-11-18'),
+ status: 'SUBMITTED',
+ updatedAt: new Date('2023-11-18'),
+ rateType: 'AMENDMENT',
+ stateName: 'Minnesota',
+ contractRevisions: [],
+ },
+ {
+ id: 'rate-3-id',
+ name: 'rate-3-certification-name',
+ programs: [statePrograms[0]],
+ submittedAt: '2023-12-01',
+ rateDateStart: new Date('2023-12-01'),
+ rateDateEnd: new Date('2024-12-01'),
+ status: 'UNLOCKED',
+ updatedAt: new Date('2023-12-01'),
+ rateType: 'NEW',
+ stateName: 'Minnesota',
+ contractRevisions: [],
+ },
+ ]
+ it('renders rates table correctly', async () => {
+ renderWithProviders(
+ ,
+ {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ ],
+ },
+ }
+ )
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText('Displaying 3 of 3 rates')
+ ).toBeInTheDocument()
+ })
+ // expect filter accordion to be present
+ expect(screen.getByTestId('accordion')).toBeInTheDocument()
+ expect(screen.getByText('0 filters applied')).toBeInTheDocument()
+
+ // expect table caption
+ expect(screen.getByText('Test table caption')).toBeInTheDocument()
+
+ const tableRows = screen.getAllByRole('row')
+
+ // expect there to be 4 rows, one of which is the header row
+ expect(tableRows).toHaveLength(4)
+
+ // expect rows to be in order where latest updatedAt is first in the array
+ expect(
+ within(tableRows[1]).getByText('rate-3-certification-name')
+ ).toBeInTheDocument()
+ expect(
+ within(tableRows[2]).getByText('rate-2-certification-name')
+ ).toBeInTheDocument()
+ expect(
+ within(tableRows[3]).getByText('rate-1-certification-name')
+ ).toBeInTheDocument()
+ })
+ it('renders rates table correctly without filters, captions and no rates', async () => {
+ renderWithProviders(, {
+ apolloProvider: {
+ mocks: [
+ fetchCurrentUserMock({
+ statusCode: 200,
+ user: mockValidCMSUser(),
+ }),
+ ],
+ },
+ })
+
+ // expect no filter accordion to be present
+ expect(screen.queryByTestId('accordion')).not.toBeInTheDocument()
+ expect(screen.queryByText('0 filters applied')).not.toBeInTheDocument()
+
+ // expect no table
+ expect(screen.queryByRole('table')).not.toBeInTheDocument()
+
+ // expect now rate review text
+ expect(
+ screen.getByText('You have no rate reviews yet')
+ ).toBeInTheDocument()
+ })
+})
diff --git a/services/app-web/src/pages/CMSDashboard/RateReviewsTable.tsx b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
similarity index 98%
rename from services/app-web/src/pages/CMSDashboard/RateReviewsTable.tsx
rename to services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
index 3546b1092b..a4d403b2ab 100644
--- a/services/app-web/src/pages/CMSDashboard/RateReviewsTable.tsx
+++ b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
@@ -18,8 +18,8 @@ import {
Program,
RelatedContractRevisions,
RateType,
-} from '../../gen/gqlClient'
-import styles from '../../components/HealthPlanPackageTable/HealthPlanPackageTable.module.scss'
+} from '../../../gen/gqlClient'
+import styles from '../../../components/HealthPlanPackageTable/HealthPlanPackageTable.module.scss'
import { Table, Tag, Link } from '@trussworks/react-uswds'
import { NavLink } from 'react-router-dom'
import dayjs from 'dayjs'
@@ -29,9 +29,9 @@ import {
FilterSelect,
FilterSelectedOptionsType,
FilterOptionType,
-} from '../../components/FilterAccordion'
-import { pluralize } from '../../common-code/formatters'
-import { RateTypeRecord } from '../../constants/healthPlanPackages'
+} from '../../../components/FilterAccordion'
+import { pluralize } from '../../../common-code/formatters'
+import { RateTypeRecord } from '../../../constants/healthPlanPackages'
declare module '@tanstack/table-core' {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/services/app-web/src/testHelpers/apolloMocks/index.ts b/services/app-web/src/testHelpers/apolloMocks/index.ts
index 5569815c41..c0d3439027 100644
--- a/services/app-web/src/testHelpers/apolloMocks/index.ts
+++ b/services/app-web/src/testHelpers/apolloMocks/index.ts
@@ -50,4 +50,8 @@ export { mockQuestionsPayload } from './questionResponseDataMocks'
export { fetchEmailSettings } from './emailGQLMock'
export { mockMNState } from './stateMock'
+export { rateDataMock } from './rateDataMock'
+
+export { indexRatesMockSuccess, indexRatesMockFailure } from './rateGQLMocks'
+
export { updateUserMockError, updateUserMockSuccess } from './updateUserMock'
diff --git a/services/app-web/src/testHelpers/apolloMocks/rateDataMock.ts b/services/app-web/src/testHelpers/apolloMocks/rateDataMock.ts
new file mode 100644
index 0000000000..75fc6b5065
--- /dev/null
+++ b/services/app-web/src/testHelpers/apolloMocks/rateDataMock.ts
@@ -0,0 +1,207 @@
+import {
+ Rate,
+ RateRevision,
+ RelatedContractRevisions,
+} from '../../gen/gqlClient'
+import { mockMNState } from './stateMock'
+import { v4 as uuidv4 } from 'uuid'
+
+const contractRevisionOnRateDataMock = (
+ data?: Partial
+): RelatedContractRevisions => ({
+ __typename: 'RelatedContractRevisions',
+ id: uuidv4(),
+ contract: {
+ __typename: 'ContractOnRevisionType',
+ id: uuidv4(),
+ stateCode: 'MN',
+ stateNumber: 3,
+ },
+ createdAt: '2023-10-16T18:52:16.295Z',
+ updatedAt: '2023-10-16T19:02:26.795Z',
+ submitInfo: {
+ __typename: 'UpdateInformation',
+ updatedAt: '2023-10-16T19:02:26.795Z',
+ updatedBy: 'aang@example.com',
+ updatedReason: 'Initial submission',
+ },
+ unlockInfo: null,
+ formData: {
+ __typename: 'ContractFormData',
+ programIDs: ['d95394e5-44d1-45df-8151-1cc1ee66f100'],
+ populationCovered: 'MEDICAID',
+ submissionType: 'CONTRACT_AND_RATES',
+ riskBasedContract: false,
+ submissionDescription: 'description of contract and rates submission',
+ stateContacts: [
+ {
+ __typename: 'StateContact',
+ name: 'Name',
+ title: null,
+ email: 'example@example.com',
+ },
+ ],
+ supportingDocuments: [],
+ contractType: 'BASE',
+ contractExecutionStatus: 'EXECUTED',
+ contractDocuments: [
+ {
+ __typename: 'GenericDocument',
+ name: 'contract-document.pdf',
+ s3URL: 's3://bucketname/key/contract-document',
+ sha256: 'fakeSha',
+ },
+ ],
+ contractDateStart: '2024-04-01',
+ contractDateEnd: '2025-03-31',
+ managedCareEntities: ['MCO'],
+ federalAuthorities: ['STATE_PLAN'],
+ inLieuServicesAndSettings: false,
+ modifiedBenefitsProvided: null,
+ modifiedGeoAreaServed: null,
+ modifiedMedicaidBeneficiaries: null,
+ modifiedRiskSharingStrategy: true,
+ modifiedIncentiveArrangements: true,
+ modifiedWitholdAgreements: false,
+ modifiedStateDirectedPayments: false,
+ modifiedPassThroughPayments: false,
+ modifiedPaymentsForMentalDiseaseInstitutions: true,
+ modifiedMedicalLossRatioStandards: null,
+ modifiedOtherFinancialPaymentIncentive: null,
+ modifiedEnrollmentProcess: null,
+ modifiedGrevienceAndAppeal: null,
+ modifiedNetworkAdequacyStandards: null,
+ modifiedLengthOfContract: null,
+ modifiedNonRiskPaymentArrangements: true,
+ },
+ ...data,
+})
+const rateRevisionDataMock = (data?: Partial): RateRevision => {
+ return {
+ __typename: 'RateRevision',
+ id: uuidv4(),
+ createdAt: '2023-10-16T19:01:21.389Z',
+ updatedAt: '2023-10-16T19:02:26.767Z',
+ unlockInfo: null,
+ submitInfo: {
+ __typename: 'UpdateInformation',
+ updatedAt: '2023-10-16T19:02:26.766Z',
+ updatedBy: 'aang@example.com',
+ updatedReason: 'Initial submission',
+ },
+ formData: {
+ __typename: 'RateFormData',
+ rateType: 'AMENDMENT',
+ rateCapitationType: 'RATE_CELL',
+ rateDocuments: [
+ {
+ __typename: 'GenericDocument',
+ name: 'rate-document.pdf',
+ s3URL: 's3://bucketname/key/rate-document',
+ sha256: 'fakeSha',
+ },
+ ],
+ supportingDocuments: [
+ {
+ __typename: 'GenericDocument',
+ name: 'rate-supporting-document.pdf',
+ s3URL: 's3://bucketname/key/rate-supporting-document',
+ sha256: 'fakeSha',
+ },
+ ],
+ rateDateStart: '2023-02-01',
+ rateDateEnd: '2025-03-01',
+ rateDateCertified: '2024-03-01',
+ amendmentEffectiveDateStart: '2024-03-01',
+ amendmentEffectiveDateEnd: '2025-03-01',
+ rateProgramIDs: ['d95394e5-44d1-45df-8151-1cc1ee66f100'],
+ rateCertificationName:
+ 'MCR-MN-0003-PMAP-RATE-20240301-20250301-AMENDMENT-20240301',
+ certifyingActuaryContacts: [
+ {
+ __typename: 'ActuaryContact',
+ name: 'Actuary Contact Person',
+ titleRole: 'Actuary Contact Title',
+ email: 'actuarycontact@example.com',
+ actuarialFirm: 'MERCER',
+ actuarialFirmOther: '',
+ },
+ ],
+ addtlActuaryContacts: [
+ {
+ __typename: 'ActuaryContact',
+ name: 'Additional actuary name',
+ titleRole: 'Additional actuary title',
+ email: 'additonalactuary@example.com',
+ actuarialFirm: 'MILLIMAN',
+ actuarialFirmOther: '',
+ },
+ ],
+ actuaryCommunicationPreference: 'OACT_TO_ACTUARY',
+ packagesWithSharedRateCerts: [
+ {
+ __typename: 'PackageWithSameRate',
+ packageName: 'MCR-MN-0001-PMAP',
+ packageId: 'f3306599-a1c9-411a-87ac-fa3541c3e723',
+ packageStatus: 'DRAFT',
+ },
+ {
+ __typename: 'PackageWithSameRate',
+ packageName: 'MCR-MN-0002-PMAP',
+ packageId: '1bf66cff-512b-4a30-bea8-5e27d1764810',
+ packageStatus: 'SUBMITTED',
+ },
+ ],
+ },
+ contractRevisions: [contractRevisionOnRateDataMock()],
+ ...data,
+ }
+}
+
+const rateDataMock = (rateData?: Partial): 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(),
+ ],
+})
+
+export { rateDataMock, rateRevisionDataMock }
diff --git a/services/app-web/src/testHelpers/apolloMocks/rateGQLMocks.ts b/services/app-web/src/testHelpers/apolloMocks/rateGQLMocks.ts
new file mode 100644
index 0000000000..300cbcdc06
--- /dev/null
+++ b/services/app-web/src/testHelpers/apolloMocks/rateGQLMocks.ts
@@ -0,0 +1,51 @@
+import { IndexRatesDocument, IndexRatesQuery, Rate } from '../../gen/gqlClient'
+import { MockedResponse } from '@apollo/client/testing'
+import { rateDataMock } from './rateDataMock'
+import { GraphQLError } from 'graphql/index'
+
+const indexRatesMockSuccess = (
+ rates: Rate[] = [
+ { ...rateDataMock(), id: 'test-id-123', stateNumber: 3 },
+ { ...rateDataMock(), id: 'test-id-123', stateNumber: 2 },
+ { ...rateDataMock(), id: 'test-id-124', stateNumber: 1 },
+ ]
+): MockedResponse => {
+ const ratesEdge = rates.map((rate) => {
+ return {
+ node: rate,
+ }
+ })
+ return {
+ request: {
+ query: IndexRatesDocument,
+ },
+ result: {
+ data: {
+ indexRates: {
+ totalCount: ratesEdge.length,
+ edges: ratesEdge,
+ },
+ },
+ },
+ }
+}
+
+const indexRatesMockFailure = (): MockedResponse => {
+ const graphQLError = new GraphQLError('Issue finding rates with history', {
+ extensions: {
+ code: 'NOT_FOUND',
+ cause: 'DB_ERROR',
+ },
+ })
+ return {
+ request: {
+ query: IndexRatesDocument,
+ },
+ result: {
+ data: null,
+ errors: [graphQLError],
+ },
+ }
+}
+
+export { indexRatesMockSuccess, indexRatesMockFailure }
From 2da429abcf44a2d897191cda05cbc27cef7ea4fc Mon Sep 17 00:00:00 2001
From: MacRae Linton <55759+macrael@users.noreply.github.com>
Date: Wed, 18 Oct 2023 15:18:23 -0700
Subject: [PATCH 2/7] get stricter about rateinfo ids (#1992)
---
.../app-api/src/handlers/proto_to_db.test.ts | 5 +-
.../proto_to_db_CleanupLastMigration.ts | 1 -
.../submitHealthPlanPackage.test.ts | 3 +
.../unlockHealthPlanPackage.test.ts | 3 +
.../updateHealthPlanFormData.test.ts | 166 ++++++++++++++++++
.../updateHealthPlanFormData.ts | 12 ++
.../app-api/src/testHelpers/gqlHelpers.ts | 2 +
.../healthPlanFormDataEncoding.test.ts | 14 --
.../healthPlanFormDataProto/toProtoBuffer.ts | 3 +-
.../RateDetails/RateDetails.tsx | 1 +
10 files changed, 192 insertions(+), 18 deletions(-)
diff --git a/services/app-api/src/handlers/proto_to_db.test.ts b/services/app-api/src/handlers/proto_to_db.test.ts
index 9413ad2428..d1ffbe7ca1 100644
--- a/services/app-api/src/handlers/proto_to_db.test.ts
+++ b/services/app-api/src/handlers/proto_to_db.test.ts
@@ -10,6 +10,7 @@ import {
unlockTestHealthPlanPackage,
updateTestHealthPlanFormData,
} from '../testHelpers/gqlHelpers'
+import { v4 as uuidv4 } from 'uuid'
import { latestFormData } from '../testHelpers/healthPlanPackageHelpers'
import { testLDService } from '../testHelpers/launchDarklyHelpers'
import { testCMSUser } from '../testHelpers/userHelpers'
@@ -33,7 +34,7 @@ import type {
LockedHealthPlanFormDataType,
} from '../../../app-web/src/common-code/healthPlanFormDataType'
-describe('test that we migrate things', () => {
+describe.skip('test that we migrate things', () => {
const mockPreRefactorLDService = testLDService({
'rates-db-refactor': false,
})
@@ -99,6 +100,7 @@ describe('test that we migrate things', () => {
formData.rateInfos.push(
{
+ id: uuidv4(),
rateDateStart: new Date(),
rateDateEnd: new Date(),
rateProgramIDs: ['5c10fe9f-bec9-416f-a20c-718b152ad633'],
@@ -123,6 +125,7 @@ describe('test that we migrate things', () => {
],
},
{
+ id: uuidv4(),
rateDateStart: new Date(),
rateDateEnd: new Date(),
rateProgramIDs: ['5c10fe9f-bec9-416f-a20c-718b152ad633'],
diff --git a/services/app-api/src/postgres/contractAndRates/proto_to_db_CleanupLastMigration.ts b/services/app-api/src/postgres/contractAndRates/proto_to_db_CleanupLastMigration.ts
index 4056226750..99c1de2c82 100644
--- a/services/app-api/src/postgres/contractAndRates/proto_to_db_CleanupLastMigration.ts
+++ b/services/app-api/src/postgres/contractAndRates/proto_to_db_CleanupLastMigration.ts
@@ -18,7 +18,6 @@ export async function cleanupLastMigration(
client.rateRevisionsOnContractRevisionsTable.deleteMany(),
client.contractRevisionTable.deleteMany(),
client.rateRevisionTable.deleteMany(),
- client.rateRevisionsOnContractRevisionsTable.deleteMany(),
client.updateInfoTable.deleteMany(),
// must be last due to foreign keys
diff --git a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
index d2a8e154a2..3be2fe0ed0 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
@@ -11,6 +11,7 @@ import {
defaultFloridaRateProgram,
submitTestHealthPlanPackage,
} from '../../testHelpers/gqlHelpers'
+import { v4 as uuidv4 } from 'uuid'
import { testEmailConfig, testEmailer } from '../../testHelpers/emailerHelpers'
import { base64ToDomain } from '../../../../app-web/src/common-code/proto/healthPlanFormDataProto'
import {
@@ -242,6 +243,7 @@ describe.each(flagValueTestParameters)(
submissionType: 'CONTRACT_AND_RATES',
rateInfos: [
{
+ id: uuidv4(),
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
@@ -909,6 +911,7 @@ describe.each(flagValueTestParameters)(
submissionType: 'CONTRACT_AND_RATES',
rateInfos: [
{
+ id: uuidv4(),
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
rateDateCertified: undefined,
diff --git a/services/app-api/src/resolvers/healthPlanPackage/unlockHealthPlanPackage.test.ts b/services/app-api/src/resolvers/healthPlanPackage/unlockHealthPlanPackage.test.ts
index ed3d7884f4..8b30e08320 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/unlockHealthPlanPackage.test.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/unlockHealthPlanPackage.test.ts
@@ -1,5 +1,6 @@
import type { GraphQLError } from 'graphql'
import UNLOCK_HEALTH_PLAN_PACKAGE from '../../../../app-graphql/src/mutations/unlockHealthPlanPackage.graphql'
+import { v4 as uuidv4 } from 'uuid'
import type {
HealthPlanPackage,
HealthPlanRevisionEdge,
@@ -259,6 +260,7 @@ describe.each(flagValueTestParameters)(
formData.rateInfos.push(
{
+ id: uuidv4(),
rateDateStart: new Date(),
rateDateEnd: new Date(),
rateProgramIDs: ['5c10fe9f-bec9-416f-a20c-718b152ad633'],
@@ -313,6 +315,7 @@ describe.each(flagValueTestParameters)(
],
},
{
+ id: uuidv4(),
rateDateStart: new Date(),
rateDateEnd: new Date(),
rateProgramIDs: ['08d114c2-0c01-4a1a-b8ff-e2b79336672d'],
diff --git a/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.test.ts b/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.test.ts
index c39c52967d..b957e1cf29 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.test.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.test.ts
@@ -191,6 +191,7 @@ describe.each(flagValueTestParameters)(
// Create 2 rate data for insertion
const rate1 = {
+ id: uuidv4(),
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
@@ -225,6 +226,7 @@ describe.each(flagValueTestParameters)(
}
const rate2 = {
+ id: uuidv4(),
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
@@ -334,6 +336,7 @@ describe.each(flagValueTestParameters)(
)
const rate3 = {
+ id: uuidv4(),
rateType: 'AMENDMENT' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
@@ -418,6 +421,169 @@ describe.each(flagValueTestParameters)(
)
})
+ it('errors on a rate with no ID.', async () => {
+ const stateUser = {
+ id: uuidv4(),
+ givenName: 'Aang',
+ familyName: 'Avatar',
+ email: 'aang@example.com',
+ role: 'STATE_USER' as const,
+ stateCode: 'MN',
+ }
+ const server = await constructTestPostgresServer({
+ ldService: mockLDService,
+ context: {
+ user: stateUser,
+ },
+ })
+
+ const stateCode = 'MN'
+ const createdDraft = await createTestHealthPlanPackage(
+ server,
+ stateCode
+ )
+ const statePrograms = must(
+ findStatePrograms(createdDraft.stateCode)
+ )
+
+ // Create 2 valid contracts to attached to packagesWithSharedRateCerts
+ const createdDraftTwo = await createTestHealthPlanPackage(
+ server,
+ stateCode
+ )
+ const createdDraftThree = await createTestHealthPlanPackage(
+ server,
+ stateCode
+ )
+
+ const createdDraftTwoFormData = latestFormData(createdDraftTwo)
+ const createdDraftThreeFormData = latestFormData(createdDraftThree)
+
+ const packageWithSharedRate1 = {
+ packageId: createdDraftTwo.id,
+ packageName: packageName(
+ createdDraftTwo.stateCode,
+ createdDraftTwoFormData.stateNumber,
+ createdDraftTwoFormData.programIDs,
+ statePrograms
+ ),
+ } as const
+
+ const packageWithSharedRate2 = {
+ packageId: createdDraftThree.id,
+ packageName: packageName(
+ createdDraftThree.stateCode,
+ createdDraftThreeFormData.stateNumber,
+ createdDraftThreeFormData.programIDs,
+ statePrograms
+ ),
+ } as const
+
+ // Create 2 rate data for insertion
+ const rate1 = {
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2025, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rateDocument.pdf',
+ s3URL: 's3://bucketname/key/supporting-documents',
+ documentCategories: ['RATES' as const],
+ sha256: 'rate1-sha',
+ },
+ ],
+ rateAmendmentInfo: undefined,
+ rateCapitationType: undefined,
+ rateCertificationName: undefined,
+ supportingDocuments: [],
+ //We only want one rate ID and use last program in list to differentiate from programID if possible.
+ rateProgramIDs: [statePrograms.reverse()[0].id],
+ actuaryContacts: [
+ {
+ name: 'test name',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ packagesWithSharedRateCerts: [
+ packageWithSharedRate1,
+ packageWithSharedRate2,
+ ],
+ }
+
+ const rate2 = {
+ id: uuidv4(),
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2025, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rateDocument.pdf',
+ s3URL: 's3://bucketname/key/supporting-documents',
+ documentCategories: ['RATES' as const],
+ sha256: 'rate2-sha',
+ },
+ ],
+ rateAmendmentInfo: undefined,
+ rateCapitationType: undefined,
+ rateCertificationName: undefined,
+ supportingDocuments: [],
+ //We only want one rate ID and use last program in list to differentiate from programID if possible.
+ rateProgramIDs: [statePrograms.reverse()[0].id],
+ actuaryContacts: [
+ {
+ name: 'test name',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ packagesWithSharedRateCerts: [],
+ }
+
+ // update that draft form data.
+ const formData = Object.assign(latestFormData(createdDraft), {
+ addtlActuaryContacts: [
+ {
+ name: 'additional actuary 1',
+ titleRole: 'additional actuary title 1',
+ email: 'additionalactuary1@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ {
+ name: 'additional actuary 2',
+ titleRole: 'additional actuary title 2',
+ email: 'additionalactuary1@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ rateInfos: [rate1, rate2],
+ })
+
+ // convert to base64 proto
+ const updatedB64 = domainToBase64(formData)
+
+ // update the DB contract
+ const updateResult = await server.executeOperation({
+ query: UPDATE_HEALTH_PLAN_FORM_DATA,
+ variables: {
+ input: {
+ pkgID: createdDraft.id,
+ healthPlanFormData: updatedB64,
+ },
+ },
+ })
+
+ expect(updateResult.errors).toBeDefined()
+ })
+
it('updates relational fields such as documents and contacts', async () => {
const server = await constructTestPostgresServer({
ldService: mockLDService,
diff --git a/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.ts b/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.ts
index 5987bb5220..8b9fee561c 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/updateHealthPlanFormData.ts
@@ -116,6 +116,18 @@ export function updateHealthPlanFormDataResolver(
const unlockedFormData: UnlockedHealthPlanFormDataType = formDataResult
+ // If the client tries to update a rate without setting its ID that's an error.
+ for (const rateFD of unlockedFormData.rateInfos) {
+ if (!rateFD.id) {
+ const errMessage = `Attempted to update a rateInfo that has no ID: ${input.pkgID} ${rateFD}`
+ logError('updateHealthPlanFormData', errMessage)
+ setErrorAttributesOnActiveSpan(errMessage, span)
+ throw new UserInputError(errMessage, {
+ argumentName: 'healthPlanFormData.rateInfo',
+ })
+ }
+ }
+
// Uses new DB if flag is on
if (ratesDatabaseRefactor) {
// Find contract from DB
diff --git a/services/app-api/src/testHelpers/gqlHelpers.ts b/services/app-api/src/testHelpers/gqlHelpers.ts
index df98810a04..9e5498ffe5 100644
--- a/services/app-api/src/testHelpers/gqlHelpers.ts
+++ b/services/app-api/src/testHelpers/gqlHelpers.ts
@@ -1,4 +1,5 @@
import { ApolloServer } from 'apollo-server-lambda'
+import { v4 as uuidv4 } from 'uuid'
import CREATE_HEALTH_PLAN_PACKAGE from 'app-graphql/src/mutations/createHealthPlanPackage.graphql'
import SUBMIT_HEALTH_PLAN_PACKAGE from 'app-graphql/src/mutations/submitHealthPlanPackage.graphql'
import UNLOCK_HEALTH_PLAN_PACKAGE from 'app-graphql/src/mutations/unlockHealthPlanPackage.graphql'
@@ -200,6 +201,7 @@ const createAndUpdateTestHealthPlanPackage = async (
]
draft.rateInfos = [
{
+ id: uuidv4(),
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
diff --git a/services/app-web/src/common-code/proto/healthPlanFormDataProto/healthPlanFormDataEncoding.test.ts b/services/app-web/src/common-code/proto/healthPlanFormDataProto/healthPlanFormDataEncoding.test.ts
index 4500bb4490..c1249f30b2 100644
--- a/services/app-web/src/common-code/proto/healthPlanFormDataProto/healthPlanFormDataEncoding.test.ts
+++ b/services/app-web/src/common-code/proto/healthPlanFormDataProto/healthPlanFormDataEncoding.test.ts
@@ -49,20 +49,6 @@ describe('Validate encoding to protobuf and decoding back to domain model', () =
}
)
- it('encodes to protobuf and generates rate id', () => {
- const draftFormDataWithNoRateID = unlockedWithFullRates()
- draftFormDataWithNoRateID.rateInfos[0].id = undefined
-
- //Encode data to protobuf and back to domain model
- const domainData = toDomain(toProtoBuffer(draftFormDataWithNoRateID))
-
- if (domainData instanceof Error) {
- throw Error(domainData.message)
- }
-
- expect(domainData.rateInfos[0]?.id).toBeDefined()
- })
-
it('encodes to protobuf and back to domain model without corrupting existing rate info id', () => {
const draftFormDataWithNoRateID = unlockedWithFullRates()
draftFormDataWithNoRateID.rateInfos[0].id =
diff --git a/services/app-web/src/common-code/proto/healthPlanFormDataProto/toProtoBuffer.ts b/services/app-web/src/common-code/proto/healthPlanFormDataProto/toProtoBuffer.ts
index 04e56eeb85..e333fb2bbd 100644
--- a/services/app-web/src/common-code/proto/healthPlanFormDataProto/toProtoBuffer.ts
+++ b/services/app-web/src/common-code/proto/healthPlanFormDataProto/toProtoBuffer.ts
@@ -9,7 +9,6 @@ import {
import statePrograms from '../../data/statePrograms.json'
import { ProgramArgType } from '../../healthPlanFormDataType/State'
import { CURRENT_PROTO_VERSION } from './toLatestVersion'
-import { v4 as uuidv4 } from 'uuid'
const findStatePrograms = (stateCode: string): ProgramArgType[] => {
const programs = statePrograms.states.find(
@@ -198,7 +197,7 @@ const toProtoBuffer = (
domainData.rateInfos && domainData.rateInfos.length
? domainData.rateInfos.map((rateInfo) => {
return {
- id: rateInfo.id ?? uuidv4(),
+ id: rateInfo.id,
rateType: domainEnumToProto(
rateInfo.rateType,
mcreviewproto.RateType
diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetails.tsx b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetails.tsx
index 7dc39210e0..1a30906fb8 100644
--- a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetails.tsx
+++ b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetails.tsx
@@ -185,6 +185,7 @@ export const RateDetails = ({
const cleanedRateInfos = rateInfos.map((rateInfo) => {
return {
+ id: rateInfo.id,
rateType: rateInfo.rateType,
rateCapitationType: rateInfo.rateCapitationType,
rateDocuments: formatDocumentsForDomain(
From 67572c9276c30a383cf0e1ff78c39a5ffccf7838 Mon Sep 17 00:00:00 2001
From: haworku
Date: Thu, 19 Oct 2023 11:43:27 -0500
Subject: [PATCH 3/7] Fix VAL rates dashboard crash (#1993)
* Loosen the actuary contact graphql types- throwing an error that was breaking rates dash
* Don't return all rates - leave off the ones associated with contract only
* Revert "Don't return all rates - leave off the ones associated with contract only"
This reverts commit 13d433b556de50c9d6b0bf68c2f535674bae30d8.
---
services/app-graphql/src/schema.graphql | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/services/app-graphql/src/schema.graphql b/services/app-graphql/src/schema.graphql
index 0b82dae8d1..bbc37cb94f 100644
--- a/services/app-graphql/src/schema.graphql
+++ b/services/app-graphql/src/schema.graphql
@@ -835,10 +835,10 @@ enum ActuarialFirm {
}
type ActuaryContact {
- name: String!
- titleRole: String!
- email: String!
- actuarialFirm: ActuarialFirm!
+ name: String
+ titleRole: String
+ email: String
+ actuarialFirm: ActuarialFirm
actuarialFirmOther: String
}
From ce40d1cc502aed4c43f21db5c3b8a4a856b5c547 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Oct 2023 14:26:45 +0000
Subject: [PATCH 4/7] Bump lerna from 7.0.1 to 7.4.1 (#1994)
---
yarn.lock | 415 +++++++++++++++++++++++++++++-------------------------
1 file changed, 221 insertions(+), 194 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 7d07a37bc8..35117a977d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9830,13 +9830,6 @@
dependencies:
"@sinclair/typebox" "^0.24.1"
-"@jest/schemas@^29.4.3":
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
- integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==
- dependencies:
- "@sinclair/typebox" "^0.25.16"
-
"@jest/schemas@^29.6.0":
version "29.6.0"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040"
@@ -9844,6 +9837,13 @@
dependencies:
"@sinclair/typebox" "^0.27.8"
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
"@jest/source-map@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf"
@@ -10148,32 +10148,84 @@
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
-"@lerna/child-process@7.0.1":
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.0.1.tgz#b4edc965c88b2247ccc1c9bfb3dce1f42baec928"
- integrity sha512-lov3hXcX+g76fjQ5kg6+QdffL6kFw/aH3sG7NGk61mZfsWCDum9kcp9biqIRAmD6xJbrQsr1i0i9YeCMnHJ6pA==
+"@lerna/child-process@7.4.1":
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.4.1.tgz#efacbbe79794ef977feb86873d853bb8708707be"
+ integrity sha512-Bx1cRCZcVcWoz+atDQc4CSVzGuEgGJPOpIAXjQbBEA2cX5nqIBWdbye8eHu31En/F03aH9BhpNEJghs6wy4iTg==
dependencies:
chalk "^4.1.0"
execa "^5.0.0"
strong-log-transformer "^2.1.0"
-"@lerna/create@7.0.1":
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.0.1.tgz#a204a087b3b7a2ea7bb00d374faf4f306cd48aca"
- integrity sha512-vv9gtbrn/gBwQLdDlUeatO3uY58nxMktv9h9/5GEFcBesV9MAeQ0zRz8zkr2C0DX/m25lE+J5KTzJqZtMb03kw==
+"@lerna/create@7.4.1":
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/@lerna/create/-/create-7.4.1.tgz#3e4bb7235bf5700e7e63c470eba5619171331c1a"
+ integrity sha512-zPO9GyWceRimtMD+j+aQ8xJgNPYn/Q/SzHf4wYN+4Rj5nrFKMyX+Et7FbWgUNpj0dRgyCCKBDYmTB7xQVVq4gQ==
dependencies:
- "@lerna/child-process" "7.0.1"
+ "@lerna/child-process" "7.4.1"
+ "@npmcli/run-script" "6.0.2"
+ "@nx/devkit" ">=16.5.1 < 17"
+ "@octokit/plugin-enterprise-rest" "6.0.1"
+ "@octokit/rest" "19.0.11"
+ byte-size "8.1.1"
+ chalk "4.1.0"
+ clone-deep "4.0.1"
+ cmd-shim "6.0.1"
+ columnify "1.6.0"
+ conventional-changelog-core "5.0.1"
+ conventional-recommended-bump "7.0.1"
+ cosmiconfig "^8.2.0"
dedent "0.7.0"
+ execa "5.0.0"
fs-extra "^11.1.1"
+ get-stream "6.0.0"
+ git-url-parse "13.1.0"
+ glob-parent "5.1.2"
+ globby "11.1.0"
+ graceful-fs "4.2.11"
+ has-unicode "2.0.1"
+ ini "^1.3.8"
init-package-json "5.0.0"
+ inquirer "^8.2.4"
+ is-ci "3.0.1"
+ is-stream "2.0.0"
+ js-yaml "4.1.0"
+ libnpmpublish "7.3.0"
+ load-json-file "6.2.0"
+ lodash "^4.17.21"
+ make-dir "4.0.0"
+ minimatch "3.0.5"
+ multimatch "5.0.0"
+ node-fetch "2.6.7"
npm-package-arg "8.1.1"
+ npm-packlist "5.1.1"
+ npm-registry-fetch "^14.0.5"
+ npmlog "^6.0.2"
+ nx ">=16.5.1 < 17"
+ p-map "4.0.0"
+ p-map-series "2.1.0"
+ p-queue "6.6.2"
p-reduce "^2.1.0"
pacote "^15.2.0"
pify "5.0.0"
+ read-cmd-shim "4.0.0"
+ read-package-json "6.0.4"
+ resolve-from "5.0.0"
+ rimraf "^4.4.1"
semver "^7.3.4"
+ signal-exit "3.0.7"
slash "^3.0.0"
+ ssri "^9.0.1"
+ strong-log-transformer "2.1.0"
+ tar "6.1.11"
+ temp-dir "1.0.0"
+ upath "2.0.1"
+ uuid "^9.0.0"
validate-npm-package-license "^3.0.4"
validate-npm-package-name "5.0.0"
+ write-file-atomic "5.0.1"
+ write-pkg "4.0.0"
+ yargs "16.2.0"
yargs-parser "20.2.4"
"@mdx-js/mdx@^1.6.22":
@@ -10318,7 +10370,7 @@
dependencies:
which "^3.0.0"
-"@npmcli/run-script@6.0.2":
+"@npmcli/run-script@6.0.2", "@npmcli/run-script@^6.0.0":
version "6.0.2"
resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.2.tgz#a25452d45ee7f7fb8c16dfaf9624423c0c0eb885"
integrity sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==
@@ -10329,92 +10381,83 @@
read-package-json-fast "^3.0.0"
which "^3.0.0"
-"@npmcli/run-script@^6.0.0":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.1.tgz#a94404783d9afaff62decb71944435d0d8a29f8e"
- integrity sha512-Yi04ZSold8jcbBJD/ahKMJSQCQifH8DAbMwkBvoLaTpGFxzHC3B/5ZyoVR69q/4xedz84tvi9DJOJjNe17h+LA==
+"@nrwl/devkit@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.10.0.tgz#ac8c5b4db00f12c4b817c937be2f7c4eb8f2593c"
+ integrity sha512-fRloARtsDQoQgQ7HKEy0RJiusg/HSygnmg4gX/0n/Z+SUS+4KoZzvHjXc6T5ZdEiSjvLypJ+HBM8dQzIcVACPQ==
dependencies:
- "@npmcli/node-gyp" "^3.0.0"
- "@npmcli/promise-spawn" "^6.0.0"
- node-gyp "^9.0.0"
- read-package-json-fast "^3.0.0"
- which "^3.0.0"
-
-"@nrwl/devkit@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nrwl/devkit/-/devkit-16.3.2.tgz#b45393dfd62dcb75554ff0c2dff6715a907e3877"
- integrity sha512-EiDwVIvh6AcClXv22Q7auQh7Iy/ONISEFWzTswy/J6ZmVGCQesbiwg4cGV0MKiScr+awdVzqyNey+wD6IR5Lkw==
- dependencies:
- "@nx/devkit" "16.3.2"
+ "@nx/devkit" "16.10.0"
-"@nrwl/tao@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.3.2.tgz#eefc1974342afbbe48e4e5351d6707ad2f9fb179"
- integrity sha512-2Kg7dtv6JcQagCZPSq+okceI81NqmXGGgbKWqS7sOfdmp1otxS9uiUFNXw+Pdtnw38mdRviMtSOXScntu4sUKg==
+"@nrwl/tao@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-16.10.0.tgz#94642a0380709b8e387e1e33705a5a9624933375"
+ integrity sha512-QNAanpINbr+Pod6e1xNgFbzK1x5wmZl+jMocgiEFXZ67KHvmbD6MAQQr0MMz+GPhIu7EE4QCTLTyCEMlAG+K5Q==
dependencies:
- nx "16.3.2"
+ nx "16.10.0"
+ tslib "^2.3.0"
-"@nx/devkit@16.3.2", "@nx/devkit@>=16.1.3 < 17":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.3.2.tgz#95d58d104449c54bdc276fa1c9166fcad867cfa8"
- integrity sha512-1ev3EDm2Sx/ibziZroL1SheqxDR7UgC49tkBgJz1GrQLQnfdhBYroCPSyBSWGPMLHjIuHb3+hyGSV1Bz+BIYOA==
+"@nx/devkit@16.10.0", "@nx/devkit@>=16.5.1 < 17":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-16.10.0.tgz#7e466be2dee2dcb1ccaf286786ca2a0a639aa007"
+ integrity sha512-IvKQqRJFDDiaj33SPfGd3ckNHhHi6ceEoqCbAP4UuMXOPPVOX6H0KVk+9tknkPb48B7jWIw6/AgOeWkBxPRO5w==
dependencies:
- "@nrwl/devkit" "16.3.2"
+ "@nrwl/devkit" "16.10.0"
ejs "^3.1.7"
+ enquirer "~2.3.6"
ignore "^5.0.4"
- semver "7.3.4"
+ semver "7.5.3"
tmp "~0.2.1"
tslib "^2.3.0"
-"@nx/nx-darwin-arm64@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.3.2.tgz#83b6e78b27d2d7da8f7626560f52070c8735d28a"
- integrity sha512-YfYVNfsJBzBcBnJUU4AcA6A4QMkgnVlETfp4KGL36Otq542mRY1ISGHdox63ocI5AKh5gay5AaGcR4wR9PU9Vg==
-
-"@nx/nx-darwin-x64@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.3.2.tgz#0ae2a64356542c5fb73ca8038ce10ec4512e7fcb"
- integrity sha512-bJtpozz0zSRVRrcQ76GrlT3TWEGTymLYWrVG51bH5KZ46t6/a4EQBI3uL3vubMmOZ0jR4ywybOcPBBhxmBJ68w==
-
-"@nx/nx-freebsd-x64@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.3.2.tgz#202adf4d6070f47ed46450f006ecd50851147c74"
- integrity sha512-ZvufI0bWqT67nLbBo6ejrIGxypdoedRQTP/tudWbs/4isvxLe1uVku1BfKCTQUsJG367SqNOU1H5kzI/MRr3ow==
-
-"@nx/nx-linux-arm-gnueabihf@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.3.2.tgz#62314a82566e3647866b9dd4167a2d0e1397f001"
- integrity sha512-IQL4kxdiZLvifar7+SIum3glRuVsxtE0dL8RvteSDXrxDQnaTUrjILC+VGhalRmk7ngBbGKNrhWOeeL7390CzQ==
-
-"@nx/nx-linux-arm64-gnu@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.3.2.tgz#02826400aa55b8f44bac83332dd29647d0e95001"
- integrity sha512-f6AWgPVu3mfUEoOBa0rY2/7QY0Or9eR0KtLFpcPh7RUpxPw2EXzIbjD/0RGipdpspSrgiMKbZpsUjo6mXBFsQA==
-
-"@nx/nx-linux-arm64-musl@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.3.2.tgz#a0a81520e0904aa026a7ab0a8a3bf3facec9f14c"
- integrity sha512-AvrWcYz7021E3b5P9/0i26p60XMZfw86Epks51L6AhlflarlOH4AcEChc7APMtb1ELAIbDWx2S6oIDRbQ7rtVA==
-
-"@nx/nx-linux-x64-gnu@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.3.2.tgz#e79b5c142ec8d9bfb458ea5803bc4b62abbcf296"
- integrity sha512-K2pWGAcbCNm6b7UZI9cc8z4Rb540QcuepBXD7akjPjWerzXriT6VCn4i9mVKsCg2mwSfknTJJVJ1PZwJSmTl/Q==
-
-"@nx/nx-linux-x64-musl@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.3.2.tgz#900aee8f171638b9fb44378e2ac0548cb4aa99a7"
- integrity sha512-sY1QDuQlqyYiRPJZanrtV07tU0DOXiCrWb0pDsGiO0qHuUSmW5Vw17GWEY4z3rt0/5U8fJ+/9WQrneviOmsOKg==
-
-"@nx/nx-win32-arm64-msvc@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.3.2.tgz#88db772b3535648e147b1a0206b1a1fe875fa9a5"
- integrity sha512-wBfohT2hjrLKn9WFHvG0MFVk7uYhgYNiptnTLdTouziHgFyZ08vyl7XYBq55BwHPMQ5iswVoEfjn/5ZBfCPscg==
-
-"@nx/nx-win32-x64-msvc@16.3.2":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.3.2.tgz#2195faaf1fc465c7a89bfdd62323fdd2a5d91f15"
- integrity sha512-QC0sWrfQm0/WdvvM//7UAgm+otbak6bznZ0zawTeqmLBh1hLjNeweyzSVKQEtZtlzDMKpzCVuuwkJq+VKBLvmw==
+"@nx/nx-darwin-arm64@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-16.10.0.tgz#0c73010cac7a502549483b12bad347da9014e6f1"
+ integrity sha512-YF+MIpeuwFkyvM5OwgY/rTNRpgVAI/YiR0yTYCZR+X3AAvP775IVlusNgQ3oedTBRUzyRnI4Tknj1WniENFsvQ==
+
+"@nx/nx-darwin-x64@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-16.10.0.tgz#2ccf270418d552fd0a8e0d6089aee4944315adaa"
+ integrity sha512-ypi6YxwXgb0kg2ixKXE3pwf5myVNUgWf1CsV5OzVccCM8NzheMO51KDXTDmEpXdzUsfT0AkO1sk5GZeCjhVONg==
+
+"@nx/nx-freebsd-x64@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-16.10.0.tgz#c3ee6914256e69493fed9355b0d6661d0e86da44"
+ integrity sha512-UeEYFDmdbbDkTQamqvtU8ibgu5jQLgFF1ruNb/U4Ywvwutw2d4ruOMl2e0u9hiNja9NFFAnDbvzrDcMo7jYqYw==
+
+"@nx/nx-linux-arm-gnueabihf@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-16.10.0.tgz#a961eccbb38acb2da7fc125b29d1fead0b39152f"
+ integrity sha512-WV3XUC2DB6/+bz1sx+d1Ai9q2Cdr+kTZRN50SOkfmZUQyEBaF6DRYpx/a4ahhxH3ktpNfyY8Maa9OEYxGCBkQA==
+
+"@nx/nx-linux-arm64-gnu@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-16.10.0.tgz#795f20072549d03822b5c4639ef438e473dbb541"
+ integrity sha512-aWIkOUw995V3ItfpAi5FuxQ+1e9EWLS1cjWM1jmeuo+5WtaKToJn5itgQOkvSlPz+HSLgM3VfXMvOFALNk125g==
+
+"@nx/nx-linux-arm64-musl@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-16.10.0.tgz#f2428ee6dbe2b2c326e8973f76c97666def33607"
+ integrity sha512-uO6Gg+irqpVcCKMcEPIQcTFZ+tDI02AZkqkP7koQAjniLEappd8DnUBSQdcn53T086pHpdc264X/ZEpXFfrKWQ==
+
+"@nx/nx-linux-x64-gnu@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-16.10.0.tgz#d36c2bcf94d49eaa24e3880ddaf6f1f617de539b"
+ integrity sha512-134PW/u/arNFAQKpqMJniC7irbChMPz+W+qtyKPAUXE0XFKPa7c1GtlI/wK2dvP9qJDZ6bKf0KtA0U/m2HMUOA==
+
+"@nx/nx-linux-x64-musl@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-16.10.0.tgz#78bd2ab97a583b3d4ea3387b67fd7b136907493c"
+ integrity sha512-q8sINYLdIJxK/iUx9vRk5jWAWb/2O0PAbOJFwv4qkxBv4rLoN7y+otgCZ5v0xfx/zztFgk/oNY4lg5xYjIso2Q==
+
+"@nx/nx-win32-arm64-msvc@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-16.10.0.tgz#ef20ec8d0c83d66e73e20df12d2c788b8f866396"
+ integrity sha512-moJkL9kcqxUdJSRpG7dET3UeLIciwrfP08mzBQ12ewo8K8FzxU8ZUsTIVVdNrwt01CXOdXoweGfdQLjJ4qTURA==
+
+"@nx/nx-win32-x64-msvc@16.10.0":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-16.10.0.tgz#7410a51d0f8be631eec9552f01b2e5946285927c"
+ integrity sha512-5iV2NKZnzxJwZZ4DM5JVbRG/nkhAbzEskKaLBB82PmYGKzaDHuMHP1lcPoD/rtYMlowZgNA/RQndfKvPBPwmXA==
"@octokit/action@^5.0.2":
version "5.0.2"
@@ -11798,11 +11841,6 @@
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.28.tgz#15aa0b416f82c268b1573ab653e4413c965fe794"
integrity sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==
-"@sinclair/typebox@^0.25.16":
- version "0.25.24"
- resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
- integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==
-
"@sinclair/typebox@^0.27.8":
version "0.27.8"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
@@ -15999,10 +16037,10 @@
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
-"@yarnpkg/parsers@^3.0.0-rc.18":
- version "3.0.0-rc.34"
- resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.34.tgz#db1d16e082e167db6dbc67f1c264639e0b4c5e1a"
- integrity sha512-NhEA0BusInyk7EiJ7i7qF1Mkrb6gGjZcQQ/W1xxGazxapubEmGO7v5WSll6hWxFXE2ngtLj8lflq1Ff5VtqEww==
+"@yarnpkg/parsers@3.0.0-rc.46":
+ version "3.0.0-rc.46"
+ resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz#03f8363111efc0ea670e53b0282cd3ef62de4e01"
+ integrity sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==
dependencies:
js-yaml "^3.10.0"
tslib "^2.4.0"
@@ -19992,10 +20030,10 @@ diff-sequences@^27.5.1:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
-diff-sequences@^29.4.3:
- version "29.4.3"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
- integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
diff@^4.0.1:
version "4.0.2"
@@ -20164,7 +20202,7 @@ dot-prop@^5.1.0:
dependencies:
is-obj "^2.0.0"
-dotenv-expand@^10.0.0:
+dotenv-expand@^10.0.0, dotenv-expand@~10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==
@@ -20174,12 +20212,12 @@ dotenv-expand@^5.1.0:
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
-dotenv@^10.0.0, dotenv@~10.0.0:
+dotenv@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
-dotenv@^16.0.0, dotenv@^16.3.1:
+dotenv@^16.0.0, dotenv@^16.3.1, dotenv@~16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
@@ -21465,17 +21503,6 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
-fast-glob@3.2.7:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
- integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
- dependencies:
- "@nodelib/fs.stat" "^2.0.2"
- "@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.2"
- merge2 "^1.3.0"
- micromatch "^4.0.4"
-
fast-glob@^2.2.6:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@@ -24652,15 +24679,15 @@ jest-config@^29.6.2:
slash "^3.0.0"
strip-json-comments "^3.1.1"
-"jest-diff@>=29.4.3 < 30":
- version "29.5.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63"
- integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==
+"jest-diff@>=29.4.3 < 30", jest-diff@^29.4.1, jest-diff@^29.6.2:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
dependencies:
chalk "^4.0.0"
- diff-sequences "^29.4.3"
- jest-get-type "^29.4.3"
- pretty-format "^29.5.0"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
jest-diff@^27.5.1:
version "27.5.1"
@@ -24672,16 +24699,6 @@ jest-diff@^27.5.1:
jest-get-type "^27.5.1"
pretty-format "^27.5.1"
-jest-diff@^29.6.2:
- version "29.6.2"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46"
- integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==
- dependencies:
- chalk "^4.0.0"
- diff-sequences "^29.4.3"
- jest-get-type "^29.4.3"
- pretty-format "^29.6.2"
-
jest-docblock@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0"
@@ -24765,6 +24782,11 @@ jest-get-type@^29.4.3:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5"
integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==
+jest-get-type@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
+ integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
+
jest-haste-map@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa"
@@ -25923,14 +25945,14 @@ lazystream@^1.0.0:
readable-stream "^2.0.5"
lerna@^7.0.0:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.0.1.tgz#056fc44f0e4852a06e943197d3d0d05d59d84559"
- integrity sha512-kX279o8N/L2URwoR3Pf4TdIl5P8G443qAFy095ZD+Vu1tOMo8U6xOc221EgHoMuYhdqlT3f0vgn5bMMr/xNYhQ==
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.4.1.tgz#d124fa5f0a1fe10ae9a6081bc363d98f3f6caca9"
+ integrity sha512-c6sOO0dlJU689vStIsko+zjRdn2fJOWH8aNjePLNv2AubAdABKqfrDCpE2H/Q7+O80Duo68ZQtWYkUUk7hRWDw==
dependencies:
- "@lerna/child-process" "7.0.1"
- "@lerna/create" "7.0.1"
+ "@lerna/child-process" "7.4.1"
+ "@lerna/create" "7.4.1"
"@npmcli/run-script" "6.0.2"
- "@nx/devkit" ">=16.1.3 < 17"
+ "@nx/devkit" ">=16.5.1 < 17"
"@octokit/plugin-enterprise-rest" "6.0.1"
"@octokit/rest" "19.0.11"
byte-size "8.1.1"
@@ -25964,7 +25986,8 @@ lerna@^7.0.0:
libnpmaccess "7.0.2"
libnpmpublish "7.3.0"
load-json-file "6.2.0"
- make-dir "3.1.0"
+ lodash "^4.17.21"
+ make-dir "4.0.0"
minimatch "3.0.5"
multimatch "5.0.0"
node-fetch "2.6.7"
@@ -25972,7 +25995,7 @@ lerna@^7.0.0:
npm-packlist "5.1.1"
npm-registry-fetch "^14.0.5"
npmlog "^6.0.2"
- nx ">=16.1.3 < 17"
+ nx ">=16.5.1 < 17"
p-map "4.0.0"
p-map-series "2.1.0"
p-pipe "3.1.0"
@@ -26531,12 +26554,12 @@ magic-string@^0.25.0, magic-string@^0.25.7:
dependencies:
sourcemap-codec "^1.4.8"
-make-dir@3.1.0, make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
- integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+make-dir@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e"
+ integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==
dependencies:
- semver "^6.0.0"
+ semver "^7.5.3"
make-dir@^1.0.0:
version "1.3.0"
@@ -26553,6 +26576,13 @@ make-dir@^2.0.0, make-dir@^2.1.0:
pify "^4.0.1"
semver "^5.6.0"
+make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
make-error@1.x, make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
@@ -27468,6 +27498,11 @@ node-libs-browser@^2.2.1:
util "^0.11.0"
vm-browserify "^1.0.1"
+node-machine-id@1.1.12:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267"
+ integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==
+
node-preload@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301"
@@ -27729,36 +27764,38 @@ nwsapi@^2.2.0:
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.1.tgz#10a9f268fbf4c461249ebcfe38e359aa36e2577c"
integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==
-nx@16.3.2, "nx@>=16.1.3 < 17":
- version "16.3.2"
- resolved "https://registry.yarnpkg.com/nx/-/nx-16.3.2.tgz#92a2d7ef06d15b3b111b7cf9d35de08de0a22d90"
- integrity sha512-fOzCVL7qoCJAcYTJwvJ9j+PSaL791ro4AICWuLxaphZsp2jcLoav4Ev7ONPks2Wlkt8FS9bee3nqQ3w1ya36Og==
+nx@16.10.0, "nx@>=16.5.1 < 17":
+ version "16.10.0"
+ resolved "https://registry.yarnpkg.com/nx/-/nx-16.10.0.tgz#b070461f7de0a3d7988bd78558ea84cda3543ace"
+ integrity sha512-gZl4iCC0Hx0Qe1VWmO4Bkeul2nttuXdPpfnlcDKSACGu3ZIo+uySqwOF8yBAxSTIf8xe2JRhgzJN1aFkuezEBg==
dependencies:
- "@nrwl/tao" "16.3.2"
+ "@nrwl/tao" "16.10.0"
"@parcel/watcher" "2.0.4"
"@yarnpkg/lockfile" "^1.1.0"
- "@yarnpkg/parsers" "^3.0.0-rc.18"
+ "@yarnpkg/parsers" "3.0.0-rc.46"
"@zkochan/js-yaml" "0.0.6"
axios "^1.0.0"
chalk "^4.1.0"
cli-cursor "3.1.0"
cli-spinners "2.6.1"
- cliui "^7.0.2"
- dotenv "~10.0.0"
+ cliui "^8.0.1"
+ dotenv "~16.3.1"
+ dotenv-expand "~10.0.0"
enquirer "~2.3.6"
- fast-glob "3.2.7"
figures "3.2.0"
flat "^5.0.2"
fs-extra "^11.1.0"
glob "7.1.4"
ignore "^5.0.4"
+ jest-diff "^29.4.1"
js-yaml "4.1.0"
jsonc-parser "3.2.0"
lines-and-columns "~2.0.3"
minimatch "3.0.5"
+ node-machine-id "1.1.12"
npm-run-path "^4.0.1"
open "^8.4.0"
- semver "7.3.4"
+ semver "7.5.3"
string-width "^4.2.3"
strong-log-transformer "^2.1.0"
tar-stream "~2.2.0"
@@ -27769,16 +27806,16 @@ nx@16.3.2, "nx@>=16.1.3 < 17":
yargs "^17.6.2"
yargs-parser "21.1.1"
optionalDependencies:
- "@nx/nx-darwin-arm64" "16.3.2"
- "@nx/nx-darwin-x64" "16.3.2"
- "@nx/nx-freebsd-x64" "16.3.2"
- "@nx/nx-linux-arm-gnueabihf" "16.3.2"
- "@nx/nx-linux-arm64-gnu" "16.3.2"
- "@nx/nx-linux-arm64-musl" "16.3.2"
- "@nx/nx-linux-x64-gnu" "16.3.2"
- "@nx/nx-linux-x64-musl" "16.3.2"
- "@nx/nx-win32-arm64-msvc" "16.3.2"
- "@nx/nx-win32-x64-msvc" "16.3.2"
+ "@nx/nx-darwin-arm64" "16.10.0"
+ "@nx/nx-darwin-x64" "16.10.0"
+ "@nx/nx-freebsd-x64" "16.10.0"
+ "@nx/nx-linux-arm-gnueabihf" "16.10.0"
+ "@nx/nx-linux-arm64-gnu" "16.10.0"
+ "@nx/nx-linux-arm64-musl" "16.10.0"
+ "@nx/nx-linux-x64-gnu" "16.10.0"
+ "@nx/nx-linux-x64-musl" "16.10.0"
+ "@nx/nx-win32-arm64-msvc" "16.10.0"
+ "@nx/nx-win32-x64-msvc" "16.10.0"
nyc@15.1.0:
version "15.1.0"
@@ -29505,15 +29542,6 @@ pretty-format@^29.0.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"
-pretty-format@^29.5.0:
- version "29.5.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a"
- integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==
- dependencies:
- "@jest/schemas" "^29.4.3"
- ansi-styles "^5.0.0"
- react-is "^18.0.0"
-
pretty-format@^29.6.2:
version "29.6.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47"
@@ -29523,6 +29551,15 @@ pretty-format@^29.6.2:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
pretty-hrtime@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
@@ -30290,7 +30327,7 @@ read-package-json-fast@^3.0.0:
json-parse-even-better-errors "^3.0.0"
npm-normalize-package-bin "^3.0.0"
-read-package-json@6.0.4:
+read-package-json@6.0.4, read-package-json@^6.0.0:
version "6.0.4"
resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.4.tgz#90318824ec456c287437ea79595f4c2854708836"
integrity sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==
@@ -30300,16 +30337,6 @@ read-package-json@6.0.4:
normalize-package-data "^5.0.0"
npm-normalize-package-bin "^3.0.0"
-read-package-json@^6.0.0:
- version "6.0.3"
- resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.3.tgz#726116b75e00eac2075240995f05681af4ca7122"
- integrity sha512-4QbpReW4kxFgeBQ0vPAqh2y8sXEB3D4t3jsXbJKIhBiF80KT6XRo45reqwtftju5J6ru1ax06A2Gb/wM1qCOEQ==
- dependencies:
- glob "^10.2.2"
- json-parse-even-better-errors "^3.0.0"
- normalize-package-data "^5.0.0"
- npm-normalize-package-bin "^3.0.0"
-
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -31238,10 +31265,10 @@ semver@7.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
-semver@7.3.4:
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
- integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
+semver@7.5.3:
+ version "7.5.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
+ integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
dependencies:
lru-cache "^6.0.0"
From d016a8e7b2d9eb3df39c126e8bca4eaea0995f44 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Oct 2023 14:28:24 +0000
Subject: [PATCH 5/7] Bump undici from 5.19.1 to 5.26.3 (#1982)
---
yarn.lock | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 35117a977d..f740a7c7de 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8482,6 +8482,11 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333"
integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==
+"@fastify/busboy@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8"
+ integrity sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==
+
"@floating-ui/core@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.0.4.tgz#03066eaea8e9b2a2cd3f5aaa60f1e0f580ebe88e"
@@ -33598,11 +33603,11 @@ unc-path-regex@^0.1.2:
integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==
undici@^5.12.0, undici@^5.8.0:
- version "5.19.1"
- resolved "https://registry.yarnpkg.com/undici/-/undici-5.19.1.tgz#92b1fd3ab2c089b5a6bd3e579dcda8f1934ebf6d"
- integrity sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==
+ version "5.26.3"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-5.26.3.tgz#ab3527b3d5bb25b12f898dfd22165d472dd71b79"
+ integrity sha512-H7n2zmKEWgOllKkIUkLvFmsJQj062lSm3uA4EYApG8gLuiOM0/go9bIoC3HVaSnfg4xunowDE2i9p8drkXuvDw==
dependencies:
- busboy "^1.6.0"
+ "@fastify/busboy" "^2.0.0"
unfetch@^4.2.0:
version "4.2.0"
From 663f0c11763951b16cf67dbadf478252e5b5272a Mon Sep 17 00:00:00 2001
From: haworku
Date: Fri, 20 Oct 2023 10:28:33 -0500
Subject: [PATCH 6/7] MCR-3570 fix: Previous contract submissions contained
incorrect rate data (#1991)
* Add failing test for rates refactor with submit
* Clean up submitHPP test
* Add passing fetchRate tests
* clarify which ids are used
* Make parseRateWithHistory look more like parseContractWithHistory
* Revert "Make parseRateWithHistory look more like parseContractWithHistory"
This reverts commit 571bbf8aa708322012cd35364a19caf5846c8ddf.
* Fix adding rate revisions submitted after contract revision into history.
* Fix test for strict rate id checks.
* Make types play nice - right now common code actuary contact and graphql actuary contact slightly different
* Refactor loop of rate revisions of a contract revision to retain the rate order.
* Add more to docs about contract history
* Update comment.
* Refactor some more.
* Fix to retain rate order.
* cypress re-run
* cypress re-run
---------
Co-authored-by: Jason Lin
---
.../contract-rate-change-history.md | 18 +-
.../contractAndRates/revisionTypes.ts | 7 +-
.../parseContractAndRates.test.ts | 7 +
.../parseContractWithHistory.ts | 29 +-
.../contractAndRates/parseRateWithHistory.ts | 1 +
.../prismaDraftRatesHelpers.ts | 1 +
.../prismaSharedContractRateHelpers.ts | 4 +-
.../contractAndRates/unlockContract.test.ts | 7 +-
.../contractAndRates/fetchRate.test.ts | 271 ++++++++++++++++++
.../submitHealthPlanPackage.test.ts | 172 ++++++++++-
.../submitHealthPlanPackage.ts | 8 +-
.../contractAndRates/rateHelpers.ts | 15 +
.../app-api/src/testHelpers/gqlHelpers.ts | 43 ++-
.../testHelpers/healthPlanPackageHelpers.ts | 16 ++
.../DataDetailContactField.tsx | 4 +-
15 files changed, 572 insertions(+), 31 deletions(-)
diff --git a/docs/technical-design/contract-rate-change-history.md b/docs/technical-design/contract-rate-change-history.md
index e00451153b..9f310c8ea1 100644
--- a/docs/technical-design/contract-rate-change-history.md
+++ b/docs/technical-design/contract-rate-change-history.md
@@ -29,9 +29,23 @@ At the Postgres Table level, draft revisions and submitted revisions live in the
The list of revisions returned from prisma is run through [Zod](https://zod.dev/) to return [domain mode types](../../services/app-api/src/domain-models/contractAndRates). This is initiated by the `*WithHistory` database functions. See [parseContractWithHistory](../../services/app-api/src/postgres/contractAndRates/parseContractWithHistory.ts) and [parseRateWithHistory](../../services/app-api/src/postgres/contractAndRates/parseRateWithHistory.ts).
+#### Contract History
+- `parseContractWithHistory` takes our prisma contract data and parses into our domain `ContractType`. In `ContractType` the `revisions` is an array of **contract** **revisions**; this is the contract history.
+- `revisions` differs from `draftRevision` in the `ContractType`. The `draftRevision` is a singular revision that is not submitted and this data has no historical significance until it is submitted. Most of the data in this revision can be updated.
+- Each **contract revision** in `revisions` is submitted and retains data at the time of the submission. These revision's data will never be updated to retain its historical integrity.
+- An important note about the `rateRevisions` field in each contract revision in `revision`.
+ - Like contracts, rates also have **rate revisions** which are used to construct a rate history through submissions, but the purpose of `rateRevisions` on a contract revision is not for rate history.
+ - The purpose of `rateRevisions` is to retain the data of a rate linked to this contract revision at the time of submission.
+ - For that we need the single rate revision that was submitted at the time this contract revision was submitted.
+ - Here are some guidelines for each rate revision in `rateRevisions` of a contract revision.
+ - Each rate revision in `rateRevisions` is unique by rate id, meaning there will never be two rate revisions with the same rate id in `rateRevisions`
+ - Each rate revision is the latest submitted up till the contract revision submitted time.
+ - Like contract revision, rate revision is read only and cannot be updated to retain its historical integrity.
+
+
*Dev Note*: If the `draftRevision` field has a value and the `revisions` field is an empty array, we know the Contract or Rate we are looking at is an initial draft that has never been submitted.
-## The link between contract and rates is versioned. That link is solidified on submit.
+### The link between contract and rates is versioned. That link is solidified on submit.
It's possible to tell if a link between a contract and rate has become outdated by refencing the `valid After` and `validUntil` fields on the join table between contract and rate revisions. The `validFrom` is set when a link is created (when a contract is submitted with a link to rates). At the point of creation, the `validUntil` is still null.
@@ -50,4 +64,4 @@ The `unlockInfo` and `submitInfo` associated with that revision is important met
When constructing a new package with a draft contract that has a draft rate, one of them must be submitted first. We have chosen that rates submit first, then contracts are submitted with a relationship to a set of submitted rates.
## Related documentation
-- [Contract and Rates Refactor Relationships](./contract-rate-refactor-relationships.md).
\ No newline at end of file
+- [Contract and Rates Refactor Relationships](./contract-rate-refactor-relationships.md).
diff --git a/services/app-api/src/domain-models/contractAndRates/revisionTypes.ts b/services/app-api/src/domain-models/contractAndRates/revisionTypes.ts
index 168fba1bd8..8377d66879 100644
--- a/services/app-api/src/domain-models/contractAndRates/revisionTypes.ts
+++ b/services/app-api/src/domain-models/contractAndRates/revisionTypes.ts
@@ -18,7 +18,12 @@ const contractRevisionSchema = z.object({
const rateRevisionSchema = z.object({
id: z.string().uuid(),
- // rateID: z.string(), // TODO we have this data in prisma but we lose it in the domain type - its needed for frontend which uses parent ids for routing
+ rate: z.object({
+ id: z.string().uuid(),
+ stateCode: z.string(),
+ stateNumber: z.number().min(1),
+ createdAt: z.date(),
+ }),
submitInfo: updateInfoSchema.optional(),
unlockInfo: updateInfoSchema.optional(),
createdAt: z.date(),
diff --git a/services/app-api/src/postgres/contractAndRates/parseContractAndRates.test.ts b/services/app-api/src/postgres/contractAndRates/parseContractAndRates.test.ts
index 7383e0b979..cd8436874f 100644
--- a/services/app-api/src/postgres/contractAndRates/parseContractAndRates.test.ts
+++ b/services/app-api/src/postgres/contractAndRates/parseContractAndRates.test.ts
@@ -163,6 +163,13 @@ describe('parseDomainData', () => {
isRemoval: false,
rateRevision: {
id: uuidv4(),
+ rate: {
+ id: '24fb2a5f-6d0d-4e26-9906-4de28927c882',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ stateCode: 'MN',
+ stateNumber: 111,
+ },
rateID: 'Rate ID',
createdAt: new Date(),
updatedAt: new Date(),
diff --git a/services/app-api/src/postgres/contractAndRates/parseContractWithHistory.ts b/services/app-api/src/postgres/contractAndRates/parseContractWithHistory.ts
index 21b7d6fcdf..c9937e2d9a 100644
--- a/services/app-api/src/postgres/contractAndRates/parseContractWithHistory.ts
+++ b/services/app-api/src/postgres/contractAndRates/parseContractWithHistory.ts
@@ -194,7 +194,8 @@ function contractWithHistoryToDomainModel(
// }
// }
- // Basically the same as above, except we do not create new contract revisions for rate changes.
+ // This loop is finding the rate revision submitted along with this contract revision to preserve the historical
+ // rate data for the submission history.
for (const rateRev of contractRev.rateRevisions) {
if (!rateRev.rateRevision.submitInfo) {
return new Error(
@@ -202,28 +203,22 @@ function contractWithHistoryToDomainModel(
)
}
- // if it's from before this contract was submitted, it's there at the beginning.
+ // Make sure this rate revision was not submitted after this contract revision, and it was not removed.
if (
rateRev.rateRevision.submitInfo.updatedAt <=
- contractRev.submitInfo.updatedAt
+ contractRev.submitInfo.updatedAt &&
+ !rateRev.isRemoval
) {
- if (!rateRev.isRemoval) {
- initialEntry.rateRevisions.push(rateRev.rateRevision)
- }
- } else {
- // if after, then it's always a new entry in the list
- let lastRates = [...initialEntry.rateRevisions]
-
// take out the previous rate revision this revision supersedes
- lastRates = lastRates.filter(
- (r) => r.rateID !== rateRev.rateRevision.rateID
+ const filteredRevisions = initialEntry.rateRevisions.filter(
+ (rr) => rr.rateID !== rateRev.rateRevision.rateID
)
- // an isRemoval entry indicates that this rate was removed from this contract.
- if (!rateRev.isRemoval) {
- lastRates.push(rateRev.rateRevision)
- }
- initialEntry.rateRevisions = lastRates
+ // add latest revision
+ filteredRevisions.push(rateRev.rateRevision)
+
+ // Sort to retain order by rate.createdAt.
+ initialEntry.rateRevisions = filteredRevisions
}
}
}
diff --git a/services/app-api/src/postgres/contractAndRates/parseRateWithHistory.ts b/services/app-api/src/postgres/contractAndRates/parseRateWithHistory.ts
index 13c3257039..561f4f4064 100644
--- a/services/app-api/src/postgres/contractAndRates/parseRateWithHistory.ts
+++ b/services/app-api/src/postgres/contractAndRates/parseRateWithHistory.ts
@@ -85,6 +85,7 @@ function rateRevisionToDomainModel(
return {
id: revision.id,
+ rate: revision.rate,
createdAt: revision.createdAt,
updatedAt: revision.updatedAt,
submitInfo: convertUpdateInfoToDomainModel(revision.submitInfo),
diff --git a/services/app-api/src/postgres/contractAndRates/prismaDraftRatesHelpers.ts b/services/app-api/src/postgres/contractAndRates/prismaDraftRatesHelpers.ts
index d1c7e8c4a4..9b844154c7 100644
--- a/services/app-api/src/postgres/contractAndRates/prismaDraftRatesHelpers.ts
+++ b/services/app-api/src/postgres/contractAndRates/prismaDraftRatesHelpers.ts
@@ -51,6 +51,7 @@ function draftRateRevToDomainModel(
return {
id: revision.id,
+ rate: revision.rate,
createdAt: revision.createdAt,
updatedAt: revision.updatedAt,
formData,
diff --git a/services/app-api/src/postgres/contractAndRates/prismaSharedContractRateHelpers.ts b/services/app-api/src/postgres/contractAndRates/prismaSharedContractRateHelpers.ts
index 9b04f67d67..18ed03cb70 100644
--- a/services/app-api/src/postgres/contractAndRates/prismaSharedContractRateHelpers.ts
+++ b/services/app-api/src/postgres/contractAndRates/prismaSharedContractRateHelpers.ts
@@ -89,6 +89,7 @@ function getContractRateStatus(
const includeRateFormData = {
submitInfo: includeUpdateInfo,
unlockInfo: includeUpdateInfo,
+ rate: true,
rateDocuments: {
orderBy: {
@@ -224,6 +225,7 @@ function rateRevisionToDomainModel(
return {
id: revision.id,
+ rate: revision.rate,
createdAt: revision.createdAt,
updatedAt: revision.updatedAt,
unlockInfo: convertUpdateInfoToDomainModel(revision.unlockInfo),
@@ -248,7 +250,7 @@ function ratesRevisionsToDomainModel(
}
domainRevisions.sort(
- (a, b) => a.createdAt.getTime() - b.createdAt.getTime()
+ (a, b) => a.rate.createdAt.getTime() - b.rate.createdAt.getTime()
)
return domainRevisions
diff --git a/services/app-api/src/postgres/contractAndRates/unlockContract.test.ts b/services/app-api/src/postgres/contractAndRates/unlockContract.test.ts
index 8081370d54..1a5e5c734f 100644
--- a/services/app-api/src/postgres/contractAndRates/unlockContract.test.ts
+++ b/services/app-api/src/postgres/contractAndRates/unlockContract.test.ts
@@ -131,7 +131,12 @@ describe('unlockContract', () => {
)
})
- it('Unlocks a rate without breaking connected submitted contract', async () => {
+ // This is unlocking a rate without unlocking the contract that this rate belongs to. Then it updates the rate and resubmits.
+ // The rate gets a new revision, but the submitted contract does not.
+ // This test does not simulate how creating/updating a rate currently works in our app and the contract revision history
+ // will not match.
+ // Skipping this for now, revisit during rate only feature work.
+ it.skip('Unlocks a rate without breaking connected submitted contract', async () => {
const client = await sharedTestPrismaClient()
const stateUser = await client.user.create({
diff --git a/services/app-api/src/resolvers/contractAndRates/fetchRate.test.ts b/services/app-api/src/resolvers/contractAndRates/fetchRate.test.ts
index fa2c31137d..5ceb46f7c8 100644
--- a/services/app-api/src/resolvers/contractAndRates/fetchRate.test.ts
+++ b/services/app-api/src/resolvers/contractAndRates/fetchRate.test.ts
@@ -2,15 +2,286 @@ import FETCH_RATE from '../../../../app-graphql/src/queries/fetchRate.graphql'
import {
constructTestPostgresServer,
createAndSubmitTestHealthPlanPackage,
+ defaultFloridaRateProgram,
+ resubmitTestHealthPlanPackage,
unlockTestHealthPlanPackage,
+ updateTestHealthPlanPackage,
} from '../../testHelpers/gqlHelpers'
import { testCMSUser } from '../../testHelpers/userHelpers'
import { testLDService } from '../../testHelpers/launchDarklyHelpers'
import { latestFormData } from '../../testHelpers/healthPlanPackageHelpers'
+import { must } from '../../testHelpers'
+import { v4 as uuidv4 } from 'uuid'
describe('fetchRate', () => {
const mockLDService = testLDService({ 'rates-db-refactor': true })
+ it('returns correct rate revisions on resubmit when existing rate is edited', async () => {
+ const cmsUser = testCMSUser()
+ const server = await constructTestPostgresServer({
+ ldService: mockLDService,
+ })
+
+ const cmsServer = await constructTestPostgresServer({
+ context: {
+ user: cmsUser,
+ },
+ ldService: mockLDService,
+ })
+
+ const initialRateInfos = () => ({
+ id: uuidv4(),
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2025, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rateDocument.pdf',
+ s3URL: 'fakeS3URL',
+ sha256: 'fakesha',
+ documentCategories: ['RATES' as const],
+ },
+ ],
+ supportingDocuments: [],
+ rateProgramIDs: [defaultFloridaRateProgram().id],
+ actuaryContacts: [
+ {
+ name: 'test name',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ actuaryCommunicationPreference: 'OACT_TO_ACTUARY' as const,
+ packagesWithSharedRateCerts: [],
+ })
+
+ // First, create new submission and unlock to edit rate
+ const submittedEditedRates = await createAndSubmitTestHealthPlanPackage(
+ server,
+ {
+ rateInfos: [initialRateInfos()],
+ }
+ )
+ const packageID = submittedEditedRates.id
+
+ // Unlock submission
+ const unlockedHPP = await unlockTestHealthPlanPackage(
+ cmsServer,
+ packageID,
+ 'Unlock to edit an existing rate'
+ )
+
+ // Decode unlocked submission form data
+ const unlockedHppFormData = latestFormData(unlockedHPP)
+ // Get the data of the first and only rate in the HPP
+ const unlockedRate = unlockedHppFormData.rateInfos[0]
+
+ // edit the same rate
+ await updateTestHealthPlanPackage(server, packageID, {
+ rateInfos: [
+ {
+ ...unlockedRate,
+ id: unlockedRate.id, // edit same rate, use same id
+ rateDateStart: new Date(Date.UTC(2025, 1, 1)),
+ rateDateEnd: new Date(Date.UTC(2027, 1, 1)),
+ },
+ ],
+ })
+
+ // Resubmit
+ const resubmittedHPP = await resubmitTestHealthPlanPackage(
+ server,
+ packageID,
+ 'Resubmit with edited rate description'
+ )
+
+ // Decode resubmitted HPP form data
+ const resubmittedHppFormData = latestFormData(resubmittedHPP)
+
+ // fetch and check rate
+ const result = await cmsServer.executeOperation({
+ query: FETCH_RATE,
+ variables: {
+ input: {
+ rateID: resubmittedHppFormData.rateInfos[0].id,
+ },
+ },
+ })
+
+ const resubmittedRate = result.data?.fetchRate.rate
+ expect(result.errors).toBeUndefined()
+ expect(resubmittedRate).toBeDefined()
+
+ // check that we have two revisions of the same rate
+ expect(resubmittedRate.revisions).toHaveLength(2)
+
+ // newest revision data is correct
+ expect(resubmittedRate.revisions[0].formData.rateDateStart).toBe(
+ '2025-02-01'
+ )
+ expect(resubmittedRate.revisions[0].formData.rateDateEnd).toBe(
+ '2027-02-01'
+ )
+ expect(resubmittedRate.revisions[0].submitInfo.updatedReason).toBe(
+ 'Resubmit with edited rate description'
+ )
+ // the initial submit data is correct
+ expect(resubmittedRate.revisions[1].formData.rateDateStart).toBe(
+ '2025-06-01'
+ )
+ expect(resubmittedRate.revisions[1].formData.rateDateEnd).toBe(
+ '2026-05-30'
+ )
+ expect(resubmittedRate.revisions[1].submitInfo.updatedReason).toBe(
+ 'Initial submission'
+ )
+ })
+
+ it('returns correct rate revisions on resubmit when new rate added', async () => {
+ const cmsUser = testCMSUser()
+ const server = await constructTestPostgresServer({
+ ldService: mockLDService,
+ })
+
+ const cmsServer = await constructTestPostgresServer({
+ context: {
+ user: cmsUser,
+ },
+ ldService: mockLDService,
+ })
+
+ const initialRateInfos = () => ({
+ id: uuidv4(),
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2025, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rateDocument.pdf',
+ s3URL: 'fakeS3URL',
+ sha256: 'fakesha',
+ documentCategories: ['RATES' as const],
+ },
+ ],
+ supportingDocuments: [],
+ rateProgramIDs: [defaultFloridaRateProgram().id],
+ actuaryContacts: [
+ {
+ name: 'test name',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ actuaryCommunicationPreference: 'OACT_TO_ACTUARY' as const,
+ packagesWithSharedRateCerts: [],
+ })
+
+ // First, create new submission and unlock to edit rate
+ const submittedInitial = await createAndSubmitTestHealthPlanPackage(
+ server,
+ {
+ rateInfos: [initialRateInfos()],
+ }
+ )
+
+ const existingRate = await unlockTestHealthPlanPackage(
+ cmsServer,
+ submittedInitial.id,
+ 'Unlock to edit add a new rate'
+ )
+
+ // add new rate
+ const existingFormData = latestFormData(existingRate)
+ const firstRateID = existingFormData.rateInfos[0].id
+ expect(existingFormData.rateInfos).toHaveLength(1)
+ await updateTestHealthPlanPackage(server, submittedInitial.id, {
+ rateInfos: [
+ existingFormData.rateInfos[0], // first rate unchanged
+ {
+ ...initialRateInfos(),
+ rateDateStart: new Date(Date.UTC(2030, 1, 1)),
+ rateDateEnd: new Date(Date.UTC(2030, 12, 1)),
+ rateDateCertified: new Date(Date.UTC(2029, 10, 31)),
+ },
+ ],
+ })
+
+ const resubmitResult = await resubmitTestHealthPlanPackage(
+ server,
+ submittedInitial.id,
+ 'Resubmit with an additional rate'
+ )
+
+ // fetch and check rate 1 which was resubmitted with no changese
+ expect(firstRateID).toBe(latestFormData(resubmitResult).rateInfos[0].id) // first rate ID should be unchanged
+
+ const result1 = must(
+ await cmsServer.executeOperation({
+ query: FETCH_RATE,
+ variables: {
+ input: { rateID: firstRateID },
+ },
+ })
+ )
+ const resubmittedRate1 = result1.data?.fetchRate.rate
+ expect(resubmittedRate1.revisions).toHaveLength(2)
+ // dates for first rate should be unchanged
+ expect(resubmittedRate1.revisions[0].formData.rateDateStart).toBe(
+ '2025-06-01'
+ )
+ expect(resubmittedRate1.revisions[0].formData.rateDateEnd).toBe(
+ '2026-05-30'
+ )
+ expect(resubmittedRate1.revisions[0].submitInfo.updatedReason).toBe(
+ 'Resubmit with an additional rate'
+ )
+
+ // check that initial submission is correct
+ expect(resubmittedRate1.revisions[1].formData.rateDateStart).toBe(
+ '2025-06-01'
+ )
+ expect(resubmittedRate1.revisions[1].formData.rateDateEnd).toBe(
+ '2026-05-30'
+ )
+ expect(resubmittedRate1.revisions[1].submitInfo.updatedReason).toBe(
+ 'Initial submission'
+ )
+
+ // Check our second test rate which was added in unlock
+ const secondRateID = latestFormData(resubmitResult).rateInfos[1].id
+ const result2 = await cmsServer.executeOperation({
+ query: FETCH_RATE,
+ variables: {
+ input: { rateID: secondRateID },
+ },
+ })
+
+ const resubmitted2 = result2.data?.fetchRate.rate
+ expect(result2.errors).toBeUndefined()
+ expect(resubmitted2).toBeDefined()
+
+ // second test rate should only have one revision with the correct data
+ expect(resubmitted2.revisions).toHaveLength(1)
+ expect(resubmitted2.revisions[0].submitInfo.updatedReason).toBe(
+ 'Resubmit with an additional rate'
+ )
+ expect(resubmitted2.revisions[0].formData.rateDateStart).toBe(
+ '2030-02-01'
+ )
+ expect(resubmitted2.revisions[0].formData.rateDateEnd).toBe(
+ '2031-01-01'
+ )
+ expect(resubmitted2.revisions[0].formData.rateDateCertified).toBe(
+ '2029-12-01'
+ )
+ })
+
it('returns the right revisions as a rate is unlocked', async () => {
const cmsUser = testCMSUser()
const server = await constructTestPostgresServer({
diff --git a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
index 3be2fe0ed0..ce1565f061 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts
@@ -10,6 +10,7 @@ import {
createAndSubmitTestHealthPlanPackage,
defaultFloridaRateProgram,
submitTestHealthPlanPackage,
+ updateTestHealthPlanPackage,
} from '../../testHelpers/gqlHelpers'
import { v4 as uuidv4 } from 'uuid'
import { testEmailConfig, testEmailer } from '../../testHelpers/emailerHelpers'
@@ -18,7 +19,10 @@ import {
generateRateName,
packageName,
} from '../../../../app-web/src/common-code/healthPlanFormDataType'
-import { latestFormData } from '../../testHelpers/healthPlanPackageHelpers'
+import {
+ latestFormData,
+ previousFormData,
+} from '../../testHelpers/healthPlanPackageHelpers'
import {
mockEmailParameterStoreError,
getTestStateAnalystsEmails,
@@ -135,6 +139,172 @@ describe.each(flagValueTestParameters)(
).toBeGreaterThan(0)
}, 20000)
+ it('returns a state submission with the correct rate data on resubmit', async () => {
+ const cmsUser = testCMSUser()
+ const server = await constructTestPostgresServer({
+ ldService: mockLDService,
+ })
+
+ const cmsServer = await constructTestPostgresServer({
+ context: {
+ user: cmsUser,
+ },
+ ldService: mockLDService,
+ })
+
+ const initialRateInfos = () => ({
+ id: uuidv4(),
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2025, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rateDocument.pdf',
+ s3URL: 'fakeS3URL',
+ sha256: 'fakesha',
+ documentCategories: ['RATES' as const],
+ },
+ ],
+ supportingDocuments: [],
+ rateProgramIDs: [defaultFloridaRateProgram().id],
+ actuaryContacts: [
+ {
+ name: 'test name',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ actuaryCommunicationPreference: 'OACT_TO_ACTUARY' as const,
+ packagesWithSharedRateCerts: [],
+ })
+
+ // First, create new submissions
+ const submittedEditedRates =
+ await createAndSubmitTestHealthPlanPackage(server, {
+ rateInfos: [initialRateInfos()],
+ })
+ const submittedNewRates =
+ await createAndSubmitTestHealthPlanPackage(server, {
+ rateInfos: [initialRateInfos()],
+ })
+
+ // Unlock both - one to be rate edited in place, the other to add new rate
+ const existingRate1 = await unlockTestHealthPlanPackage(
+ cmsServer,
+ submittedEditedRates.id,
+ 'Unlock to edit an existing rate'
+ )
+ const existingRate2 = await unlockTestHealthPlanPackage(
+ cmsServer,
+ submittedNewRates.id,
+ 'Unlock to add a new rate'
+ )
+
+ // update one with a new rate start and end date
+ const existingFormData = latestFormData(existingRate1)
+ expect(existingFormData.rateInfos).toHaveLength(1)
+ await updateTestHealthPlanPackage(server, submittedEditedRates.id, {
+ rateInfos: [
+ {
+ ...existingFormData.rateInfos[0],
+ rateDateStart: new Date(Date.UTC(2025, 1, 1)),
+ rateDateEnd: new Date(Date.UTC(2027, 1, 1)),
+ },
+ ],
+ })
+
+ // update the other with additional new rate
+ const existingFormData2 = latestFormData(existingRate2)
+ expect(existingFormData2.rateInfos).toHaveLength(1)
+ await updateTestHealthPlanPackage(server, submittedNewRates.id, {
+ rateInfos: [
+ existingFormData2.rateInfos[0],
+ {
+ ...initialRateInfos(),
+ id: uuidv4(), // this is a new rate
+ rateDateStart: new Date(Date.UTC(2030, 1, 1)),
+ rateDateEnd: new Date(Date.UTC(2030, 12, 1)),
+ },
+ ],
+ })
+ // resubmit both
+ await resubmitTestHealthPlanPackage(
+ server,
+ submittedEditedRates.id,
+ 'Resubmit with edited rate description'
+ )
+ await resubmitTestHealthPlanPackage(
+ server,
+ submittedNewRates.id,
+ 'Resubmit with an additional rate added'
+ )
+
+ // fetch both packages and check that the latest data is correct
+ const editedRatesPackage = await fetchTestHealthPlanPackageById(
+ server,
+ submittedEditedRates.id
+ )
+ expect(latestFormData(editedRatesPackage).rateInfos).toHaveLength(1)
+ expect(
+ latestFormData(editedRatesPackage).rateInfos[0].rateDateStart
+ ).toMatchObject(new Date(Date.UTC(2025, 1, 1)))
+ expect(
+ latestFormData(editedRatesPackage).rateInfos[0].rateDateEnd
+ ).toMatchObject(new Date(Date.UTC(2027, 1, 1)))
+ expect(
+ editedRatesPackage.revisions[0].node.submitInfo?.updatedReason
+ ).toBe('Resubmit with edited rate description')
+
+ const newRatesPackage = await fetchTestHealthPlanPackageById(
+ server,
+ submittedNewRates.id
+ )
+ expect(latestFormData(newRatesPackage).rateInfos).toHaveLength(2)
+ expect(
+ latestFormData(newRatesPackage).rateInfos[0].rateDateStart
+ ).toMatchObject(initialRateInfos().rateDateStart)
+ expect(
+ latestFormData(newRatesPackage).rateInfos[0].rateDateEnd
+ ).toMatchObject(initialRateInfos().rateDateEnd)
+ expect(
+ latestFormData(newRatesPackage).rateInfos[1].rateDateStart
+ ).toMatchObject(new Date(Date.UTC(2030, 1, 1)))
+ expect(
+ latestFormData(newRatesPackage).rateInfos[1].rateDateEnd
+ ).toMatchObject(new Date(Date.UTC(2030, 12, 1)))
+ expect(
+ newRatesPackage.revisions[0].node.submitInfo?.updatedReason
+ ).toBe('Resubmit with an additional rate added')
+
+ // also check both packages to ensure previous revision data is unchanged
+ expect(previousFormData(editedRatesPackage).rateInfos).toHaveLength(
+ 1
+ )
+ expect(
+ previousFormData(editedRatesPackage).rateInfos[0].rateDateStart
+ ).toMatchObject(initialRateInfos().rateDateStart)
+ expect(
+ previousFormData(editedRatesPackage).rateInfos[0].rateDateEnd
+ ).toMatchObject(initialRateInfos().rateDateEnd)
+ expect(
+ editedRatesPackage.revisions[1].node.submitInfo?.updatedReason
+ ).toBe('Initial submission')
+
+ expect(previousFormData(newRatesPackage).rateInfos).toHaveLength(1)
+ expect(
+ previousFormData(newRatesPackage).rateInfos[0].rateDateStart
+ ).toMatchObject(initialRateInfos().rateDateStart)
+ expect(
+ previousFormData(newRatesPackage).rateInfos[0].rateDateEnd
+ ).toMatchObject(initialRateInfos().rateDateEnd)
+ expect(
+ newRatesPackage.revisions[1].node.submitInfo?.updatedReason
+ ).toBe('Initial submission')
+ })
+
it('returns an error if there are no contract documents attached', async () => {
const server = await constructTestPostgresServer({
ldService: mockLDService,
diff --git a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts
index ebc3680b8c..d60bc9b518 100644
--- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts
+++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts
@@ -290,7 +290,7 @@ export function submitHealthPlanPackageResolver(
// reassign variable set up before rates feature flag
const conversionResult = convertContractWithRatesToFormData(
- contractWithHistory.revisions[0],
+ contractWithHistory.draftRevision,
contractWithHistory.id,
contractWithHistory.stateCode,
contractWithHistory.stateNumber
@@ -304,7 +304,7 @@ export function submitHealthPlanPackageResolver(
}
initialFormData = conversionResult
- contractRevisionID = contractWithHistory.revisions[0].id
+ contractRevisionID = contractWithHistory.draftRevision.id
// Final clean + check of data before submit - parse to state submission
const maybeLocked = parseAndSubmit(initialFormData)
@@ -367,9 +367,9 @@ export function submitHealthPlanPackageResolver(
}
// If there are rates, submit those first
- if (contractWithHistory.revisions[0].rateRevisions.length > 0) {
+ if (contractWithHistory.draftRevision.rateRevisions.length > 0) {
const ratePromises: Promise[] = []
- contractWithHistory.revisions[0].rateRevisions.forEach(
+ contractWithHistory.draftRevision.rateRevisions.forEach(
(rateRev) => {
ratePromises.push(
store.submitRate({
diff --git a/services/app-api/src/testHelpers/contractAndRates/rateHelpers.ts b/services/app-api/src/testHelpers/contractAndRates/rateHelpers.ts
index a9baf0faba..c8652e98e2 100644
--- a/services/app-api/src/testHelpers/contractAndRates/rateHelpers.ts
+++ b/services/app-api/src/testHelpers/contractAndRates/rateHelpers.ts
@@ -8,6 +8,14 @@ import type { StateCodeType } from '../../../../app-web/src/common-code/healthPl
import { findStatePrograms } from '../../postgres'
import { must } from '../errorHelpers'
+const defaultRateData = () => ({
+ id: '24fb2a5f-6d0d-4e26-9906-4de28927c882',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ stateCode: 'MN',
+ stateNumber: 111,
+})
+
const createInsertRateData = (
rateArgs?: Partial
): InsertRateArgsType => {
@@ -27,6 +35,7 @@ const createDraftRateData = (
stateNumber: 111,
revisions: rate?.revisions ?? [
createRateRevision(
+ rate,
{
contractRevisions: undefined,
submitInfo: null,
@@ -47,6 +56,7 @@ const createRateData = (
stateNumber: 111,
revisions: rate?.revisions ?? [
createRateRevision(
+ rate,
{
draftContracts: undefined,
},
@@ -57,6 +67,7 @@ const createRateData = (
})
const createRateRevision = (
+ rate?: Partial,
revision?: Partial,
stateCode: StateCodeType = 'MN'
): RateRevisionTableWithContracts => {
@@ -64,6 +75,10 @@ const createRateRevision = (
return {
id: uuidv4(),
+ rate: {
+ ...defaultRateData(),
+ ...rate,
+ },
createdAt: new Date(),
updatedAt: new Date(),
submitInfo: {
diff --git a/services/app-api/src/testHelpers/gqlHelpers.ts b/services/app-api/src/testHelpers/gqlHelpers.ts
index 9e5498ffe5..3ccd40a2d3 100644
--- a/services/app-api/src/testHelpers/gqlHelpers.ts
+++ b/services/app-api/src/testHelpers/gqlHelpers.ts
@@ -178,6 +178,40 @@ const updateTestHealthPlanFormData = async (
return updateResult.data.updateHealthPlanFormData.pkg
}
+const updateTestHealthPlanPackage = async (
+ server: ApolloServer,
+ pkgID: string,
+ partialUpdates?: Partial
+): Promise => {
+ const pkg = await fetchTestHealthPlanPackageById(server, pkgID)
+ const draft = latestFormData(pkg)
+ const updatedFormData = {
+ ...draft,
+ ...partialUpdates,
+ status: 'DRAFT' as const,
+ }
+ const updateResult = await server.executeOperation({
+ query: UPDATE_HEALTH_PLAN_FORM_DATA,
+ variables: {
+ input: {
+ pkgID: pkgID,
+ healthPlanFormData: domainToBase64(updatedFormData),
+ },
+ },
+ })
+ if (updateResult.errors) {
+ console.info('errors', JSON.stringify(updateResult.errors))
+ throw new Error(
+ `updateTestHealthPlanFormData mutation failed with errors ${updateResult.errors}`
+ )
+ }
+
+ if (!updateResult.data) {
+ throw new Error('updateTestHealthPlanFormData returned nothing')
+ }
+ return updateResult.data.updateHealthPlanFormData.pkg
+}
+
const createAndUpdateTestHealthPlanPackage = async (
server: ApolloServer,
partialUpdates?: Partial,
@@ -276,9 +310,13 @@ const createAndUpdateTestHealthPlanPackage = async (
}
const createAndSubmitTestHealthPlanPackage = async (
- server: ApolloServer
+ server: ApolloServer,
+ partialUpdates?: Partial
): Promise => {
- const pkg = await createAndUpdateTestHealthPlanPackage(server)
+ const pkg = await createAndUpdateTestHealthPlanPackage(
+ server,
+ partialUpdates
+ )
return await submitTestHealthPlanPackage(server, pkg.id)
}
@@ -499,4 +537,5 @@ export {
createTestQuestion,
indexTestQuestions,
createTestQuestionResponse,
+ updateTestHealthPlanPackage,
}
diff --git a/services/app-api/src/testHelpers/healthPlanPackageHelpers.ts b/services/app-api/src/testHelpers/healthPlanPackageHelpers.ts
index 98a6476b38..46590d102b 100644
--- a/services/app-api/src/testHelpers/healthPlanPackageHelpers.ts
+++ b/services/app-api/src/testHelpers/healthPlanPackageHelpers.ts
@@ -17,3 +17,19 @@ export function latestFormData(pkg: HealthPlanPackage): HealthPlanFormDataType {
return unwrapResult
}
+
+export function previousFormData(
+ pkg: HealthPlanPackage
+): HealthPlanFormDataType {
+ const latestRevision = pkg.revisions[1].node
+ if (!latestRevision) {
+ throw new Error('no previous revisions found for package' + pkg.id)
+ }
+
+ const unwrapResult = base64ToDomain(latestRevision.formDataProto)
+ if (unwrapResult instanceof Error) {
+ throw unwrapResult
+ }
+
+ return unwrapResult
+}
diff --git a/services/app-web/src/components/DataDetail/DataDetailContactField/DataDetailContactField.tsx b/services/app-web/src/components/DataDetail/DataDetailContactField/DataDetailContactField.tsx
index 977e8239ff..3b524904c5 100644
--- a/services/app-web/src/components/DataDetail/DataDetailContactField/DataDetailContactField.tsx
+++ b/services/app-web/src/components/DataDetail/DataDetailContactField/DataDetailContactField.tsx
@@ -5,9 +5,9 @@ import {
} from '../../../common-code/healthPlanFormDataType'
import { getActuaryFirm } from '../../SubmissionSummarySection'
import { DataDetailMissingField } from '../DataDetailMissingField'
+import { ActuaryContact as GQLActuaryContact } from '../../../gen/gqlClient'
-type Contact = ActuaryContact | StateContact
-
+type Contact = ActuaryContact | StateContact | GQLActuaryContact
function isCertainActuaryContact(contact: Contact): contact is ActuaryContact {
return (contact as ActuaryContact).actuarialFirm !== undefined
}
From b9392633c53b880b47dd1803e07c7212b2b8355b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 20 Oct 2023 15:45:41 +0000
Subject: [PATCH 7/7] Bump graphql-scalars from 1.22.2 to 1.22.4 (#1980)
---
yarn.lock | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index f740a7c7de..d944f46244 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -22780,9 +22780,9 @@ graphql-request@^5.0.0:
form-data "^3.0.0"
graphql-scalars@^1.11.1:
- version "1.22.2"
- resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.22.2.tgz#6326e6fe2d0ad4228a9fea72a977e2bf26b86362"
- integrity sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==
+ version "1.22.4"
+ resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.22.4.tgz#af092b142bcfd5c1f8c53cb70ee1955ecd4ddb03"
+ integrity sha512-ILnv7jq5VKHLUyoaTFX7lgYrjCd6vTee9i8/B+D4zJKJT5TguOl0KkpPEbXHjmeor8AZYrVsrYUHdqRBMX1pjA==
dependencies:
tslib "^2.5.0"