diff --git a/services/app-web/src/pages/LinkYourRates/LinkRateSelect.tsx b/services/app-web/src/pages/LinkYourRates/LinkRateSelect.tsx index 41e8e250c1..5cfe1dbe8c 100644 --- a/services/app-web/src/pages/LinkYourRates/LinkRateSelect.tsx +++ b/services/app-web/src/pages/LinkYourRates/LinkRateSelect.tsx @@ -162,13 +162,13 @@ export const LinkRateSelect = ({ isClearable noOptionsMessage={() => noOptionsMessage()} classNamePrefix="select" - id={`${name}-linkRateSelect`} + id={`${name}.linkRateSelect`} inputId="" placeholder={ loading ? 'Loading rate certifications...' : 'Select...' } loadingMessage={() => 'Loading rate certifications...'} - name={name} + name={`${name}.linkRateSelect`} filterOption={filterOptions} {...selectProps} // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.test.ts b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.test.ts index adbbed2281..4adbcc2b72 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.test.ts +++ b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.test.ts @@ -2,7 +2,7 @@ import { RateDetailsFormSchema } from "./RateDetailsSchema" describe('RateDetailsSchema', () => { - it('Skips validating previously submitted rates', async () => { + it('checks child rates', async () => { const badRateRev = { rateForms: [ @@ -11,17 +11,21 @@ describe('RateDetailsSchema', () => { rateType: 'NEW', rateDocuments: [], supportingDocuments: [], - ratePreviouslySubmitted: 'YES', + ratePreviouslySubmitted: 'NO', } - ], - actuaryCommunicationPreference: 'OACT_TO_ACTUARY' + ] } - const res = await RateDetailsFormSchema({'link-rates': true}).validate(badRateRev, {abortEarly: false}) - expect(res.rateForms?.[0].ratePreviouslySubmitted).toBe('YES') + try { + await RateDetailsFormSchema({'link-rates': true}).validate(badRateRev, {abortEarly: false}) + } catch (err) { + return + } + + expect('Validator should have errored in this case').toBeUndefined() }) - it('checks child rates', async () => { + it('checks unspecified rates', async () => { const badRateRev = { rateForms: [ @@ -30,7 +34,6 @@ describe('RateDetailsSchema', () => { rateType: 'NEW', rateDocuments: [], supportingDocuments: [], - ratePreviouslySubmitted: 'NO', } ] } @@ -44,12 +47,12 @@ describe('RateDetailsSchema', () => { expect('Validator should have errored in this case').toBeUndefined() }) - it('checks unspecified rates', async () => { + it('checks empty linked rates', async () => { const badRateRev = { rateForms: [ { - id: 'fooba', + id: undefined, rateType: 'NEW', rateDocuments: [], supportingDocuments: [], diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.ts b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.ts index e1fdf0804a..499a71fd7b 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.ts +++ b/services/app-web/src/pages/StateSubmission/RateDetails/RateDetailsSchema.ts @@ -13,6 +13,9 @@ const SingleRateCertSchema = (_activeFeatureFlags: FeatureFlagSettings) => Yup.object().when('.ratePreviouslySubmitted', { // this first when is skipping all validations for a previously submitted rate. is: 'YES', + then: Yup.object().shape({ + linkRateSelect: Yup.string().defined('You must select a rate certification'), + }), otherwise: Yup.object().shape({ ratePreviouslySubmitted: _activeFeatureFlags['rate-edit-unlock'] || _activeFeatureFlags['link-rates']? Yup.string().defined( "You must select yes or no " diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.test.tsx b/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.test.tsx index aed2150ffd..bb1d5bad10 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.test.tsx +++ b/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.test.tsx @@ -1,5 +1,6 @@ import { screen, waitFor } from '@testing-library/react' import { RateDetailsV2 } from './RateDetailsV2' + import { TEST_DOC_FILE, TEST_PNG_FILE, @@ -13,7 +14,7 @@ import { mockValidStateUser, mockContractWithLinkedRateDraft, } from '../../../../testHelpers/apolloMocks' -import { Route, Routes } from 'react-router-dom' +import { Route, Routes, Location } from 'react-router-dom' import { RoutesRecord } from '../../../../constants' import userEvent from '@testing-library/user-event' import { @@ -118,7 +119,7 @@ describe('RateDetailsv2', () => { }) }) // eslint-disable-next-line - it.skip('disabled with alert if previously submitted with more than one rate cert file', async () => { + it('disabled with alert if previously submitted with more than one rate cert file', async () => { const rateID = 'abc-123' renderWithProviders( @@ -300,7 +301,7 @@ describe('RateDetailsv2', () => { }) }) - it('display rest of the form when linked rates question is answered', async () => { + it('display rest of the form when linked rates question is answered as NO', async () => { const { user } = renderWithProviders( { }) }) + it('validate form when the linked rate question is answered as YES', async () => { + const { user } = renderWithProviders( + + } + /> + , + { + apolloProvider: { + mocks: [ + fetchCurrentUserMock({ statusCode: 200 }), + fetchContractMockSuccess({ + contract: { + ...mockContractWithLinkedRateDraft(), + id: 'test-abc-123', + // clean draft rates for this test. + draftRates: [], + }, + }), + ], + }, + routerProvider: { + route: `/submissions/test-abc-123/edit/rate-details`, + }, + featureFlags: { + 'link-rates': true, + 'rate-edit-unlock': false, + }, + } + ) + await screen.findByText('Rate Details') + + await userEvent.click( + screen.getByLabelText( + 'Yes, this rate certification is part of another submission' + ) + ) + + const submitButton = screen.getByRole('button', { + name: 'Continue', + }) + + // trigger validations + await user.click(submitButton) + await waitFor(() => { + expect( + screen.getByText('Rate certification 1') + ).toBeInTheDocument() + expect(submitButton).toHaveAttribute('aria-disabled', 'true') + expect( + screen.getByText('There is 1 error on this page') + ).toBeInTheDocument() + expect( + screen.getByText('You must select a rate certification') + ).toBeInTheDocument() + }) + }) + it('renders remove rate certification button, which removes set of rate certification fields from the form', async () => { renderWithProviders( @@ -515,6 +575,96 @@ describe('RateDetailsv2', () => { ).toBeInTheDocument() }) }) + + it('save as draft with partial data without error', async () => { + let testLocation: Location // set up location to track URL changes + const { user } = renderWithProviders( + + } + /> + Dashboard page placeholder} + /> + , + { + apolloProvider: { + mocks: [ + fetchCurrentUserMock({ statusCode: 200 }), + fetchContractMockSuccess({ + contract: { + ...mockContractWithLinkedRateDraft({ + draftRates: [ + rateDataMock( + { + formData: { + ...rateRevisionDataMock() + .formData, + rateCapitationType: + undefined, + rateType: undefined, + }, + }, + { id: 'test-abc-123' } + ), + ], + }), + }, + }), + updateDraftContractRatesMockSuccess({ + contract: { + ...mockContractWithLinkedRateDraft({ + draftRates: [ + rateDataMock( + { + formData: { + ...rateRevisionDataMock() + .formData, + rateCapitationType: + undefined, + rateType: undefined, + }, + }, + { id: 'test-abc-123' } + ), + ], + }), + }, + }), + ], + }, + routerProvider: { + route: `/submissions/test-abc-123/edit/rate-details`, + }, + featureFlags: { + 'link-rates': true, + 'rate-edit-unlock': false, + }, + location: (location) => (testLocation = location), + } + ) + await screen.findByText('Rate Details') + + await userEvent.click( + screen.getByLabelText( + 'No, this rate certification was not included with any other submissions' + ) + ) + + const saveButton = screen.getByRole('button', { + name: 'Save as draft', + }) + + await user.click(saveButton) + await waitFor(() => { + expect(testLocation.pathname).toBe(`/dashboard/submissions`) + expect( + screen.getByText('Dashboard page placeholder') + ).toBeInTheDocument() + }) + }) }) describe('can link existing rate', () => { diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.tsx b/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.tsx index effd7c954f..c082c56bd4 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.tsx +++ b/services/app-web/src/pages/StateSubmission/RateDetails/V2/RateDetailsV2.tsx @@ -72,6 +72,7 @@ export type FormikRateForm = { packagesWithSharedRateCerts: RateRevision['formData']['packagesWithSharedRateCerts'] ratePreviouslySubmitted?: 'YES' | 'NO' initiallySubmittedAt?: Date + linkRateSelect?: string } // We have a list of rates to enable multi-rate behavior @@ -266,8 +267,14 @@ const RateDetailsV2 = ({ (options.type === 'CONTINUE' || options.type === 'SAVE_AS_DRAFT') ) { try { - const updatedRates = generateUpdatedRates(rateForms) - + const formattedRateForms = rateForms.filter((rate) => { + if (rate.ratePreviouslySubmitted === 'YES') { + return rate.id + } else { + return rate + } + }) + const updatedRates = generateUpdatedRates(formattedRateForms) await updateDraftContractRates({ variables: { input: { diff --git a/services/app-web/src/pages/StateSubmission/RateDetails/V2/rateDetailsHelpers.ts b/services/app-web/src/pages/StateSubmission/RateDetails/V2/rateDetailsHelpers.ts index ff20c6ac76..d6b4fdce9d 100644 --- a/services/app-web/src/pages/StateSubmission/RateDetails/V2/rateDetailsHelpers.ts +++ b/services/app-web/src/pages/StateSubmission/RateDetails/V2/rateDetailsHelpers.ts @@ -73,8 +73,8 @@ const convertGQLRateToRateForm = (getKey: S3ClientT['getKey'], rate?: Rate, pare id: rate?.id, status: rate?.status, rateCertificationName: rateForm?.rateCertificationName ?? undefined, - rateType: rateForm?.rateType, - rateCapitationType: rateForm?.rateCapitationType, + rateType: rateForm?.rateType ?? undefined, + rateCapitationType: rateForm?.rateCapitationType ?? undefined, rateDateStart: formatForForm(rateForm?.rateDateStart), rateDateEnd: formatForForm(rateForm?.rateDateEnd), rateDateCertified: formatForForm(rateForm?.rateDateCertified), @@ -102,7 +102,8 @@ const convertGQLRateToRateForm = (getKey: S3ClientT['getKey'], rate?: Rate, pare packagesWithSharedRateCerts: rateForm?.packagesWithSharedRateCerts ?? [], ratePreviouslySubmitted: handleAsLinkedRate? 'YES' : rateForm ? 'NO' : undefined, - initiallySubmittedAt: rate?.initiallySubmittedAt + initiallySubmittedAt: rate?.initiallySubmittedAt, + linkRateSelect: handleAsLinkedRate && rate?.id ? 'true' : undefined } } diff --git a/services/app-web/src/testHelpers/apolloMocks/contractGQLMock.ts b/services/app-web/src/testHelpers/apolloMocks/contractGQLMock.ts index 144134b871..690e7c52d4 100644 --- a/services/app-web/src/testHelpers/apolloMocks/contractGQLMock.ts +++ b/services/app-web/src/testHelpers/apolloMocks/contractGQLMock.ts @@ -3,7 +3,7 @@ import { Contract, FetchContractDocument, UpdateDraftContractRatesDocument, - UpdateDraftContractRatesMutation + UpdateDraftContractRatesMutation, } from '../../gen/gqlClient' import { MockedResponse } from '@apollo/client/testing' import { mockContractPackageDraft } from './contractPackageDataMock' @@ -62,15 +62,7 @@ const updateDraftContractRatesMockSuccess = ({ actuarialFirmOther: "" } ], - addtlActuaryContacts: [ - { - name: "", - titleRole: "", - email: "", - actuarialFirm: undefined, - actuarialFirmOther: "" - } - ], + addtlActuaryContacts: [], actuaryCommunicationPreference: undefined, packagesWithSharedRateCerts: [], },