From 96c77fc5c43bc039970681e4953cb6e80d7f4bda Mon Sep 17 00:00:00 2001 From: MacRae Linton Date: Mon, 17 Jul 2023 17:01:38 -0700 Subject: [PATCH] Remove Population Covered Feature Flag --- services/app-api/src/handlers/apollo_gql.ts | 15 +- .../src/resolvers/configureResolvers.ts | 7 +- .../submitHealthPlanPackage.test.ts | 6 +- .../submitHealthPlanPackage.ts | 25 +- .../app-api/src/testHelpers/gqlHelpers.ts | 5 +- .../src/common-code/featureFlags/flags.ts | 7 - .../healthPlanFormData.ts | 14 +- ...ithALittleBitOfEverything-2023-07-17.proto | Bin 0 -> 941 bytes .../SubmissionTypeSummarySection.test.tsx | 7 +- .../SubmissionTypeSummarySection.tsx | 32 +- .../New/NewStateSubmissionForm.test.tsx | 3 + .../SubmissionType/SubmissionType.test.tsx | 532 +++++++++--------- .../SubmissionType/SubmissionType.tsx | 168 +++--- .../SubmissionType/SubmissionTypeSchema.ts | 10 +- 14 files changed, 377 insertions(+), 454 deletions(-) create mode 100644 services/app-web/src/common-code/proto/healthPlanFormDataProto/testData/unlockedWithALittleBitOfEverything-2023-07-17.proto diff --git a/services/app-api/src/handlers/apollo_gql.ts b/services/app-api/src/handlers/apollo_gql.ts index 1abae40d68..3922c9f40b 100644 --- a/services/app-api/src/handlers/apollo_gql.ts +++ b/services/app-api/src/handlers/apollo_gql.ts @@ -29,11 +29,6 @@ import { newAWSEmailParameterStore, newLocalEmailParameterStore, } from '../parameterStore' -import { - LDService, - ldService, - offlineLDService, -} from '../launchDarkly/launchDarkly' import { LDClient } from 'launchdarkly-node-server-sdk' import * as ld from 'launchdarkly-node-server-sdk' import { @@ -291,18 +286,15 @@ async function initializeGQLHandler(): Promise { eventsUri: 'https://events.launchdarkly.us', } ldClient = ld.init(ldSDKKey, ldOptions) - let launchDarkly: LDService // Wait for initialization. On initialization failure default to offlineLDService and close ldClient. try { await ldClient.waitForInitialization() - launchDarkly = ldService(ldClient) } catch (err) { console.error( `LaunchDarkly Error: ${err.message} Falling back to LaunchDarkly offline service.` ) ldClient.close() - launchDarkly = offlineLDService() } // Configure Apollo sandbox plugin @@ -353,12 +345,7 @@ async function initializeGQLHandler(): Promise { }) // Resolvers are defined and tested in the resolvers package - const resolvers = configureResolvers( - store, - emailer, - emailParameterStore, - launchDarkly - ) + const resolvers = configureResolvers(store, emailer, emailParameterStore) const userFetcher = authMode === 'LOCAL' diff --git a/services/app-api/src/resolvers/configureResolvers.ts b/services/app-api/src/resolvers/configureResolvers.ts index dedee3e724..48eeecb984 100644 --- a/services/app-api/src/resolvers/configureResolvers.ts +++ b/services/app-api/src/resolvers/configureResolvers.ts @@ -24,14 +24,12 @@ import { indexUsersResolver, } from './user' import { EmailParameterStore } from '../parameterStore' -import { LDService } from '../launchDarkly/launchDarkly' import { fetchEmailSettingsResolver } from './email/fetchEmailSettings' export function configureResolvers( store: Store, emailer: Emailer, - emailParameterStore: EmailParameterStore, - launchDarkly: LDService + emailParameterStore: EmailParameterStore ): Resolvers { const resolvers: Resolvers = { Date: GraphQLDate, @@ -54,8 +52,7 @@ export function configureResolvers( submitHealthPlanPackage: submitHealthPlanPackageResolver( store, emailer, - emailParameterStore, - launchDarkly + emailParameterStore ), unlockHealthPlanPackage: unlockHealthPlanPackageResolver( store, 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..4772399b09 100644 --- a/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts +++ b/services/app-api/src/resolvers/healthPlanPackage/submitHealthPlanPackage.ts @@ -29,9 +29,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 +68,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, @@ -80,11 +77,9 @@ function submit( } // move this check into isValidContract when feature flag is removed - const validPopulationCovered = featureFlags?.['chip-only-form'] - ? hasValidPopulationCoverage( - maybeStateSubmission as LockedHealthPlanFormDataType - ) - : true + const validPopulationCovered = hasValidPopulationCoverage( + maybeStateSubmission as LockedHealthPlanFormDataType + ) if ( isValidAndCurrentLockedHealthPlanFormData(maybeStateSubmission) && @@ -139,8 +134,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 +142,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 +273,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..d9d34dbbb3 100644 --- a/services/app-api/src/testHelpers/gqlHelpers.ts +++ b/services/app-api/src/testHelpers/gqlHelpers.ts @@ -37,7 +37,6 @@ import { EmailParameterStore, } from '../parameterStore' import statePrograms from 'app-web/src/common-code/data/statePrograms.json' -import { testLDService } from './launchDarklyHelpers' import { LDService } from '../launchDarkly/launchDarkly' import { insertUserToLocalAurora } from '../authn' import { testStateUser } from './userHelpers' @@ -84,7 +83,6 @@ const constructTestPostgresServer = async (opts?: { const emailer = opts?.emailer || constructTestEmailer() const parameterStore = opts?.emailParameterStore || newLocalEmailParameterStore() - const ldService = opts?.ldService || testLDService() const prismaClient = await sharedTestPrismaClient() const postgresStore = opts?.store || NewPostgresStore(prismaClient) @@ -94,8 +92,7 @@ const constructTestPostgresServer = async (opts?: { const postgresResolvers = configureResolvers( postgresStore, emailer, - parameterStore, - ldService + parameterStore ) return new ApolloServer({ diff --git a/services/app-web/src/common-code/featureFlags/flags.ts b/services/app-web/src/common-code/featureFlags/flags.ts index a33e723ca0..39d4f8ec94 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/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 0000000000000000000000000000000000000000..793bc6c428bfff4cadb9f4bb64b0e1c9feff8ed9 GIT binary patch literal 941 zcmb7@Pmj_-7{)tok=krx7sJ|gW6}`fpG^j4N?Tx03oIM<0B!&i!^NGMPS?87lD6pT zX=6N?JsD0O{aAhhy?gR%A(|L33x`SG%=={WyubGuRU3_41Vk~nNaHaO^P71n;hEAW{^_X zhsZ{Z)~SOT-rd>NtqMu5|<(9_{@d2=Qkkn z2!qVE>b&l{E+X_?dcE5+V@{@KvY@jdNrEVhAFFvkicCu4LViXqf%KBG(iU@ zcp@O70ggZqoPig@x$sJugDc@0fKNd90JeKux&c_-6o8gD { }) 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..1e23b0b17a 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 @@ -289,9 +281,7 @@ export const SubmissionType = ({ {({ values, @@ -326,78 +316,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'