From b4d20b5aa6499b38fd8a08cc081d86642357b956 Mon Sep 17 00:00:00 2001 From: Alex Gonzalez Date: Tue, 12 Mar 2024 11:05:28 -0700 Subject: [PATCH] Add SNAP/OHEP info screens to flow start (#110) --- build.gradle | 11 +- .../conditions/ProgramsIncludeSnapOrTCA.java | 20 +++ src/main/resources/flows-config.yaml | 11 ++ src/main/resources/messages.properties | 75 +++++----- .../resources/static/assets/css/custom.css | 4 + .../mdBenefitsFlow/expeditedSnapNotice.html | 52 ++----- .../mdBenefitsFlow/howThisWorks.html | 130 ++++++++---------- .../templates/mdBenefitsFlow/ohepNotice.html | 33 +++++ .../journeys/MdBenefitsFlowJourneyTest.java | 74 ++++++++-- .../org/mdbenefits/app/testutils/Page.java | 11 +- 10 files changed, 254 insertions(+), 167 deletions(-) create mode 100644 src/main/java/org/mdbenefits/app/submission/conditions/ProgramsIncludeSnapOrTCA.java create mode 100644 src/main/resources/templates/mdBenefitsFlow/ohepNotice.html diff --git a/build.gradle b/build.gradle index f4459940..48ced3ce 100644 --- a/build.gradle +++ b/build.gradle @@ -43,14 +43,9 @@ dependencies { implementation group: 'ch.qos.logback.contrib', name: 'logback-jackson', version: '0.1.5' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.16.2' implementation 'com.opencsv:opencsv:5.9' - - if (profile == 'dev' || useLocalLibrary == 'true') { - implementation fileTree(dir: "$rootDir/../form-flow/build/libs", include: '*.jar') - println "📦 Using local library" - } else { - implementation "org.codeforamerica.platform:form-flow:${formFlowLibraryVersion}" - println "📚Using form flow library ${formFlowLibraryVersion}" - } + + implementation "org.codeforamerica.platform:form-flow:${formFlowLibraryVersion}" + println "📚Using form flow library ${formFlowLibraryVersion}" implementation 'com.amazonaws:aws-encryption-sdk-java:3.0.0' implementation 'org.bouncycastle:bcpg-jdk15on:1.70' diff --git a/src/main/java/org/mdbenefits/app/submission/conditions/ProgramsIncludeSnapOrTCA.java b/src/main/java/org/mdbenefits/app/submission/conditions/ProgramsIncludeSnapOrTCA.java new file mode 100644 index 00000000..d0787e6e --- /dev/null +++ b/src/main/java/org/mdbenefits/app/submission/conditions/ProgramsIncludeSnapOrTCA.java @@ -0,0 +1,20 @@ +package org.mdbenefits.app.submission.conditions; + +import formflow.library.config.submission.Condition; +import formflow.library.data.Submission; +import java.util.ArrayList; +import org.springframework.stereotype.Component; + +@Component +public class ProgramsIncludeSnapOrTCA implements Condition { + + @Override + public Boolean run(Submission submission) { + var inputData = submission.getInputData(); + if (inputData.containsKey("programs[]")) { + var programArr = (ArrayList) submission.getInputData().get("programs[]"); + return programArr.contains("SNAP") || programArr.contains("TCA"); + } + return false; + } +} diff --git a/src/main/resources/flows-config.yaml b/src/main/resources/flows-config.yaml index 638afc11..8956aad1 100644 --- a/src/main/resources/flows-config.yaml +++ b/src/main/resources/flows-config.yaml @@ -19,6 +19,17 @@ flow: nextScreens: - name: choosePrograms choosePrograms: + nextScreens: + - name: expeditedSnapNotice + expeditedSnapNotice: + condition: ProgramsIncludeSnap + nextScreens: + - name: ohepNotice + ohepNotice: + condition: ProgramsIncludeSnapOrTCA + nextScreens: + - name: howThisWorks + howThisWorks: nextScreens: - name: signPost signPost: diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 679239c8..23a6dae6 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -22,6 +22,7 @@ general.none-of-the-above=None of the above general.good-news=Good news! general.i-dont-know=I don't know general.not-interested=No, I\u2019m not interested +general.ok-thanks=Ok, thanks error.error=Error error.uh-oh=Uh oh! error.we-are-sorry=We're sorry, but something went wrong. Please try again later. @@ -193,28 +194,6 @@ final-confirmation.additional-comments-note=Note: We\u2019re unable to share any final-confirmation.feedback-submit-feedback=Submit Feedback final-confirmation.feedback-submitted=Thanks for your feedback! It will help improve this website for future applicants. final-confirmation.answer-feedback-question=Make sure you provide a rating - -# How this works -how-this-works.title=How this works -how-this-works.header=How this works -how-this-works.subtext=This application form should take less than 20 minutes to complete. -how-this-works.we-will-ask=We will ask you about -how-this-works.we-will-ask-l1=Personal information -how-this-works.we-will-ask-l2=People who live with you -how-this-works.we-will-ask-l3=Income -how-this-works.we-will-ask-l4=Expenses -how-this-works.submitting-an-incomplete-app=Submitting an incomplete application (SNAP only) -how-this-works.submitting-an-incomplete-app-l1=If you are applying for SNAP, you will have the choice to submit an incomplete application with only your name, address, and signature. -how-this-works.submitting-an-incomplete-app-l2=By choosing to submit an incomplete application, you may experience longer processing time and more communication with DCFS. -how-this-works.adding-documents=Adding documents -how-this-works.adding-documents-l1=At the end of this application, you will have the option to add documents, like photo ID, pay stubs, or medical bills. -how-this-works.adding-documents-l2=You can use your phone to take photos of paper documents or select a file from your device. -how-this-works.adding-documents-l3=You can always return to our homepage to add documents later, too. -how-this-works.after-you-submit=After you submit -how-this-works.after-you-submit-l1=Your application submission date is the earliest date your benefits can begin. If you submit the application after 4:30 pm Central Time or on a weekend or holiday, your application date will be the next business day. -how-this-works.after-you-submit-l2=Some people also need to create a HiRE account, or have an active HiRE account with the Louisiana Workforce Commission in order to receive SNAP benefits. We'll let you know if we think anyone on this application may also need to create a HiRE account. -how-this-works.after-you-submit-l3=Most programs on this application require an interview after you submit. There will be a phone number to call after you submit your application to schedule an interview. -how-this-works.your-information-is-secure=Your information is secure and will be handled in accordance with our privacy policy. # Timeout Notice timeout-notice.title=Timeout notice timeout-notice.header=After an hour of inactivity, your data will be deleted @@ -273,16 +252,48 @@ choose-programs.rca.short-desc=Get help for refugees choose-programs.rca.desc=
Gives cash to people who are refugees until they get jobs and are able to be financially independent. choose-programs.other=I want to add another program not shown here choose-programs.other.desc=
If you believe there are other benefits you can get or a caseworker at an office believes you can get benefits from another program, choose this option. -# Expedited SNAP -expedited-snap.title=Expedited notice -expedited-snap.header=If you are eligible, you can get expedited food assistance (SNAP) in seven days or less -expedited-snap.what-is=What is expedited SNAP? -expedited-snap.what-is.content=Expedited SNAP means you can get your food benefits more quickly. People who qualify for expedited SNAP can get their EBT card delivered in 7 days or less. -expedited-snap.who-qualifies=Who qualifies for expedited SNAP? -expedited-snap.who-qualifies.content=You may qualify for expedited SNAP if any of these situations are true: -expedited-snap.who-qualifies.li1=Your monthly income is less than $150 and you have $100 or less in personal savings, bank accounts, or cash on hand. -expedited-snap.who-qualifies.li2=The amount you pay for rent or mortgage, and utilities is more than your income and savings. -expedited-snap.who-qualifies.li3=You are a migrant or seasonal farmworker who is not working right now and has $100 or less in personal savings, bank accounts, or cash on hand. +# Expedited SNAP Notice +expedited-snap-notice.title=Expedited SNAP notice +expedited-snap-notice.header=We see you want help with food. +expedited-snap-notice.no-income=If you have no income or very low income, we check to see if you can get benefits in 7 days or less. +expedited-snap-notice.expedited-snap=This is called expedited SNAP. +# OHEP Notice +ohep-notice.title=OHEP Notice +ohep-notice.header=When you apply for SNAP or TCA, we will check to see if you can get help with heating, electric and gas bills. +ohep-notice.ohep=How does this work? +ohep-notice.ohep-l1=A recent law change says that people who are able to get SNAP or TCA benefits are also eligible for help through the Office of Home Energy Programs (OHEP). +ohep-notice.ohep-l2=These programs help with heating, electricity and gas bills. Maryland will pay the company that sends you bills directly. +# How this works +how-this-works.title=How this works +how-this-works.header=How applying works +how-this-works.subtext=Applying usually takes 20 minutes or less. +how-this-works.we-will-ask=We will ask you about: +how-this-works.we-will-ask-l1=Who you are +how-this-works.we-will-ask-l2=People you live with +how-this-works.we-will-ask-l3=Money you earn or get +how-this-works.we-will-ask-l4=Your costs to live +how-this-works.we-will-ask-l5=Property and assets you own +how-this-works.we-will-ask-l6=Documents to help us understand who you are and what your situation is +how-this-works.who-can=Who can apply for benefits +how-this-works.who-can-l1=U.S. citizens can apply to get benefits. Many permanent residents (also called green card holders), refugees and asylees may still be eligible for benefits. They can apply. +how-this-works.who-can-l2=People who are not U.S. citizens or lawful residents cannot apply to get benefits but their income will impact what benefits you or others in your household can get. You will be asked to add non-U.S. citizens and their income later. +how-this-works.after=What happens after you submit +how-this-works.after-l1=After you submit, your application is assigned to a county worker who will reach out to you about next steps. +how-this-works.after-l2=For some benefits you will need to do an interview with a county worker. +how-this-works.how-soon=How soon will you get benefits +how-this-works.how-soon-l1=If you're able to get benefits, the date you submit your application is when your benefits start. +how-this-works.how-soon-l2=You will get them in 30 days or less after you submit your application. +how-this-works.how-soon-l3=For food benefits, if you have no income or very low income, we check to see if you can get benefits in 7 days or less. +how-this-works.minimum-application=If you need and want to submit a minimum application +how-this-works.minimum-application-l1=When you apply to Supplemental Nutrition Program (SNAP), the law says you can choose to submit an application after only adding your name, address and signature. For Temporary Cash Assistance (TCA), you also need to add your birth date. This is a minimum application. +how-this-works.minimum-application-l2=Submitting a minimum application may make getting benefits take longer. +how-this-works.minimum-application-l3=You will still need to answer more questions later. +how-this-works.minimum-application-l4=We encourage answering more questions now to get benefits sooner. +how-this-works.add-documents=How to add documents +how-this-works.add-documents-l1=When applying, you will need to show documents that prove things like money you have and spent. +how-this-works.add-documents-l2=You will be able to add documents, like pay stubs and pay checks later. +how-this-works.add-documents-l3=You can use your phone to take photos of paper documents or add a file from your device. +how-this-works.add-documents-l4=You can also email your documents to: {0} # Signpost signpost.step=Step 1 of 6 signpost.title=Signpost diff --git a/src/main/resources/static/assets/css/custom.css b/src/main/resources/static/assets/css/custom.css index 74fa1d0c..6613b844 100644 --- a/src/main/resources/static/assets/css/custom.css +++ b/src/main/resources/static/assets/css/custom.css @@ -491,3 +491,7 @@ li li { .form-group-spacing-half .form-group { margin-bottom: 4rem; } + +.expedited-snap-notice header { + margin-bottom: 2.5rem; +} diff --git a/src/main/resources/templates/mdBenefitsFlow/expeditedSnapNotice.html b/src/main/resources/templates/mdBenefitsFlow/expeditedSnapNotice.html index d68a43cb..84f4adb5 100644 --- a/src/main/resources/templates/mdBenefitsFlow/expeditedSnapNotice.html +++ b/src/main/resources/templates/mdBenefitsFlow/expeditedSnapNotice.html @@ -1,57 +1,27 @@ - - + +
-
- +
+ - - - - - - -

-
-
- - - - - - -

-
    -
  • -
  • -
  • -
-
-
- -
- + \ No newline at end of file diff --git a/src/main/resources/templates/mdBenefitsFlow/howThisWorks.html b/src/main/resources/templates/mdBenefitsFlow/howThisWorks.html index 1255c328..d4614fda 100644 --- a/src/main/resources/templates/mdBenefitsFlow/howThisWorks.html +++ b/src/main/resources/templates/mdBenefitsFlow/howThisWorks.html @@ -7,91 +7,71 @@
- -
+
- - - - - - -
    -
  • -
  • -
  • -
  • -
-
+ th:replace="~{fragments/cardHeader :: cardHeader(header=#{how-this-works.header})}"/> +

+

+
    +
  • +
  • +
  • +
  • +
  • +
  • +
+ + +

+

+
- - - - - - - -

-

+ + +

+

- - - - - - - -
    -
  • -
  • -
  • -
+ + +

+

+

- - - - - + + +

+

+

+

- -

-

-

+
+ + +

+

+

+

- - - -
-
- -
-

+
+
diff --git a/src/main/resources/templates/mdBenefitsFlow/ohepNotice.html b/src/main/resources/templates/mdBenefitsFlow/ohepNotice.html new file mode 100644 index 00000000..0f7bbed9 --- /dev/null +++ b/src/main/resources/templates/mdBenefitsFlow/ohepNotice.html @@ -0,0 +1,33 @@ + + + + +
+
+
+
+
+
+ + +
+ + +

+

+
+
+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/src/test/java/org/mdbenefits/app/journeys/MdBenefitsFlowJourneyTest.java b/src/test/java/org/mdbenefits/app/journeys/MdBenefitsFlowJourneyTest.java index dad81e7b..a9ecec95 100644 --- a/src/test/java/org/mdbenefits/app/journeys/MdBenefitsFlowJourneyTest.java +++ b/src/test/java/org/mdbenefits/app/journeys/MdBenefitsFlowJourneyTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mdbenefits.app.data.enums.ApplicantObjective; +import org.mdbenefits.app.data.enums.Counties; import org.mdbenefits.app.data.enums.EthnicityType; import org.mdbenefits.app.testutils.AbstractBasePageTest; import org.openqa.selenium.By; @@ -53,19 +54,20 @@ void redirectToMyMDTHINKOnUnsupportedApplicationType() { void redirectToMyMDTHINKOnUnsupportedCounty() { testPage.navigateToFlowScreen("mdBenefitsFlow/county"); // should redirect to MyMDTHINK - testPage.selectFromDropdown("county", "Frederick County"); + testPage.selectFromDropdown("county", Counties.FREDERICK.getDisplayName()); testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo(message("redirect.mdthink.title")); // should not redirect testPage.navigateToFlowScreen("mdBenefitsFlow/county"); - testPage.selectFromDropdown("county", "Baltimore County"); + testPage.selectFromDropdown("county", Counties.BALTIMORE.getDisplayName()); testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo(message("select-app.title")); } @Test void selectNotSureHelpNeededAndChooseProgramFlow() { + preloadCountyScreen(Counties.BALTIMORE.getDisplayName()); // select help needed testPage.navigateToFlowScreen("mdBenefitsFlow/selectHelpNeeded"); testPage.clickContinue(); @@ -94,6 +96,18 @@ void selectNotSureHelpNeededAndChooseProgramFlow() { testPage.clickElementById("programs-SNAP"); testPage.clickContinue(); + + // Expedited Snap Notice + assertThat(testPage.getTitle()).isEqualTo(message("expedited-snap-notice.title")); + testPage.clickContinue(); + + // OHEP Notice + assertThat(testPage.getTitle()).isEqualTo(message("ohep-notice.title")); + testPage.clickButton("Ok, thanks"); + + // How this works + assertThat(testPage.getTitle()).isEqualTo(message("how-this-works.title")); + testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo(message("signpost.title")); } @@ -101,9 +115,13 @@ void selectNotSureHelpNeededAndChooseProgramFlow() { @Test void selectSnapOrTcaHelpAndChooseProgramFlow() { // select help needed - testPage.navigateToFlowScreen("mdBenefitsFlow/selectHelpNeeded"); + testPage.navigateToFlowScreen("mdBenefitsFlow/county"); + testPage.selectFromDropdown("county", Counties.BALTIMORE.getDisplayName()); + testPage.clickContinue(); + testPage.clickElementById("none__checkbox"); testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo("Select help"); + testPage.clickContinue(); assert (testPage.hasErrorText(message("error.missing-general"))); testPage.clickElementById("helpNeeded-FOOD"); @@ -126,20 +144,27 @@ void selectSnapOrTcaHelpAndChooseProgramFlow() { testPage.clickElementById("programs-SNAP"); testPage.clickContinue(); - + assertThat(testPage.getTitle()).isEqualTo(message("expedited-snap-notice.title")); + testPage.clickContinue(); + assertThat(testPage.getTitle()).isEqualTo(message("ohep-notice.title")); + testPage.clickButton("Ok, thanks"); + assertThat(testPage.getTitle()).isEqualTo(message("how-this-works.title")); + testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo(message("signpost.title")); } @Test void selectNonSnapOrTcaAndChooseProgramFlow() { // select help needed - testPage.navigateToFlowScreen("mdBenefitsFlow/selectHelpNeeded"); + testPage.navigateToFlowScreen("mdBenefitsFlow/county"); + testPage.selectFromDropdown("county", Counties.BALTIMORE.getDisplayName()); + testPage.clickContinue(); + testPage.clickElementById("none__checkbox"); testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo("Select help"); + testPage.clickContinue(); assert (testPage.hasErrorText(message("error.missing-general"))); - testPage.clickElementById("helpNeeded-REFUGEE"); - testPage.clickContinue(); // choose program flow @@ -157,7 +182,8 @@ void selectNonSnapOrTcaAndChooseProgramFlow() { testPage.clickElementById("programs-RCA"); testPage.clickContinue(); - + assertThat(testPage.getTitle()).isEqualTo(message("how-this-works.title")); + testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo(message("signpost.title")); } @@ -421,7 +447,7 @@ void completeFlowApplicantOnly() { testPage.clickButton("Apply Now"); assertThat(testPage.getTitle()).isEqualTo("County"); - testPage.selectFromDropdown("county", "Baltimore County"); + testPage.selectFromDropdown("county", Counties.BALTIMORE.getDisplayName()); testPage.clickContinue(); assertThat(testPage.getTitle()).isEqualTo("Select application"); @@ -437,6 +463,18 @@ void completeFlowApplicantOnly() { assertThat(testPage.getTitle()).isEqualTo(message("choose-programs.title")); testPage.clickContinue(); + + // Expedited Snap Notice + assertThat(testPage.getTitle()).isEqualTo(message("expedited-snap-notice.title")); + testPage.clickContinue(); + + // OHEP Notice + assertThat(testPage.getTitle()).isEqualTo(message("ohep-notice.title")); + testPage.clickButton("Ok, thanks"); + + // How this works + assertThat(testPage.getTitle()).isEqualTo(message("how-this-works.title")); + testPage.clickContinue(); // Signpost assertThat(testPage.getTitle()).isEqualTo(message("signpost.title")); @@ -711,6 +749,18 @@ void shouldValidateMailingAddressWhenNoHomeAddress() throws SmartyException, IOE assertThat(driver.findElements(By.className("notice--warning")).get(0).getText()).isEqualTo( message("select-address.notice")); } + + @Test + void howThisWorksShouldShowCorrectEmailForCounty() { + preloadCountyScreen(Counties.BALTIMORE.getDisplayName()); + testPage.navigateToFlowScreen("mdBenefitsFlow/howThisWorks"); + testPage.findAccordionByButtonText("How to add documents").click(); + assertThat(testPage.findElementById("county-document-email").getText()).contains("baltimorecounty.dmc@maryland.gov"); + preloadCountyScreen(Counties.QUEEN_ANNES.getDisplayName()); + testPage.navigateToFlowScreen("mdBenefitsFlow/howThisWorks"); + testPage.findAccordionByButtonText("How to add documents").click(); + assertThat(testPage.findElementById("county-document-email").getText()).contains("qacfia.customeraccount@maryland.gov"); + } void loadUserPersonalData() { testPage.navigateToFlowScreen("mdBenefitsFlow/personalInfo"); @@ -760,4 +810,10 @@ void preloadIncomeScreen() { testPage.clickButton("Yes"); } + + void preloadCountyScreen(String county) { + testPage.navigateToFlowScreen("mdBenefitsFlow/county"); + testPage.selectFromDropdown("county", county); + testPage.clickContinue(); + } } diff --git a/src/test/java/org/mdbenefits/app/testutils/Page.java b/src/test/java/org/mdbenefits/app/testutils/Page.java index 2a37d174..6f11638b 100644 --- a/src/test/java/org/mdbenefits/app/testutils/Page.java +++ b/src/test/java/org/mdbenefits/app/testutils/Page.java @@ -59,7 +59,7 @@ public void clickLink(String linkText) { public void clickButton(String buttonText) { checkForBadMessageKeys(); - WebElement buttonToClick = findElementsByButtonText(buttonText); + WebElement buttonToClick = findElementByButtonText(buttonText); if (buttonToClick == null) { throw new RuntimeException("No button found containing text: " + buttonText); } @@ -325,13 +325,20 @@ public WebElement findElementById(String id) { return driver.findElement(By.id(id)); } - public WebElement findElementsByButtonText(String buttonText) { + public WebElement findElementByButtonText(String buttonText) { return driver.findElements(By.className("button")).stream() .filter(button -> button.getText().contains(buttonText)) .findFirst() .orElse(null); } + public WebElement findAccordionByButtonText(String buttonText) { + return driver.findElements(By.className("accordion__button")).stream() + .filter(button -> button.getText().contains(buttonText)) + .findFirst() + .orElse(null); + } + public boolean elementDoesNotExistById(String id) { try { driver.findElement(By.id(id));