diff --git a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
index 02fad0109b..f63c375911 100644
--- a/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
+++ b/services/app-web/src/pages/CMSDashboard/RateReviewsDashboard/RateReviewsTable.tsx
@@ -411,7 +411,7 @@ export const RateReviewsTable = ({
-
+
{reactTable.getHeaderGroups().map((headerGroup) => (
{headerGroup.headers.map((header) => (
diff --git a/services/cypress/integration/cmsWorkflow/rateReview.spec.ts b/services/cypress/integration/cmsWorkflow/rateReview.spec.ts
index b55559db6e..8866d1ab69 100644
--- a/services/cypress/integration/cmsWorkflow/rateReview.spec.ts
+++ b/services/cypress/integration/cmsWorkflow/rateReview.spec.ts
@@ -1,107 +1,91 @@
+import { HealthPlanFormDataType, packageName } from "../../../app-web/src/common-code/healthPlanFormDataType"
+import { base64ToDomain } from "../../../app-web/src/common-code/proto/healthPlanFormDataProto"
+import { HealthPlanPackage } from "../../gen/gqlClient"
+import { cmsUser, minnesotaStatePrograms, stateUser } from "../../utils/apollo-test-utils"
+
describe('CMS user can view rate reviews', () => {
beforeEach(() => {
cy.stubFeatureFlags()
cy.interceptGraphQL()
})
- it('and navigate to a specific rate from the rates dashboard', () => {
- // Assign Division to CMS user zuko
- cy.apiAssignDivisionToCMSUser(cmsUser(), 'DMCO').then(() => {
- // Create a new submission
- cy.apiCreateAndSubmitContractOnlySubmission(stateUser()).then(
- (pkg) => {
- })
- })
- // state user adds a new package
- cy.logInAsStateUser()
- cy.startNewContractAndRatesSubmission()
- cy.fillOutBaseContractDetails()
- cy.navigateFormByButtonClick('CONTINUE')
+ // By default return lastest revision
+ const getFormData = (pkg: HealthPlanPackage, indx = 0): HealthPlanFormDataType => {
+ const latestRevision = pkg.revisions[indx].node
+ if (!latestRevision) {
+ throw new Error('no revisions found for package' + pkg.id)
+ }
- cy.findByRole('heading', {
- level: 2,
- name: /Rate details/,
- }).should('exist')
- cy.fillOutNewRateCertification()
- cy.navigateFormByButtonClick('CONTINUE')
+ const unwrapResult = base64ToDomain(latestRevision.formDataProto)
+ if (unwrapResult instanceof Error) {
+ throw unwrapResult
+ }
- cy.findByRole('heading', {
- level: 2,
- name: /Contacts/,
- }).should('exist')
- cy.fillOutStateContact()
- cy.fillOutAdditionalActuaryContact()
- cy.navigateFormByButtonClick('CONTINUE')
+ return unwrapResult
+ }
- cy.findByRole('heading', {
- level: 2,
- name: /Supporting documents/,
- }).should('exist')
- cy.fillOutSupportingDocuments()
- cy.navigateFormByButtonClick('CONTINUE')
- // store submission id for reference later
- let submissionId = ''
- cy.location().then((fullUrl) => {
- const { pathname } = fullUrl
- const pathnameArray = pathname.split('/')
- submissionId = pathnameArray[2]
+ it('and navigate to a specific rate from the rates dashboard', () => {
+ cy.interceptFeatureFlags({
+ 'rates-db-refactor':true,
+ 'rate-reviews-dashboard': true
})
- // submit package
- cy.findByRole('heading', { level: 2, name: /Review and submit/ })
- cy.submitStateSubmissionForm()
-
- // store submission name for later
- cy.location().then((loc) => {
- expect(loc.search).to.match(/.*justSubmitted=*/)
- const submissionName = loc.search.split('=').pop()
- if (submissionName === undefined) {
- throw new Error('No submission name found' + loc.search)
- }
-
- // sign out state user
- cy.logOut()
- // sign in CMS user
- cy.logInAsCMSUser()
- cy.findByTestId('cms-dashboard-page').should('exist')
- cy.findByRole('table').should('exist')
- cy.findByText(submissionName).should('exist')
- // check the table of submissions
-
- // only one matching entry
- cy.get('table')
- .findAllByText(submissionName)
- .should('have.length', 1)
+ cy.apiAssignDivisionToCMSUser(cmsUser(), 'DMCO').then(() => {
- // has proper row data
- cy.get('table')
+ // Create a new contract and rates submission with two attached rates
+ cy.apiCreateAndSubmitContractWithRates(stateUser()).then(
+ (pkg) => {
+ const submission = getFormData(pkg)
+ const submissionName = packageName(
+ pkg.stateCode,
+ submission.stateNumber,
+ submission.programIDs,
+ minnesotaStatePrograms
+ )
+ // Then check both rates in rate reviews table
+ cy.logInAsCMSUser({
+ initialURL: `/dashboard/rate-reviews`,
+ })
+ const rate1 = submission.rateInfos[0]
+ const rate2 = submission.rateInfos[1]
+ cy.get('table')
+ .findByRole('link', { name: rate1.rateCertificationName })
.should('exist')
- .findByText(submissionName)
- .parent()
- .findByTestId('submission-date')
- .should('not.be.empty')
-
- cy.get('table')
+ cy.get('table')
+ .findByRole('link', { name: rate2.rateCertificationName })
.should('exist')
- .findByText(submissionName)
- .parent()
- .siblings('[data-testid="submission-status"]')
- .should('have.text', 'Submitted')
- cy.get('table')
- .contains('a', submissionName)
- .parents('tr')
- .findByTestId('submission-type')
- .should('have.text', 'Contract action and rate certification')
+ // click the first rate to navigate to rate summary page
+ cy.get('table')
+ .findByRole('link', { name: rate1.rateCertificationName })
+ .should('exist').click()
+ cy.url({ timeout: 10_000 }).should('contain',rate1.id)
+ cy.findByRole('heading', {
+ name: `${rate1.rateCertificationName}`,
+ }).should('exist')
+ cy.findByText('Rate certification type').should('exist').siblings('dd').should('have.text', 'New rate certification')
+ cy.findByText('Rating period').should('exist').siblings('dd').should('have.text', '06/01/2025 to 05/30/2026')
+ cy.findByText('Date certified').should('exist').siblings('dd').should('have.text', '04/15/2025')
+ cy.findByText('Submission this rate was submitted with').should('exist').siblings('dd').should('have.text', submissionName)
+ cy.findByText('Certifying actuary').should('exist').siblings('dd').should('have.text', 'actuary1test titleemail@example.comMercer')
+ // cy.findByText('Download all rate documents').should('exist')
+ cy.findByRole('table', {
+ name: 'Rate certification',
+ }).should('exist')
+ cy.findByText('rate1Document1.pdf').should('exist')
+ cy.findByRole('table', {
+ name: 'Rate supporting documents',
+ }).should('exist')
+ })
+ cy.findByText('rate1SupportingDocument1.pdf').should('exist')
- cy.get('table')
- .contains('a', submissionName)
- .should('have.attr', 'href')
+ // Go back to dashboard and check both rates in the table
+ // check the dashboard has the columns we expect
+ cy.findByText('Back to dashboard').should('exist').click()
+ cy.url({ timeout: 10_000 }).should('contain', 'rate-reviews')
+ cy.findByText('Rate reviews').should('exist')
+ cy.get('thead').should('have.attr', 'data-testid', 'rate-reviews-table').should('be.visible') // can't put id on table itself because data attributes not passing through in react-uswds component
- // can navigate to submission summary by clicking link
- cy.findByText(submissionName).should('exist').click()
- cy.url({ timeout: 10_000 }).should('contain', submissionId)
- cy.findByTestId('submission-summary').should('exist')
})
})
})
diff --git a/services/cypress/support/apiCommands.ts b/services/cypress/support/apiCommands.ts
index edc9cf09b3..46c8d23cdf 100644
--- a/services/cypress/support/apiCommands.ts
+++ b/services/cypress/support/apiCommands.ts
@@ -75,6 +75,7 @@ const createAndSubmitContractOnlyPackage = async (
const createAndSubmitContractWithRates = async (
apolloClient: ApolloClient
): Promise => {
+ console.log('in here')
const newSubmission1 = await apolloClient.mutate({
mutation: CreateHealthPlanPackageDocument,
variables: {
@@ -115,8 +116,6 @@ const createAndSubmitContractWithRates = async (
},
},
})
-
-
return submission1.data.submitHealthPlanPackage.pkg
}
@@ -177,6 +176,19 @@ Cypress.Commands.add(
)
)
+
+Cypress.Commands.add(
+ 'apiCreateAndSubmitContractWithRates',
+ (stateUser): Cypress.Chainable =>
+ cy.task('readGraphQLSchema').then((schema) =>
+ apolloClientWrapper(
+ schema,
+ stateUser,
+ createAndSubmitContractWithRates
+ )
+ )
+)
+
Cypress.Commands.add(
'apiAssignDivisionToCMSUser',
(cmsUser, division): Cypress.Chainable =>
diff --git a/services/cypress/support/commands.ts b/services/cypress/support/commands.ts
index 14d9bdd4b2..484c339c30 100644
--- a/services/cypress/support/commands.ts
+++ b/services/cypress/support/commands.ts
@@ -50,6 +50,7 @@ Cypress.Commands.add('interceptGraphQL', () => {
aliasQuery(req, 'fetchHealthPlanPackage')
aliasQuery(req, 'fetchHealthPlanPackageWithQuestions')
aliasQuery(req, 'indexHealthPlanPackages')
+ aliasQuery(req, 'indexRates')
aliasMutation(req, 'createHealthPlanPackage')
aliasMutation(req, 'updateHealthPlanFormData')
aliasMutation(req, 'submitHealthPlanPackage')
diff --git a/services/cypress/support/index.ts b/services/cypress/support/index.ts
index 5764d2de93..f1391d3cd1 100644
--- a/services/cypress/support/index.ts
+++ b/services/cypress/support/index.ts
@@ -101,6 +101,7 @@ declare global {
}): void
apiCreateAndSubmitContractOnlySubmission(stateUser: StateUserType): Cypress.Chainable
+ apiCreateAndSubmitContractWithRates(stateUser: StateUserType): Cypress.Chainable
apiAssignDivisionToCMSUser(cmsUser: CMSUserType, division: DivisionType): Cypress.Chainable
interceptGraphQL(): void
diff --git a/services/cypress/support/loginCommands.ts b/services/cypress/support/loginCommands.ts
index 8024db89a2..6b2e5c2ab9 100644
--- a/services/cypress/support/loginCommands.ts
+++ b/services/cypress/support/loginCommands.ts
@@ -64,11 +64,15 @@ Cypress.Commands.add(
cy.wait('@fetchCurrentUserQuery', { timeout: 20_000 })
if (initialURL?.includes('submissions')) {
cy.wait('@fetchHealthPlanPackageWithQuestionsQuery', { timeout: 20_000 }) // for cases where CMs user goes to specific submission on login, likely from email link
+ } else if (initialURL?.includes('rate-reviews')) {
+ cy.wait('@indexRatesQuery', { timeout: 80_000 })
+ cy.findByTestId('cms-dashboard-page',{timeout: 10_000 }).should('exist')
+ cy.findByRole('heading', {name: /rate reviews/}).should('exist')
} else {
- // Default behavior on login is to go to CMS dashboard
+ // Default behavior on login is to go to CMS dashboard submissions
cy.wait('@indexHealthPlanPackagesQuery', { timeout: 80_000 })
cy.findByTestId('cms-dashboard-page',{timeout: 10_000 }).should('exist')
- cy.findByRole('heading', {name: 'Submissions'}).should('exist')
+ cy.findByRole('heading', {name: /Submissions/}).should('exist')
}
}
)
diff --git a/services/cypress/utils/apollo-test-utils.ts b/services/cypress/utils/apollo-test-utils.ts
index 68a1cd96f3..6fb2f85fc3 100644
--- a/services/cypress/utils/apollo-test-utils.ts
+++ b/services/cypress/utils/apollo-test-utils.ts
@@ -1,4 +1,5 @@
import { AxiosResponse } from 'axios'
+import { v4 as uuidv4 } from 'uuid'
import {
ApolloClient,
DocumentNode,
@@ -39,6 +40,30 @@ type DivisionType = 'DMCO' | 'DMCP' | 'OACT'
type UserType = StateUserType | AdminUserType | CMSUserType
+// programs for state used in tests
+const minnesotaStatePrograms =[
+ {
+ "id": "abbdf9b0-c49e-4c4c-bb6f-040cb7b51cce",
+ "fullName": "Special Needs Basic Care",
+ "name": "SNBC"
+ },
+ {
+ "id": "d95394e5-44d1-45df-8151-1cc1ee66f100",
+ "fullName": "Prepaid Medical Assistance Program",
+ "name": "PMAP"
+ },
+ {
+ "id": "ea16a6c0-5fc6-4df8-adac-c627e76660ab",
+ "fullName": "Minnesota Senior Care Plus ",
+ "name": "MSC+"
+ },
+ {
+ "id": "3fd36500-bf2c-47bc-80e8-e7aa417184c5",
+ "fullName": "Minnesota Senior Health Options",
+ "name": "MSHO"
+ }
+]
+
const contractOnlyData = (): Partial=> ({
stateContacts: [
{
@@ -78,6 +103,7 @@ const contractOnlyData = (): Partial=> ({
})
const contractAndRatesData = (): Partial=> ({
+ stateCode: 'MN',
stateContacts: [
{
name: 'Name',
@@ -121,18 +147,22 @@ const contractAndRatesData = (): Partial=> ({
rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
rateDocuments: [
{
- name: 'rateDocument.pdf',
+ name: 'rate1Document1.pdf',
s3URL: 'fakeS3URL',
sha256: 'fakesha',
documentCategories: ['RATES' as const],
},
],
- supportingDocuments: [],
- //We only want one rate ID and use last program in list to differentiate from programID if possible.
- rateProgramIDs: [ratePrograms.reverse()[0].id],
+ supportingDocuments: [ {
+ name: 'rate1SupportingDocument1.pdf',
+ s3URL: 'fakeS3URL',
+ sha256: 'fakesha',
+ documentCategories: ['RATES' as const],
+ }],
+ rateProgramIDs: [minnesotaStatePrograms[0].id],
actuaryContacts: [
{
- name: 'test name',
+ name: 'actuary1',
titleRole: 'test title',
email: 'email@example.com',
actuarialFirm: 'MERCER' as const,
@@ -142,19 +172,52 @@ const contractAndRatesData = (): Partial=> ({
actuaryCommunicationPreference: 'OACT_TO_ACTUARY' as const,
packagesWithSharedRateCerts: [],
},
+ {
+ id: uuidv4(),
+ rateType: 'NEW' as const,
+ rateDateStart: new Date(Date.UTC(2030, 5, 1)),
+ rateDateEnd: new Date(Date.UTC(2036, 4, 30)),
+ rateDateCertified: new Date(Date.UTC(2035, 3, 15)),
+ rateDocuments: [
+ {
+ name: 'rate2Document1.pdf',
+ s3URL: 'fakeS3URL',
+ sha256: 'fakesha',
+ documentCategories: ['RATES' as const],
+ },
+ ],
+ supportingDocuments: [],
+ rateProgramIDs: [minnesotaStatePrograms[0].id],
+ actuaryContacts: [
+ {
+ name: 'actuary2',
+ titleRole: 'test title',
+ email: 'email@example.com',
+ actuarialFirm: 'MERCER' as const,
+ actuarialFirmOther: '',
+ },
+ ],
+ actuaryCommunicationPreference: 'OACT_TO_ACTUARY' as const,
+ packagesWithSharedRateCerts: [],
+ },
]
})
-const newSubmissionInput = (): Partial => ({
- populationCovered: 'MEDICAID',
- programIDs: ['abbdf9b0-c49e-4c4c-bb6f-040cb7b51cce'],
- submissionType: 'CONTRACT_ONLY',
- riskBasedContract: false,
- submissionDescription: 'Test Q&A',
- contractType: 'BASE',
-})
+const newSubmissionInput = (overrides?: Partial ): Partial => {
+ return Object.assign(
+ {
+ populationCovered: 'MEDICAID',
+ programIDs: [minnesotaStatePrograms[0].id],
+ submissionType: 'CONTRACT_ONLY',
+ riskBasedContract: false,
+ submissionDescription: 'Test Q&A',
+ contractType: 'BASE'
+ },
+ overrides
+ )
+ }
const stateUser = ():StateUserType => ({
id: 'user1',
@@ -368,10 +431,12 @@ const apolloClientWrapper = async (
export {
apolloClientWrapper,
contractOnlyData,
+ contractAndRatesData,
newSubmissionInput,
cmsUser,
adminUser,
stateUser,
+ minnesotaStatePrograms
}
export type {
StateUserType,