diff --git a/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.test.ts b/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.test.ts index 43e66f8b0c..b959a118a4 100644 --- a/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.test.ts +++ b/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.test.ts @@ -1,7 +1,10 @@ import { HealthPlanPackageType } from '../../domain-models' import { toDomain } from '../../../../app-web/src/common-code/proto/healthPlanFormDataProto' import { sharedTestPrismaClient } from '../../testHelpers/storeHelpers' -import { insertHealthPlanPackage } from './insertHealthPlanPackage' +import { + insertHealthPlanPackage, + InsertHealthPlanPackageArgsType, +} from './insertHealthPlanPackage' import { isStoreError } from '../storeError' describe('insertHealthPlanPackage', () => { @@ -13,14 +16,14 @@ describe('insertHealthPlanPackage', () => { const client = await sharedTestPrismaClient() - const args = { + const args: InsertHealthPlanPackageArgsType = { stateCode: 'FL', + populationCovered: 'MEDICAID', programIDs: ['smmc'], riskBasedContract: false, - submissionType: 'CONTRACT_ONLY' as const, + submissionType: 'CONTRACT_ONLY', submissionDescription: 'concurrency state code test', - contractType: 'BASE' as const, - populationCovered: 'MEDICAID' as const, + contractType: 'BASE', } const resultPromises = [] diff --git a/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.ts b/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.ts index 7ec62631fc..d754887c1c 100644 --- a/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.ts +++ b/services/app-api/src/postgres/healthPlanPackage/insertHealthPlanPackage.ts @@ -18,7 +18,7 @@ import { PopulationCoveredType } from '../../gen/gqlServer' export type InsertHealthPlanPackageArgsType = { stateCode: string - populationCovered?: PopulationCoveredType + populationCovered: PopulationCoveredType programIDs: string[] riskBasedContract?: boolean submissionType: SubmissionType diff --git a/services/app-api/src/resolvers/configureResolvers.ts b/services/app-api/src/resolvers/configureResolvers.ts index cf9a6d4194..1f7f396fa6 100644 --- a/services/app-api/src/resolvers/configureResolvers.ts +++ b/services/app-api/src/resolvers/configureResolvers.ts @@ -57,8 +57,7 @@ export function configureResolvers( submitHealthPlanPackage: submitHealthPlanPackageResolver( store, emailer, - emailParameterStore, - launchDarkly + emailParameterStore ), unlockHealthPlanPackage: unlockHealthPlanPackageResolver( store, diff --git a/services/app-api/src/resolvers/healthPlanPackage/createHealthPlanPackage.test.ts b/services/app-api/src/resolvers/healthPlanPackage/createHealthPlanPackage.test.ts index 289fda662e..964adbd395 100644 --- a/services/app-api/src/resolvers/healthPlanPackage/createHealthPlanPackage.test.ts +++ b/services/app-api/src/resolvers/healthPlanPackage/createHealthPlanPackage.test.ts @@ -37,6 +37,7 @@ describe.each(flagValueTestParameters)( }) const input: CreateHealthPlanPackageInput = { + populationCovered: 'MEDICAID', programIDs: [ '5c10fe9f-bec9-416f-a20c-718b152ad633', '037af66b-81eb-4472-8b80-01edf17d12d9', @@ -74,6 +75,7 @@ describe.each(flagValueTestParameters)( ldService: mockLDService, }) const input: CreateHealthPlanPackageInput = { + populationCovered: 'MEDICAID', programIDs: ['xyz123'], riskBasedContract: false, submissionType: 'CONTRACT_ONLY', @@ -100,6 +102,7 @@ describe.each(flagValueTestParameters)( }) const input: CreateHealthPlanPackageInput = { + populationCovered: 'MEDICAID', programIDs: ['xyz123'], riskBasedContract: false, submissionType: 'CONTRACT_ONLY', diff --git a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts index 568602375f..0dc70fd29b 100644 --- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts +++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.test.ts @@ -23,7 +23,6 @@ import { getTestStateAnalystsEmails, } from '../../testHelpers/parameterStoreHelpers' import * as awsSESHelpers from '../../testHelpers/awsSESHelpers' -import { testLDService } from '../../testHelpers/launchDarklyHelpers' import { testCMSUser, testStateUser } from '../../testHelpers/userHelpers' describe('submitHealthPlanPackage', () => { @@ -903,10 +902,7 @@ describe('submitHealthPlanPackage', () => { describe('Feature flagged population coverage question test', () => { it('errors when population coverage question is undefined', async () => { - const mockLDService = testLDService({ 'chip-only-form': true }) - const server = await constructTestPostgresServer({ - ldService: mockLDService, - }) + const server = await constructTestPostgresServer() // setup const initialPkg = await createAndUpdateTestHealthPlanPackage(server, { diff --git a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts index fa848da18c..a4c040030f 100644 --- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts +++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts @@ -6,7 +6,6 @@ import { hasAnyValidRateData, isContractAndRates, removeRatesData, - hasValidPopulationCoverage, removeInvalidProvisionsAndAuthorities, isValidAndCurrentLockedHealthPlanFormData, hasValidSupportingDocumentCategories, @@ -29,9 +28,7 @@ import { } from '../attributeHelper' import { toDomain } from '../../../../app-web/src/common-code/proto/healthPlanFormDataProto' import { EmailParameterStore } from '../../parameterStore' -import { LDService } from '../../launchDarkly/launchDarkly' import { GraphQLError } from 'graphql' -import { FeatureFlagSettings } from 'app-web/src/common-code/featureFlags' import type { UnlockedHealthPlanFormDataType, @@ -70,8 +67,7 @@ export function isSubmissionError(err: unknown): err is SubmissionError { // This strategy (returning a different type from validation) is taken from the // "parse, don't validate" article: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ function submit( - draft: UnlockedHealthPlanFormDataType, - featureFlags?: FeatureFlagSettings + draft: UnlockedHealthPlanFormDataType ): LockedHealthPlanFormDataType | SubmissionError { const maybeStateSubmission: Record = { ...draft, @@ -79,20 +75,9 @@ function submit( submittedAt: new Date(), } - // move this check into isValidContract when feature flag is removed - const validPopulationCovered = featureFlags?.['chip-only-form'] - ? hasValidPopulationCoverage( - maybeStateSubmission as LockedHealthPlanFormDataType - ) - : true - - if ( - isValidAndCurrentLockedHealthPlanFormData(maybeStateSubmission) && - validPopulationCovered - ) + if (isValidAndCurrentLockedHealthPlanFormData(maybeStateSubmission)) return maybeStateSubmission else if ( - !validPopulationCovered || !hasValidContract(maybeStateSubmission as LockedHealthPlanFormDataType) ) { return { @@ -139,8 +124,7 @@ function submit( export function submitHealthPlanPackageResolver( store: Store, emailer: Emailer, - emailParameterStore: EmailParameterStore, - launchDarkly: LDService + emailParameterStore: EmailParameterStore ): MutationResolvers['submitHealthPlanPackage'] { return async (_parent, { input }, context) => { const { user, span } = context @@ -148,11 +132,6 @@ export function submitHealthPlanPackageResolver( setResolverDetailsOnActiveSpan('submitHealthPlanPackage', user, span) span?.setAttribute('mcreview.package_id', pkgID) - const chipOnlyFormFlag = await launchDarkly.getFeatureFlag( - context, - 'chip-only-form' - ) - // This resolver is only callable by state users if (!isStateUser(user)) { logError( @@ -284,9 +263,7 @@ export function submitHealthPlanPackageResolver( } // attempt to parse into a StateSubmission - const submissionResult = submit(draftResult, { - 'chip-only-form': chipOnlyFormFlag, - }) + const submissionResult = submit(draftResult) if (isSubmissionError(submissionResult)) { const errMessage = submissionResult.message diff --git a/services/app-api/src/testHelpers/gqlHelpers.ts b/services/app-api/src/testHelpers/gqlHelpers.ts index 14a8ce02a5..aaaefe5c61 100644 --- a/services/app-api/src/testHelpers/gqlHelpers.ts +++ b/services/app-api/src/testHelpers/gqlHelpers.ts @@ -132,8 +132,9 @@ const createTestHealthPlanPackage = async ( const programIDs = programs.map((program) => program.id) const input: CreateHealthPlanPackageInput = { programIDs: programIDs, + populationCovered: 'MEDICAID', riskBasedContract: false, - submissionType: 'CONTRACT_ONLY' as const, + submissionType: 'CONTRACT_ONLY', submissionDescription: 'A created submission', contractType: 'BASE', } diff --git a/services/app-graphql/src/schema.graphql b/services/app-graphql/src/schema.graphql index 0b774485a1..e61739561b 100644 --- a/services/app-graphql/src/schema.graphql +++ b/services/app-graphql/src/schema.graphql @@ -240,7 +240,7 @@ type Mutation { input CreateHealthPlanPackageInput { "Population that the contract covers" - populationCovered: PopulationCoveredType + populationCovered: PopulationCoveredType! "An array of managed care program IDs this package covers" programIDs: [ID!]! "Whether or not this contract is risk based" diff --git a/services/app-web/src/common-code/featureFlags/flags.ts b/services/app-web/src/common-code/featureFlags/flags.ts index 796390ff4b..d806ac7587 100644 --- a/services/app-web/src/common-code/featureFlags/flags.ts +++ b/services/app-web/src/common-code/featureFlags/flags.ts @@ -55,13 +55,6 @@ const featureFlags = { flag: 'packages-with-shared-rates', defaultValue: false, }, - /** - * Enables Chip-only form changes - */ - CHIP_ONLY_FORM: { - flag: 'chip-only-form', - defaultValue: false, - }, /** * Enables supporting documents to be associated with a specific rate certification on the Rate Details page */ diff --git a/services/app-web/src/common-code/healthPlanFormDataMocks/healthPlanFormData.ts b/services/app-web/src/common-code/healthPlanFormDataMocks/healthPlanFormData.ts index 16bafbf2ab..8d882269b0 100644 --- a/services/app-web/src/common-code/healthPlanFormDataMocks/healthPlanFormData.ts +++ b/services/app-web/src/common-code/healthPlanFormDataMocks/healthPlanFormData.ts @@ -46,6 +46,7 @@ function newHealthPlanFormData(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -68,6 +69,7 @@ function basicHealthPlanFormData(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -94,6 +96,7 @@ function contractOnly(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_ONLY', riskBasedContract: false, @@ -120,6 +123,7 @@ function contractAmendedOnly(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_ONLY', riskBasedContract: false, @@ -167,6 +171,7 @@ function unlockedWithContacts(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -254,6 +259,7 @@ function unlockedWithDocuments(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -364,6 +370,7 @@ function unlockedWithFullRates(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -409,7 +416,7 @@ function unlockedWithFullRates(): UnlockedHealthPlanFormDataType { documentCategories: ['RATES'], }, ], - supportingDocuments: [], + supportingDocuments: [], actuaryContacts: [ { name: 'foo bar', @@ -468,6 +475,7 @@ function unlockedWithFullContracts(): UnlockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_AND_RATES', riskBasedContract: true, @@ -540,7 +548,7 @@ function unlockedWithFullContracts(): UnlockedHealthPlanFormDataType { documentCategories: ['RATES'], }, ], - supportingDocuments: [], + supportingDocuments: [], actuaryContacts: [ { name: 'foo bar', @@ -599,6 +607,7 @@ function unlockedWithALittleBitOfEverything(): UnlockedHealthPlanFormDataType { status: 'DRAFT', stateCode: 'MN', stateNumber: 5, + populationCovered: 'MEDICAID', programIDs: [ mockMNState().programs[0].id, mockMNState().programs[1].id, @@ -735,6 +744,7 @@ function basicLockedHealthPlanFormData(): LockedHealthPlanFormDataType { stateNumber: 5, id: 'test-abc-123', stateCode: 'MN', + populationCovered: 'MEDICAID', programIDs: [mockMNState().programs[0].id], submissionType: 'CONTRACT_ONLY', riskBasedContract: false, diff --git a/services/app-web/src/common-code/healthPlanFormDataType/healthPlanFormData.ts b/services/app-web/src/common-code/healthPlanFormDataType/healthPlanFormData.ts index 3a2c6d59f9..f1a5d0e6f7 100644 --- a/services/app-web/src/common-code/healthPlanFormDataType/healthPlanFormData.ts +++ b/services/app-web/src/common-code/healthPlanFormDataType/healthPlanFormData.ts @@ -71,7 +71,8 @@ const hasValidContract = (sub: LockedHealthPlanFormDataType): boolean => sub.managedCareEntities.length !== 0 && sub.federalAuthorities.length !== 0 && sub.riskBasedContract !== undefined && - hasValidModifiedProvisions(sub) + hasValidModifiedProvisions(sub) && + hasValidPopulationCoverage(sub) const hasValidPopulationCoverage = ( sub: LockedHealthPlanFormDataType @@ -305,7 +306,7 @@ const generateRateName = ( return rateName } - // This logic is no longer needed once SUPPORTING_DOCS_BY_RATE flag is on in production +// This logic is no longer needed once SUPPORTING_DOCS_BY_RATE flag is on in production const convertRateSupportingDocs = ( documents: SubmissionDocument[] ): SubmissionDocument[] => { diff --git a/services/app-web/src/common-code/proto/healthPlanFormDataProto/testData/unlockedWithALittleBitOfEverything-2023-07-17.proto b/services/app-web/src/common-code/proto/healthPlanFormDataProto/testData/unlockedWithALittleBitOfEverything-2023-07-17.proto new file mode 100644 index 0000000000..793bc6c428 Binary files /dev/null and b/services/app-web/src/common-code/proto/healthPlanFormDataProto/testData/unlockedWithALittleBitOfEverything-2023-07-17.proto differ diff --git a/services/app-web/src/components/SubmissionSummarySection/SubmissionTypeSummarySection/SubmissionTypeSummarySection.test.tsx b/services/app-web/src/components/SubmissionSummarySection/SubmissionTypeSummarySection/SubmissionTypeSummarySection.test.tsx index 988ec9b6ad..82031b63c1 100644 --- a/services/app-web/src/components/SubmissionSummarySection/SubmissionTypeSummarySection/SubmissionTypeSummarySection.test.tsx +++ b/services/app-web/src/components/SubmissionSummarySection/SubmissionTypeSummarySection/SubmissionTypeSummarySection.test.tsx @@ -1,8 +1,5 @@ import { screen } from '@testing-library/react' -import { - ldUseClientSpy, - renderWithProviders, -} from '../../../testHelpers/jestHelpers' +import { renderWithProviders } from '../../../testHelpers/jestHelpers' import { SubmissionTypeSummarySection } from './SubmissionTypeSummarySection' import { mockContractAndRatesDraft, @@ -69,7 +66,6 @@ describe('SubmissionTypeSummarySection', () => { }) it('renders expected fields for draft package on review and submit', () => { - ldUseClientSpy({ 'chip-only-form': true }) renderWithProviders( { }) it('renders missing field message for population coverage question when expected', () => { - ldUseClientSpy({ 'chip-only-form': true }) renderWithProviders( p.name) const isSubmitted = submission.status === 'SUBMITTED' - const ldClient = useLDClient() - const showCHIPOnlyForm = ldClient?.variation( - featureFlags.CHIP_ONLY_FORM.flag, - featureFlags.CHIP_ONLY_FORM.defaultValue - ) - return (
- {showCHIPOnlyForm && ( - - )} + diff --git a/services/app-web/src/pages/StateSubmission/New/NewStateSubmissionForm.test.tsx b/services/app-web/src/pages/StateSubmission/New/NewStateSubmissionForm.test.tsx index f1e717f081..861513ce67 100644 --- a/services/app-web/src/pages/StateSubmission/New/NewStateSubmissionForm.test.tsx +++ b/services/app-web/src/pages/StateSubmission/New/NewStateSubmissionForm.test.tsx @@ -40,6 +40,9 @@ describe('NewStateSubmissionForm', () => { screen.getByRole('form', { name: 'New Submission Form' }) ).toBeInTheDocument() + const medicaid = await screen.findByText('Medicaid') + await userEvent.click(medicaid) + const comboBox = await screen.findByRole('combobox', { name: 'Programs this contract action covers (required)', }) diff --git a/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.test.tsx b/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.test.tsx index 3d243e7a34..f7d0d16a81 100644 --- a/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.test.tsx +++ b/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.test.tsx @@ -3,10 +3,7 @@ import userEvent from '@testing-library/user-event' import { screen, waitFor, within } from '@testing-library/react' import selectEvent from 'react-select-event' import { fetchCurrentUserMock } from '../../../testHelpers/apolloMocks' -import { - ldUseClientSpy, - renderWithProviders, -} from '../../../testHelpers/jestHelpers' +import { renderWithProviders } from '../../../testHelpers/jestHelpers' import { SubmissionType, SubmissionTypeFormValues } from './' import { Formik } from 'formik' import { contractOnly } from '../../../common-code/healthPlanFormDataMocks' @@ -50,20 +47,20 @@ describe('SubmissionType', () => { ) expect( - await screen.getByRole('form', { name: 'Submission Type Form' }) + screen.getByRole('form', { name: 'Submission Type Form' }) ).toBeInTheDocument() expect( - await screen.getByRole('button', { + screen.getByRole('button', { name: 'Save as draft', }) ).toBeDefined() expect( - await screen.getByRole('button', { + screen.getByRole('button', { name: 'Cancel', }) ).toBeDefined() expect( - await screen.getByRole('button', { + screen.getByRole('button', { name: 'Continue', }) ).toBeDefined() @@ -80,306 +77,299 @@ describe('SubmissionType', () => { }) expect( - await screen.getByRole('form', { name: 'New Submission Form' }) + screen.getByRole('form', { name: 'New Submission Form' }) ).toBeInTheDocument() expect( - await screen.queryByRole('button', { + screen.queryByRole('button', { name: 'Save as draft', }) ).toBeNull() expect( - await screen.getByRole('button', { + screen.getByRole('button', { name: 'Cancel', }) ).toBeDefined() expect( - await screen.getByRole('button', { + screen.getByRole('button', { name: 'Continue', }) ).toBeDefined() }) - describe('Feature flagged population coverage questions', () => { - beforeEach(() => { - ldUseClientSpy({ 'chip-only-form': true }) - }) - it('displays population coverage question', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + it('displays population coverage question', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) + + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'Medicaid' }) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'CHIP-only' }) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'Medicaid and CHIP' }) + ).toBeInTheDocument() + }) + it('disables contract and rates submission type radio and displays hint when CHIP only is selected', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'Medicaid' }) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'CHIP-only' }) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'Medicaid and CHIP' }) - ).toBeInTheDocument() - }) - it('disables contract and rates submission type radio and displays hint when CHIP only is selected', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + const chipOnlyRadio = screen.getByRole('radio', { + name: 'CHIP-only', + }) - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - const chipOnlyRadio = await screen.getByRole('radio', { - name: 'CHIP-only', - }) + // Select Chip only population coverage + await userEvent.click(chipOnlyRadio) - // Select Chip only population coverage - await userEvent.click(chipOnlyRadio) + // Contract and rates radio is disabled + expect( + screen.getByRole('radio', { + name: 'Contract action and rate certification', + }) + ).toHaveAttribute('disabled') - // Contract and rates radio is disabled - expect( - await screen.getByRole('radio', { - name: 'Contract action and rate certification', - }) - ).toHaveAttribute('disabled') + // Shows hint for submission type + expect( + screen.getByText( + 'States are not required to submit rates with CHIP-only contracts.' + ) + ).toBeInTheDocument() + }) + it('switches submission type to contract only when changing existing population coverage to CHIP-only', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) - // Shows hint for submission type - expect( - await screen.getByText( - 'States are not required to submit rates with CHIP-only contracts.' - ) - ).toBeInTheDocument() - }) - it('switches submission type to contract only when changing existing population coverage to CHIP-only', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + const medicaidRadio = screen.getByRole('radio', { + name: 'Medicaid', + }) + const contractAndRatesRadio = screen.getByRole('radio', { + name: 'Contract action and rate certification', + }) - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - const medicaidRadio = await screen.getByRole('radio', { - name: 'Medicaid', - }) - const contractAndRatesRadio = await screen.getByRole('radio', { - name: 'Contract action and rate certification', - }) + // Click Medicaid population coverage radio + await userEvent.click(medicaidRadio) - // Click Medicaid population coverage radio - await userEvent.click(medicaidRadio) + // Click contract and rates submission type + await userEvent.click(contractAndRatesRadio) - // Click contract and rates submission type - await userEvent.click(contractAndRatesRadio) + // Expect contract and rates radio to be selected + expect(contractAndRatesRadio).toBeChecked() - // Expect contract and rates radio to be selected - expect(contractAndRatesRadio).toBeChecked() + const chipOnlyRadio = screen.getByRole('radio', { + name: 'CHIP-only', + }) + const contractOnlyRadio = screen.getByRole('radio', { + name: 'Contract action only', + }) - const chipOnlyRadio = await screen.getByRole('radio', { - name: 'CHIP-only', - }) - const contractOnlyRadio = await screen.getByRole('radio', { - name: 'Contract action only', - }) + // Change population coverage to Chip only + await userEvent.click(chipOnlyRadio) - // Change population coverage to Chip only - await userEvent.click(chipOnlyRadio) + // Contract and rates radio is unselected and disabled + expect(contractAndRatesRadio).not.toBeChecked() + expect(contractAndRatesRadio).toHaveAttribute('disabled') - // Contract and rates radio is unselected and disabled - expect(contractAndRatesRadio).not.toBeChecked() - expect(contractAndRatesRadio).toHaveAttribute('disabled') + // Contract only radio is selected + expect(contractOnlyRadio).toBeChecked() - // Contract only radio is selected - expect(contractOnlyRadio).toBeChecked() + // Shows hint for submission type + expect( + screen.getByText( + 'States are not required to submit rates with CHIP-only contracts.' + ) + ).toBeInTheDocument() + }) + it('new submissions does not automatically select contract only submission type when selecting CHIP-only coverage', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) - // Shows hint for submission type - expect( - await screen.getByText( - 'States are not required to submit rates with CHIP-only contracts.' - ) - ).toBeInTheDocument() - }) - it('new submissions does not automatically select contract only submission type when selecting CHIP-only coverage', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + const medicaidRadio = screen.getByRole('radio', { + name: 'Medicaid', + }) + const chipOnlyRadio = screen.getByRole('radio', { + name: 'CHIP-only', + }) + const medicaidAndChipRadio = screen.getByRole('radio', { + name: 'Medicaid and CHIP', + }) + const contractAndRatesRadio = screen.getByRole('radio', { + name: 'Contract action and rate certification', + }) + const contractOnlyRadio = screen.getByRole('radio', { + name: 'Contract action only', + }) - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - const medicaidRadio = await screen.getByRole('radio', { - name: 'Medicaid', - }) - const chipOnlyRadio = await screen.getByRole('radio', { - name: 'CHIP-only', - }) - const medicaidAndChipRadio = await screen.getByRole('radio', { - name: 'Medicaid and CHIP', - }) - const contractAndRatesRadio = await screen.getByRole('radio', { - name: 'Contract action and rate certification', - }) - const contractOnlyRadio = await screen.getByRole('radio', { - name: 'Contract action only', - }) + // Click on each of the population covered radios + await userEvent.click(medicaidRadio) + await userEvent.click(chipOnlyRadio) + await userEvent.click(medicaidAndChipRadio) - // Click on each of the population covered radios - await userEvent.click(medicaidRadio) - await userEvent.click(chipOnlyRadio) - await userEvent.click(medicaidAndChipRadio) + // Expect contract and rates radio to not be selected + expect(contractAndRatesRadio).not.toBeChecked() + expect(contractOnlyRadio).not.toBeChecked() - // Expect contract and rates radio to not be selected - expect(contractAndRatesRadio).not.toBeChecked() - expect(contractOnlyRadio).not.toBeChecked() + // Change population coverage to Chip only + await userEvent.click(chipOnlyRadio) - // Change population coverage to Chip only - await userEvent.click(chipOnlyRadio) + // Expect the submission type radios to still be unselected + expect(contractAndRatesRadio).not.toBeChecked() + expect(contractOnlyRadio).not.toBeChecked() - // Expect the submission type radios to still be unselected - expect(contractAndRatesRadio).not.toBeChecked() - expect(contractOnlyRadio).not.toBeChecked() + // Shows hint for submission type + expect( + screen.getByText( + 'States are not required to submit rates with CHIP-only contracts.' + ) + ).toBeInTheDocument() + }) + it('does not clear contract only submission type radio when switching to CHIP-only population coverage', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) - // Shows hint for submission type - expect( - await screen.getByText( - 'States are not required to submit rates with CHIP-only contracts.' - ) - ).toBeInTheDocument() - }) - it('does not clear contract only submission type radio when switching to CHIP-only population coverage', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + const medicaidRadio = screen.getByRole('radio', { + name: 'Medicaid', + }) + const contractOnlyRadio = screen.getByRole('radio', { + name: 'Contract action only', + }) - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - const medicaidRadio = await screen.getByRole('radio', { - name: 'Medicaid', - }) - const contractOnlyRadio = await screen.getByRole('radio', { - name: 'Contract action only', - }) + // Click Medicaid population coverage radio + await userEvent.click(medicaidRadio) - // Click Medicaid population coverage radio - await userEvent.click(medicaidRadio) + // Click contract only submission type + await userEvent.click(contractOnlyRadio) - // Click contract only submission type - await userEvent.click(contractOnlyRadio) + // Expect contract only radio to be selected + expect(contractOnlyRadio).toBeChecked() - // Expect contract only radio to be selected - expect(contractOnlyRadio).toBeChecked() + const chipOnlyRadio = screen.getByRole('radio', { + name: 'CHIP-only', + }) - const chipOnlyRadio = await screen.getByRole('radio', { - name: 'CHIP-only', - }) + // Change population coverage to Chip only + await userEvent.click(chipOnlyRadio) - // Change population coverage to Chip only - await userEvent.click(chipOnlyRadio) + // Contract only radio is still selected + expect(contractOnlyRadio).toBeChecked() + }) + it('shows validation message when population coverage is not selected', async () => { + renderWithProviders( + + + , + { + apolloProvider: { + mocks: [fetchCurrentUserMock({ statusCode: 200 })], + }, + } + ) - // Contract only radio is still selected - expect(contractOnlyRadio).toBeChecked() - }) - it('shows validation message when population coverage is not selected', async () => { - renderWithProviders( - - - , - { - apolloProvider: { - mocks: [fetchCurrentUserMock({ statusCode: 200 })], - }, - } + // Expect population coverage question and radios + expect( + screen.getByText( + 'Which populations does this contract action cover?' ) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'Medicaid' }) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'CHIP-only' }) + ).toBeInTheDocument() + expect( + screen.getByRole('radio', { name: 'Medicaid and CHIP' }) + ).toBeInTheDocument() - // Expect population coverage question and radios - expect( - await screen.getByText( - 'Which populations does this contract action cover?' - ) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'Medicaid' }) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'CHIP-only' }) - ).toBeInTheDocument() - expect( - await screen.getByRole('radio', { name: 'Medicaid and CHIP' }) - ).toBeInTheDocument() - - // Test validations work. - await userEvent.click( - screen.getByRole('button', { name: 'Continue' }) - ) - await screen.findByTestId('error-summary') - await screen.findAllByText( - 'You must select the population this contract covers' - ) - }) + // Test validations work. + await userEvent.click(screen.getByRole('button', { name: 'Continue' })) + await screen.findByTestId('error-summary') + await screen.findAllByText( + 'You must select the population this contract covers' + ) }) it('displays programs select dropdown', async () => { @@ -398,7 +388,7 @@ describe('SubmissionType', () => { ) expect( - await screen.getByRole('combobox', { + screen.getByRole('combobox', { name: 'Programs this contract action covers (required)', }) ).toBeInTheDocument() @@ -444,14 +434,14 @@ describe('SubmissionType', () => { ) const combobox = await screen.findByRole('combobox') - await selectEvent.openMenu(combobox) + selectEvent.openMenu(combobox) await waitFor(() => { expect(screen.getByText('Program 3')).toBeInTheDocument() }) await selectEvent.select(combobox, 'Program 1') - await selectEvent.openMenu(combobox) + selectEvent.openMenu(combobox) await selectEvent.select(combobox, 'Program 3') // in react-select, only items that are selected have a "remove item" label @@ -475,10 +465,10 @@ describe('SubmissionType', () => { ) expect( - await screen.getByRole('radio', { name: 'Contract action only' }) + screen.getByRole('radio', { name: 'Contract action only' }) ).toBeInTheDocument() expect( - await screen.getByRole('radio', { + screen.getByRole('radio', { name: 'Contract action and rate certification', }) ).toBeInTheDocument() @@ -500,10 +490,10 @@ describe('SubmissionType', () => { ) expect( - await screen.getByRole('radio', { name: 'Base contract' }) + screen.getByRole('radio', { name: 'Base contract' }) ).toBeInTheDocument() expect( - await screen.getByRole('radio', { + screen.getByRole('radio', { name: 'Amendment to base contract', }) ).toBeInTheDocument() @@ -565,7 +555,7 @@ describe('SubmissionType', () => { } ) expect( - await screen.getByRole('textbox', { + screen.getByRole('textbox', { name: 'Submission description', }) ).toBeInTheDocument() @@ -582,14 +572,14 @@ describe('SubmissionType', () => { } ) - expect(await screen.getByRole('textbox')).not.toHaveClass( + expect(screen.getByRole('textbox')).not.toHaveClass( 'usa-input--error' ) expect( - await screen.queryByText('You must choose a submission type') + screen.queryByText('You must choose a submission type') ).toBeNull() expect( - await screen.queryByText( + screen.queryByText( 'You must provide a description of any major changes or updates' ) ).toBeNull() @@ -612,7 +602,7 @@ describe('SubmissionType', () => { name: 'Submission description', }) - expect(await textarea).toBeInTheDocument() + expect(textarea).toBeInTheDocument() //trigger validation await userEvent.type(textarea, 'something') @@ -643,7 +633,7 @@ describe('SubmissionType', () => { name: 'Submission description', }) - expect(await textarea).toBeInTheDocument() + expect(textarea).toBeInTheDocument() const submissionType = await screen.findByText( 'Contract action only' diff --git a/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.tsx b/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.tsx index 6dd00cd686..05d5d600e8 100644 --- a/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.tsx +++ b/services/app-web/src/pages/StateSubmission/SubmissionType/SubmissionType.tsx @@ -44,8 +44,6 @@ import { yesNoFormValueAsBoolean, } from '../../../components/Form/FieldYesNo/FieldYesNo' import { SubmissionTypeFormSchema } from './SubmissionTypeSchema' -import { useLDClient } from 'launchdarkly-react-client-sdk' -import { featureFlags } from '../../../common-code/featureFlags' export interface SubmissionTypeFormValues { populationCovered?: PopulationCoveredType @@ -79,12 +77,6 @@ export const SubmissionType = ({ const location = useLocation() const isNewSubmission = location.pathname === '/submissions/new' - const ldClient = useLDClient() - const showCHIPOnlyForm = ldClient?.variation( - featureFlags.CHIP_ONLY_FORM.flag, - featureFlags.CHIP_ONLY_FORM.defaultValue - ) - const [createHealthPlanPackage, { error }] = useCreateHealthPlanPackageMutation({ // This function updates the Apollo Client Cache after we create a new DraftSubmission @@ -162,6 +154,13 @@ export const SubmissionType = ({ ) => { if (isNewSubmission) { try { + if (!values.populationCovered) { + console.info( + 'unexpected error, attempting to submit without population covered', + values.submissionType + ) + return + } if ( !( values.submissionType === 'CONTRACT_ONLY' || @@ -289,9 +288,7 @@ export const SubmissionType = ({ {({ values, @@ -326,78 +323,71 @@ export const SubmissionType = ({ headingRef={errorSummaryHeadingRef} /> )} - - {showCHIPOnlyForm && ( - +
+ {showFieldErrors( errors.populationCovered + ) && ( + + {errors.populationCovered} + )} - > -
- {showFieldErrors( - errors.populationCovered - ) && ( - - {errors.populationCovered} - - )} - - handlePopulationCoveredClick( - 'MEDICAID', - values, - setFieldValue - ) - } - /> - - handlePopulationCoveredClick( - 'MEDICAID_AND_CHIP', - values, - setFieldValue - ) - } - /> - - handlePopulationCoveredClick( - 'CHIP', - values, - setFieldValue - ) - } - /> -
- - )} + + handlePopulationCoveredClick( + 'MEDICAID', + values, + setFieldValue + ) + } + /> + + handlePopulationCoveredClick( + 'MEDICAID_AND_CHIP', + values, + setFieldValue + ) + } + /> + + handlePopulationCoveredClick( + 'CHIP', + values, + setFieldValue + ) + } + /> +
+
- {showCHIPOnlyForm && - values.populationCovered === 'CHIP' && ( -
- States are not required to - submit rates with CHIP-only - contracts. -
- )} + {values.populationCovered === 'CHIP' && ( +
+ States are not required to submit + rates with CHIP-only contracts. +
+ )}
+const SubmissionTypeFormSchema = (_flags: FeatureFlagSettings = {}) => Yup.object().shape({ - populationCovered: flags['chip-only-form'] - ? Yup.string().required( - 'You must select the population this contract covers' - ) - : Yup.string().optional(), + populationCovered: Yup.string().required( + 'You must select the population this contract covers' + ), programIDs: Yup.array().min(1, 'You must select at least one program'), submissionType: Yup.string().required( 'You must choose a submission type' diff --git a/services/cypress/integration/stateWorkflow/questionResponse/questionResponse.spec.ts b/services/cypress/integration/stateWorkflow/questionResponse/questionResponse.spec.ts index 5c16fced3d..5f8bc3e0b1 100644 --- a/services/cypress/integration/stateWorkflow/questionResponse/questionResponse.spec.ts +++ b/services/cypress/integration/stateWorkflow/questionResponse/questionResponse.spec.ts @@ -8,7 +8,6 @@ describe('Q&A', () => { it('can add questions and responses', () => { cy.interceptFeatureFlags({ 'cms-questions': true, - 'chip-only-form': true, }) // Assign Division to CMS user zuko diff --git a/services/cypress/support/launchDarklyCommands.ts b/services/cypress/support/launchDarklyCommands.ts index f72cf7bd2c..74767a8f32 100644 --- a/services/cypress/support/launchDarklyCommands.ts +++ b/services/cypress/support/launchDarklyCommands.ts @@ -84,7 +84,6 @@ Cypress.Commands.add('stubFeatureFlags', () => { * Useful if you want default feature flags for tests that are different than default values set in common-code featureFlags **/ cy.interceptFeatureFlags({ - 'chip-only-form': true, 'packages-with-shared-rates': true, }) }) diff --git a/services/cypress/support/stateSubmissionFormCommands.ts b/services/cypress/support/stateSubmissionFormCommands.ts index 3243d61d2e..a6edcaab09 100644 --- a/services/cypress/support/stateSubmissionFormCommands.ts +++ b/services/cypress/support/stateSubmissionFormCommands.ts @@ -1,4 +1,3 @@ -import { aliasMutation } from '../utils/graphql-test-utils' Cypress.Commands.add('startNewContractOnlySubmissionWithBaseContract', () => { // Must be on '/submissions/new' cy.findByTestId('dashboard-page').should('exist') @@ -37,11 +36,7 @@ Cypress.Commands.add('startNewContractAndRatesSubmission', () => { Cypress.Commands.add('fillOutContractActionOnlyWithBaseContract', () => { // Must be on '/submissions/new' - cy.getFeatureFlagStore(['chip-only-form']).then((store) => { - if (store['chip-only-form']) { - cy.get('label[for="medicaid"]').click() - } - }) + cy.get('label[for="medicaid"]').click() cy.findByRole('combobox', { name: 'Programs this contract action covers (required)', @@ -63,11 +58,7 @@ Cypress.Commands.add('fillOutContractActionOnlyWithBaseContract', () => { Cypress.Commands.add('fillOutContractActionOnlyWithAmendment', () => { // Must be on '/submissions/new' - cy.getFeatureFlagStore(['chip-only-form']).then((store) => { - if (store['chip-only-form']) { - cy.get('label[for="medicaid"]').click() - } - }) + cy.get('label[for="medicaid"]').click() cy.findByRole('combobox', { name: 'Programs this contract action covers (required)', timeout: 2_000 }).click({ @@ -89,11 +80,7 @@ Cypress.Commands.add('fillOutContractActionOnlyWithAmendment', () => { Cypress.Commands.add('fillOutContractActionAndRateCertification', () => { // Must be on '/submissions/new' - cy.getFeatureFlagStore(['chip-only-form']).then((store) => { - if (store['chip-only-form']) { - cy.get('label[for="medicaid"]').click() - } - }) + cy.get('label[for="medicaid"]').click() cy.findByRole('combobox', { name: 'Programs this contract action covers (required)', timeout: 2_000 }).click({