diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 927030a135d..aaca9bc0384 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -92,9 +92,9 @@ body: - type: input id: duedate attributes: - label: 12.) What is your ideal due date for this change request? + label: 12.) Is there a hard deadline associated with this request? description: - placeholder: MM/DD/YYYY or Quarter + placeholder: MM/DD/YYYY validations: required: true diff --git a/.github/workflows/app_store_checks_apple.yml b/.github/workflows/app_store_checks_apple.yml new file mode 100644 index 00000000000..65ead1589db --- /dev/null +++ b/.github/workflows/app_store_checks_apple.yml @@ -0,0 +1,68 @@ +# workflow to check that PR does not break any Apple App Store max file or max character limits +name: "App Store requirement checks" + +on: + pull_request: + branches: + - main + - develop + - 'release/v**' + paths: + - "VAMobile/ios/fastlane/metadata/en-US/**" + - "VAMobile/ios/fastlane/screenshots/**" + +jobs: + check_ios_ipad_pro2_images: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 10 + working_dir: VAMobile/ios/fastlane/screenshots/en-US + counting_function: find . -maxdepth 1 -name "ipadPro2*" -printf '.' | wc -m + check_ios_ipad_pro13_images: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 10 + working_dir: VAMobile/ios/fastlane/screenshots/en-US + counting_function: find . -maxdepth 1 -name "ipadPro13*" -printf '.' | wc -m + check_ios_ipad_pro129_images: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 10 + working_dir: VAMobile/ios/fastlane/screenshots/en-US + counting_function: find . -maxdepth 1 -name "ipadPro12*" -printf '.' | wc -m + check_ios_iphone55_images: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 10 + working_dir: VAMobile/ios/fastlane/screenshots/en-US + counting_function: find . -maxdepth 1 -name "phone5*" -printf '.' | wc -m + check_ios_iphone67_images: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 10 + working_dir: VAMobile/ios/fastlane/screenshots/en-US + counting_function: find . -maxdepth 1 -name "iphone6*" -printf '.' | wc -m + check_ios_description: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 4000 + working_dir: VAMobile/ios/fastlane/metadata/en-US + counting_function: wc -c description.txt | awk '{print $1}' + check_ios_release_notes: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 4000 + working_dir: VAMobile/ios/fastlane/metadata/en-US + counting_function: wc -c release_notes.txt | awk '{print $1}' + check_ios_keyword: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 1000 + working_dir: VAMobile/ios/fastlane/metadata/en-US + counting_function: wc -c keywords.txt | awk '{print $1}' + check_ios_title: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 50 + working_dir: VAMobile/ios/fastlane/metadata/en-US + counting_function: wc -c title.txt | awk '{print $1}' diff --git a/.github/workflows/app_store_checks_google.yml b/.github/workflows/app_store_checks_google.yml new file mode 100644 index 00000000000..8101cfa8c7d --- /dev/null +++ b/.github/workflows/app_store_checks_google.yml @@ -0,0 +1,49 @@ +# workflow to check that PR does not break any Googke Play Store max file or max character limits +name: "App Store requirement checks" + +on: + pull_request: + branches: + - main + - develop + - 'release/v**' + paths: + - "VAMobile/android/fastlane/metadata/android/en-US/**" + +jobs: + check_max_android_phone_screenshots: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 8 + working_dir: VAMobile/android/fastlane/metadata/android/en-US/images/phoneScreenshots + counting_function: ls | wc -l + check_max_android_seven_inch_screenshots: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 8 + working_dir: VAMobile/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots + counting_function: ls | wc -l + check_android_long_description: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 4000 + working_dir: VAMobile/android/fastlane/metadata/android/en-US + counting_function: wc -c full-description.txt | awk '{print $1}' + check_android_short_description: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 80 + working_dir: VAMobile/android/fastlane/metadata/android/en-US + counting_function: wc -c short-description.txt | awk '{print $1}' + check_android_change_log: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 500 + working_dir: VAMobile/android/fastlane/metadata/android/en-US/changelogs + counting_function: wc -c default.txt | awk '{print $1}' + check_android_release_name: + uses: ./.github/workflows/check_max_size.yml + with: + max_size: 50 + working_dir: VAMobile/android/fastlane/metadata/android/en-US + counting_function: wc -c title.txt | awk '{print $1}' diff --git a/.github/workflows/check_max_size.yml b/.github/workflows/check_max_size.yml new file mode 100644 index 00000000000..30b2ea1f9db --- /dev/null +++ b/.github/workflows/check_max_size.yml @@ -0,0 +1,25 @@ +on: + workflow_call: + inputs: + working_dir: + required: true + type: string + max_size: + required: true + type: string + counting_function: + required: true + type: string + +jobs: + check_max_files: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: | + if [[ $(${{ inputs.counting_function }}) -gt ${{ inputs.max_size }} ]] + then + echo "PR exceeds app store limits of ${{ inputs.max_size }} for this check" + exit 1 + fi + working-directory: ${{ inputs.working_dir }} diff --git a/.github/workflows/documentation_accessibility_checks.yml b/.github/workflows/documentation_accessibility_checks.yml index fac60e697cd..9bfd1bd4942 100644 --- a/.github/workflows/documentation_accessibility_checks.yml +++ b/.github/workflows/documentation_accessibility_checks.yml @@ -8,77 +8,73 @@ on: jobs: axe-scan: - name: Acessibility Check + name: Accessibility Check runs-on: ubuntu-latest + outputs: + pages_with_errors: ${{ steps.accessibility_check.outputs.pages_with_errors }} + total_errors: ${{ steps.accessibility_check.outputs.total_errors }} steps: - - uses: actions/checkout@v3 - - name: Setup node and restore yarn cache - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - name: Install Axe CLI globally + run: | + npm install @axe-core/cli -g + - uses: actions/setup-node@v4 with: node-version-file: 'VAMobile/.nvmrc' - cache: 'yarn' - cache-dependency-path: 'VAMobile/yarn.lock' - - name: Clean npm cache - run: npm cache clean --force - - name: Install Axe CLI globally - run: npm install -g @axe-core/cli@latest - - name: Install latest version of chromeDriver - run: npm install -g chromedriver@latest - - name: Run build to generate sitemap + cache: yarn + cache-dependency-path: VAMobile/documentation/yarn.lock + - name: Install ChromeDriver + run: npm install -g chromedriver + - name: Install mobile app modules working-directory: VAMobile run: | yarn install --frozen-lockfile - cd documentation - npx update-browserslist-db@latest - yarn install --frozen-lockfile - yarn build - name: Start web server working-directory: VAMobile/documentation - run: npm start & npx wait-on http://localhost:3000 & + run: | + yarn install --frozen-lockfile + yarn build + yarn start & + npx wait-on http://localhost:3000 & + sleep 10 - name: Check accessibility issues id: accessibility_check run: | # Path to the downloaded sitemap file sitemap_path="VAMobile/documentation/build/sitemap.xml" - - # Counter for the number of accessibility issues detected - num_issues=0 - - # Extract URLs from sitemap and iterate - for url in $(grep -o '[^<]*' "$sitemap_path" | sed 's///'); do - if axe "$url" --chromedriver-path $(npm root -g)/chromedriver/bin/chromedriver --exit; then - echo "No accessibility issues found in $url" - else - echo "Accessibility issues found in $url" - echo "$url" >> accessibility_issues.txt - num_issues=$((num_issues+1)) + + # Counter for urls with errors + pages_with_errors=0 + # Counter for total errors + total_errors=0 + + for url in $(grep -o '[^<]*' "$sitemap_path" | sed 's///'); + do + # save output so that we can send it to std out AND do an operation on it + output=$(axe "$url") + # send output to stdout + echo "${output}" + + # regex number of issues NOTE: grep exits 1 if it finds no match. GH Actions exits the runner if anything exits 1 so we add the || true to overcome that + issues=$(echo "${output}" | grep -oP '\d+(?= Accessibility issues detected)' || true) + + # If issues is not an empty string, there were issues + if [[ ! -z "$issues" ]] + then + pages_with_errors=$((pages_with_errors + 1)) + total_errors=$((total_errors + issues)) fi done - num_issues_issues=$(grep -c 'Accessibility issues found' accessibility_issues.txt) - echo "Accessibility issues detected: $num_issues" - - # Fail the workflow if accessibility issues are detected - if [ "$num_issues" -gt 0 ]; then - echo "Accessibility issues were detected." - exit 1 - else - echo "No accessibility issues were found." - fi + + # Output to runner + echo "pages_with_errors=$pages_with_errors" >> $GITHUB_OUTPUT + echo "total_errors=$total_errors" >> $GITHUB_OUTPUT start_slack_thread: name: Start Slack thread - runs-on: ubuntu-latest - if: ${{ failure() }} needs: axe-scan - steps: - - name: Notify Slack - env: - SLACK_API_TOKEN: ${{ secrets.SLACK_API_TOKEN }} - channel_name: va-mobile-build-alerts - message: 'Accessibility issues detected. See :thread: or <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|workflow run> for results.' - run: | - curl -X POST \ - -H "Authorization: Bearer $SLACK_API_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"channel\":\"$channel_name\",\"text\":\"$message\"}" \ - https://slack.com/api/chat.postMessage \ No newline at end of file + uses: ./.github/workflows/start_slack_thread.yml + secrets: inherit + with: + channel_name: va-mobile-build-alerts + message: 'Accessibility issues detected in the documentation site. Please review and fix. See :thread: or <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|workflow run> for results. Number of pages with errors: ${{ needs.axe-scan.outputs.pages_with_errors }}. Total number of accessibility issues detected: ${{ needs.axe-scan.outputs.total_errors }}' diff --git a/.github/workflows/e2e_android.yml b/.github/workflows/e2e_android.yml index f849764fc03..a2943d82191 100644 --- a/.github/workflows/e2e_android.yml +++ b/.github/workflows/e2e_android.yml @@ -141,7 +141,7 @@ jobs: matrix-e2e-android: if: (!cancelled()) && needs.output_detox_tests_to_run.outputs.output1 != '' - runs-on: macos-latest-xl + runs-on: macos-13 needs: [start_slack_thread, output_detox_tests_to_run] strategy: fail-fast: false @@ -209,7 +209,22 @@ jobs: force-avd-creation: false disable-animations: true arch: x86_64 - avd-name: Pixel_4_XL_API_28 + avd-name: Pixel_6_Pro_API_33 + script: yarn e2e:android-test /e2e/tests/${{matrix.testsuite}} --updateSnapshot + continue-on-error: true + + - name: Run e2e tests for Android - Full Test - Retry + id: run_e2e_tests_full_retry + if: steps.run_e2e_tests.outcome == 'failure' + uses: reactivecircus/android-emulator-runner@v2 + with: + working-directory: VAMobile + api-level: 28 + profile: pixel_6_pro + force-avd-creation: false + disable-animations: true + arch: x86_64 + avd-name: Pixel_6_Pro_API_33 script: yarn e2e:android-test /e2e/tests/${{matrix.testsuite}} --updateSnapshot continue-on-error: true @@ -224,11 +239,13 @@ jobs: force-avd-creation: false disable-animations: true arch: x86_64 - avd-name: Pixel_4_XL_API_28 + avd-name: Pixel_6_Pro_API_33 script: yarn e2e:android-test /e2e/tests/Navigation.e2e AvailabilityFramework.e2e ${{matrix.testsuite}}.e2e --updateSnapshot + continue-on-error: true - name: Run e2e tests for Android on failure - if: failure() && steps.run_e2e_tests_nav_AF.outcome == 'failure' + if: steps.run_e2e_tests_nav_AF.outcome == 'failure' + id: run_e2e_tests_retry uses: reactivecircus/android-emulator-runner@v2 with: working-directory: VAMobile @@ -237,9 +254,9 @@ jobs: force-avd-creation: false disable-animations: true arch: x86_64 - avd-name: Pixel_4_XL_API_28 + avd-name: Pixel_6_Pro_API_33 script: yarn e2e:android-test /e2e/tests/Navigation.e2e AvailabilityFramework.e2e ${{matrix.testsuite}}.e2e --updateSnapshot - + - name: Upload e2e-junit if: failure() || success() uses: actions/upload-artifact@v4 @@ -248,7 +265,7 @@ jobs: path: VAMobile/e2e/test_reports/e2e-junit.xml - name: Upload artifacts on failure - if: failure() || steps.run_e2e_tests.outcome == 'failure' + if: failure() || steps.run_e2e_tests_full_retry.outcome == 'failure' uses: actions/upload-artifact@v4 with: name: detox-artifacts-${{ runner.os }}-${{ github.run_id }}-${{matrix.testsuite}} @@ -256,7 +273,7 @@ jobs: retention-days: 1 - name: Fail workflow if needed(View e2e step for details) - if: steps.run_e2e_tests.outcome == 'failure' + if: steps.run_e2e_tests_full_retry.outcome == 'failure' run: exit 1 output-slack-results-and-update-detox-failure-ticket: diff --git a/.github/workflows/e2e_detox_mapping.yml b/.github/workflows/e2e_detox_mapping.yml index 2c86b02b9af..1e9de7412c8 100644 --- a/.github/workflows/e2e_detox_mapping.yml +++ b/.github/workflows/e2e_detox_mapping.yml @@ -51,108 +51,121 @@ jobs: - name: Get SHA id: get-sha run: echo "sha=$(git rev-parse origin/develop)" >> $GITHUB_OUTPUT - - name: Get file difference by directory - id: changed_files_dir - uses: tj-actions/changed-files@v41 - with: - dir_names: true - json: true - base_sha: "${{ steps.get-sha.outputs.sha }}" - name: Get file difference by file name id: changed_files_file_name uses: tj-actions/changed-files@v41 with: - json: true base_sha: "${{ steps.get-sha.outputs.sha }}" + path: './VAMobile/src' + - name: Check if directory/file is in detox mapping + id: detox_mapping_check + run: | + directoryFound="false" + noFileFound="false" + fileNames=$(jq -r '.files' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + directoryNames=$(jq -r '.directory' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for file in ${{steps.changed_files_file_name.outputs.all_changed_and_modified_files}}; do + baseFile=$(echo $file | sed 's#.*/##') + baseFile=$(echo $baseFile | sed 's/ //g') + fileFound=$(echo $fileNames | jq --arg fileName "$baseFile" '.[$fileName]') + if [[ "$fileFound" == "null" ]]; then + fileDirectory=$(dirname $file) + for directory in $(echo $directoryNames | jq -r 'keys | .[]'); do + if [[ $fileDirectory =~ $directory ]]; then + directoryFound="true" + break + fi + done + if [[ "$directoryFound" == "false" ]]; then + echo "Missing File: $file or missing directory: $fileDirectory" + noFileFound="true" + fi + fi + done + if [[ "$noFileFound" == "true" ]]; then + exit 1 + fi + - name: Check if directory/file is spelled correctly + id: detox_mapping_spell_check + run: | + directoryNames=$(jq -r '.directory' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for directory in $(echo $directoryNames | jq -r 'keys | .[]'); do + if [[ "$(find ${{ github.workspace }}/VAMobile/src -type d -name "$directory")" == "" ]]; then + directoryMisspelled="true" + echo "Directory misspelled: $directory" + exit 1 + fi + done + fileNames=$(jq -r '.files' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for file in $(echo $fileNames | jq -r 'keys | .[]'); do + if [[ "$(find ${{ github.workspace }}/VAMobile/src -type f -name "$file")" == "" ]]; then + fileMisspelled="true" + echo "File misspelled: $file" + exit 1 + fi + done + - name: Check if e2eNames is spelled correctly + id: detox_mapping_e2e_names_spell_check + run: | + directoryNames=$(jq -r '.directory' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for directory in $(echo $directoryNames | jq 'keys | .[]'); do + for e2eTest in $(echo $directoryNames | jq --argjson directory "$directory" --raw-output '.[$directory] | .[]'); do + if [[ "$(find ${{ github.workspace }}/VAMobile/e2e/tests -type f -name "${e2eTest}.e2e.ts")" == "" ]]; then + echo "e2eTests in $directory are not spelled correctly" + echo "$e2eTests misspelled: $e2eTest" + exit 1 + fi + done + done + fileNames=$(jq -r '.files' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for file in $(echo $fileNames | jq 'keys | .[]'); do + for e2eTest in $(echo $fileNames | jq --argjson file "$file" --raw-output '.[$file] | .[]'); do + if [[ "$(find ${{ github.workspace }}/VAMobile/e2e/tests -type f -name "${e2eTest}.e2e.ts")" == "" ]]; then + echo "e2eTests in $file are not spelled correctly" + echo "$e2eTests misspelled: $e2eTest" + exit 1 + fi + done + done - name: Get testing matrix array id: testing_matrix run: | - resp=$(echo ${{steps.changed_files_dir.outputs.all_changed_and_modified_files}} | - jq 'select(contains(["LoginScreen"])) += ["LoginScreen"] | - select(contains(["AppealDetailsScreen"])) += ["Appeals", "AppealsExpanded"] | - select(contains(["NeedHelpData"]) or contains(["NoClaimsAndAppeals"]) or contains(["NoClaimsAndAppealsAccess"]) or contains(["ClaimsAndAppealsListView"]) or contains(["claimsAndAppeals"])) += ["Appeals", "AppealsExpanded", "Claims"] | - select(contains(["ClaimDetailsScreen"]) or contains(["ClaimLettersScreen"]) or contains(["SubmitEvidence"]) or contains(["ClaimsHistoryScreen"])) += ["Claims"] | - select(contains(["ClaimLettersScreen"]) or contains(["decisionLetters"])) += ["DecisionLetters"] | - select(contains(["DisabilityRatingsScreen"]) or contains(["disabilityRating"])) += ["DisabilityRatings", "VeteranStatusCard"] | - select(contains(["Letters"]) or contains(["letters"])) += ["VALetters"] | - select(contains(["Appointments"]) or contains(["appointments"])) += ["Appointments", "AppointmentsExpanded"] | - select(contains(["CernerAlert"]) or contains(["Facilities"])) += ["Cerner"] | - select(contains(["Pharmacy"]) or contains(["prescriptions"])) += ["Prescriptions"] | - select(contains(["SecureMessaging"]) or contains(["secureMessaging"])) += ["Messages"] | - select(contains(["Vaccines"]) or contains(["vaccines"])) += ["VaccineRecords"] | - select(contains(["ContactVAScreen"])) += ["HomeScreen"] | - select(contains(["MilitaryInformationScreen"]) or contains(["militaryService"]) or contains(["Nametag"])) += ["MilitaryInformation", "VeteranStatusCard"] | - select(contains(["PersonalInformationScreen"]) or contains(["demographics"]) or contains(["personalInformation"])) += ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"] | - select(contains(["SettingsScreen"])) += ["SettingsScreen"] | - select(contains(["VeteransCrisisLineScreen"])) += ["VeteransCrisisLine", "SignIn"] | - select(contains(["VeteranStatusScreen"])) += ["VeteranStatusCard"] | - select(contains(["OnboardingCarousel"])) += ["Onboarding"] | - select(contains(["PaymentHistory"]) or contains(["payments"])) += ["Payments"] | - select(contains(["DirectDepositScreen"]) or contains(["directDeposit"])) += ["DirectDeposit"] | - select(contains(["SplashScreen"])) += ["Onboarding", "LoginScreen"] | - select(contains(["auth"])) += ["SignIn"] | - select(contains(["authorizedServices"])) += ["Appeals", "AppealsExpanded", "Appointments", "AppointmentsExpanded", "Claims", "DirectDeposit", "DisabilityRatings", "PersonalInformationScreen", "VALetters", "MilitaryInformation", "Payments", "Prescriptions", "Messages", "VeteranStatusCard"] | - select(contains(["contactInformation"]) or contains(["ContactInformationScreen"])) += ["ContactInformation", "VALetters"] | - select(contains(["NotificationManager"])) += ["SettingsScreen", "PushNotifications", "Onboarding"] | - select(contains(["Types"]) or contains(["VAImage"])) += - ["AvailabilityFramework", "Cerner", "ContactInformation", "VALetters", "LoginScreen", "Onboarding", "ProfileScreen", "PushNotifications", "SettingsScreen", "SignIn", "VaccineRecords", "Claims", "Appeals", "AppealsExpanded", "DisabilityRatings", "Appointments", "AppointmentsExpanded", "Prescriptions", "Messages", "MilitaryInformation", "HomeScreen", "VeteransCrisisLine", "VeteranStatusCard", "DirectDeposit", "Payments", "PersonalInformationScreen"] - | unique') - resp_file=$(echo ${{steps.changed_files_file_name.outputs.all_changed_and_modified_files}} | - jq 'select(contains(["appealData.tsx"])) += ["Appeals", "AppealsExpanded"] | - select(contains(["claimData.tsx"]) or contains(["ClaimsScreen.tsx"]) or contains(["Claims.json"]) or contains(["Claims.ts"]) or contains(["ClaimsAndAppealsSlice"]) - or contains(["ClaimsAndAppealsData"]) or contains(["claims.ts"]) or contains(["claims.tsx"])) += ["Claims", "Appeals", "AppealsExpanded", "DecisionLetters"] | - select(contains(["DisabilityRatingData"]) or contains(["disabilityRating.json"]) or contains(["disabilityRating.ts"])) += ["DisabilityRatings", "VeteranStatusCard"] | - select(contains(["letters.json"]) or contains(["letters.ts"]) or contains(["Letters.ts"]) or contains(["LettersData"]) or contains(["LetterBeneficiaryData"]) or contains(["BasicError"])) += ["VALetters"] | - select(contains(["HealthScreen.tsx"]) or contains(["HealthStackScreens.tsx"])) += ["Appointments", "AppointmentsExpanded", "Cerner", "Prescriptions", "Messages", "VaccineRecords"] | - select(contains(["BenefitsScreen.tsx"]) or contains(["BenefitsStackScreens.tsx"])) += ["DisabilityRating", "Claims", "Appeals", "VALetters"] | - select(contains(["Appointments.json"]) or contains(["Appointments.ts"]) or contains(["AppointmentsSlice.ts"]) or contains(["appointments.ts"]) or contains(["canclAppointment.tsx"]) or contains(["getAppointments.tsx"]) or contains(["appointments.tsx"])) += ["Appointments", "AppointmentsExpanded"] | - select(contains(["getFacilitiesInfo"]) or contains(["FacilityData"])) += ["Cerner"] | - select(contains(["Prescriptions.json"]) or contains(["Prescriptions.ts"]) or contains(["SelectionList"]) or contains(["MultiTouchCard"]) or contains(["RadioGroupModal"])) += ["Prescriptions"] | - select(contains(["SecureMessaging.json"]) or contains(["SecureMessaging.ts"]) or contains(["InLineTextWithIcons"]) - or contains(["MessageAlert"]) or contains(["MessageList"]) or contains(["MessagesCountTag"]) or contains(["secureMessaging.ts"]) or contains(["TextLineWithIcon"])) += ["Messages"] | - select(contains(["vaccine"])) += ["VaccineRecords"] | - select(contains(["EncourageUpdate.tsx"]) or contains(["WhatsNew.tsx"])) += ["HomeScreen"] | - select(contains(["countries"]) or contains(["militaryPostOffices"]) or contains(["militaryStates"]) or contains(["states.ts"]) or contains(["PhoneData"]) or contains(["EmailData"])) += ["ContactInformation"] | - select(contains(["ServiceHistoryData"])) += ["MilitaryInformation", "VeteranStatusCard"] | - select(contains(["demographics"]) or contains(["PersonalInformation"]) or contains(["UserData"]) or contains(["Demographics"])) += ["PeronalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"] | - select(contains(["settingsSlice.ts"])) += ["SettingsScreen"] | - select(contains(["ProfileScreen.tsx"]) or contains(["profile.json"]) or contains(["profile.ts"])) += ["ProfileScreen", "ContactInformation", "MilitaryInformation", "PersonalInformationScreen", "SettingsScreen", "VALetters", "Payments"] | - select(contains(["HomeScreen.tsx"]) or contains(["HomeStackScreens.tsx"])) += ["ContactVAScreen", "ProfileScreen", "VeteranStatusCard"] | - select(contains(["carousel"])) += ["Onboarding"] | - select(contains(["payments.json"]) or contains(["payments.ts"])) += ["Payments"] | - select(contains(["accounts.ts"])) += ["DirectDeposit"] | - select(contains(["PaymentsScreen.tsx"]) or contains(["PaymentsStackScreens.tsx"])) += ["Payments", "DirectDeposit"] | - select(contains(["decisionLetters.ts"]) or contains(["decisionLetters.json"]) or contains(["claimData.tsx"])) += ["Claims"] | - select(contains(["getAuthorizedServices.json"])) += ["Appeals", "AppealsExpanded", "Appointments", "AppointmentsExpanded", "Claims", "DirectDeposit", "DisabilityRatings", "PersonalInformationScreen", "VALetters", "MilitaryInformation", "Payments", "Prescriptions", "Messages", "VeteranStatusCard"] | - select(contains(["notifications.json"]) or contains(["notifications.ts"]) or contains(["Notifications.ts"])) += ["SettingsScreen", "PushNotifications"] | - select(contains(["ErrorComponent"])) += ["Appeals", "AppealsExpanded", "DisabilityRatings", "VALetters", "Appointments", "AppointmentsExpanded", "Prescriptions", "Messages", "VaccineRecords", "ProfileScreen", "ContactInformation", "MilitaryInformation", "PersonalInformationScreen", "SettingsScreen", "Payments"] | - select(contains(["VAModalPicker"])) += ["Appointments", "Messages", "Payments"] | - select(contains(["RadioGroup"])) += ["PersonalInformationScreen", "ContactInformation"] | - select(contains(["VATextInput"]) or contains(["WaygateWrapper"])) += ["AvailabilityFramework"] | - select(contains(["AccordionCollapsible"])) += ["Claims", "Messages"] | - select(contains(["AlertWithHaptics"])) += ["AvailabilityFramework", "VALetters", "Appointments", "Prescriptions", "Messages", "ContactInformation", "DirectDeposit", "Cerner", "Prescriptions", "ContactInformation"] | - select(contains(["AppVersionAndBuild"])) += ["LoginScreen", "SettingsScreen"] | - select(contains(["ClickForActionLink"]) or contains(["ClickToCallPhoneNumber"])) += ["AvailabilityFramework", "Claims", "Appeals", "DisabilityRatings", "Appointments", "Prescriptions", "Messages", "MilitaryInformation", "HomeScreen", "VeteransCrisisLine", "VeteranStatusCard", "DirectDeposit", "Payments", "PersonalInformationScreen"] | - select(contains(["CollapsibleView"])) += ["Appeals", "AppealsExpanded", "Messages", "DirectDeposit"] | - select(contains(["DefaultList"])) += ["Claims", "DisabilityRattings", "VALetters", "ContactInformation", "Appointments", "VaccineRecords", "MilitaryInformation", "PersonalInformationScreen", "DirectDeposit", "Prescriptions", "Payments", "SettingsScreen"] | - select(contains(["LabelTag"])) += ["Prescriptions", "Messages"] | - select(contains(["SimpleList"])) += ["Messages", "Claims", "Appeals", "VALetters", "Apppointments", "Prescriptions", "VaccineRecords"] | - select(contains(["Pagination"])) += ["Appointments", "Claims", "Appeals", "AppealsExpanded", "Prescriptions", "Messages", "Payments", "VaccinesScreen"] | - select(contains(["SnackBar"])) += ["Claims", "Messages", "ContactInformation", "PersonalInformationScreen", "DirectDeposit"] | - select(contains(["VABulletList"])) += ["Appeals", "AppealsExpanded", "Claims", "Prescriptions", "Cerner", "Messages", "Onboarding", "SignIn", "SettingsScreen"] | - select(contains(["CrisisLineButton"])) += ["HomeScreen", "SignIn", "LoginScreen", "VeteransCrisisLine"] | - select(contains(["ActivityButton.tsx"])) += ["HomeScreen", "Prescriptions", "Appointments", "Claims", "Appeals", "DecisionLetters"] | - select(contains(["LinkRow.tsx"])) += ["HomeScreen"] | - select(contains(["Screens.ts"]) or contains(["BasicError"]) or contains(["LoadingComponent"]) or contains(["Box"]) or contains(["HeaderTitle"]) or contains(["LargeNavButton"]) - or contains(["TextArea"]) or contains(["TextLines"]) or contains(["TextView"]) or contains(["backButtonLabels"]) or contains(["common.ts"])) += - ["AvailabilityFramework", "Cerner", "ContactInformation", "VALetters", "LoginScreen", "Onboarding", "ProfileScreen", "PushNotifications", "SettingsScreen", "SignIn", "VaccineRecords", "Claims", "Appeals", "AppealsExpanded", "DisabilityRatings", "Appointments", "AppointmentsExpanded", "Prescriptions", "Messages", "MilitaryInformation", "HomeScreen", "VeteransCrisisLine", "VeteranStatusCard", "DirectDeposit", "Payments", "PersonalInformationScreen"] - | unique ') - - test_matrix=$(echo "$resp" | jq --argjson a "${resp_file}" --argjson b "${resp}" --compact-output '$a + $b | unique') - echo "$test_matrix" - test_matrix=$(echo $test_matrix | jq --compact-output 'map(select(. == ("Appeals", "AppealsExpanded", "Appointments", "AppointmentExpanded", "AvailabilityFramework", "Cerner", "Claims", - "ContactInformation", "DirectDeposit", "DisabilityRatings", "HomeScreen", "VALetters", "LoginScreen", "Messages", "MilitaryInformation", "Navigation", "Onboarding", "Payments", - "PersonalInformationScreen", "Prescriptions", "ProfileScreen", "PushNotifications", "SettingsScreen", "SignIn", "VaccineRecords", - "VeteransCrisisLine", "VeteranStatusCard")))') + firstInstanceFile="true" + directoryNames=$(jq -r '.directory' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + fileNames=$(jq -r '.files' ${{ github.workspace }}/VAMobile/e2e/detoxMapping.json) + for file in ${{steps.changed_files_file_name.outputs.all_changed_and_modified_files}}; do + baseFile=$(echo $file | sed 's#.*/##') + baseFile=$(echo $baseFile | sed 's/ //g') + fileFound=$(echo $fileNames | jq --arg fileName "$baseFile" '.[$fileName]') + if [[ "$fileFound" == "null" ]]; then + fileDirectory=$(dirname $file) + for directory in $(echo $directoryNames | jq -r 'keys | .[]'); do + if [[ "$fileDirectory" =~ "$directory" ]]; then + directoryFound=$(echo $directoryNames | jq --arg fileName "$directory" -r '.[$fileName]') + if [[ "$firstInstanceFile" == "true" ]]; then + test_matrix=$directoryFound + test_matrix=$(echo $test_matrix | jq -c '.') + firstInstanceFile="false" + else + test_matrix=$(echo $test_matrix | jq -c '.') + test_matrix=$(echo $test_matrix | jq --argjson matrix "$directoryFound" '. += $matrix') + fi + break + fi + done + else + if [[ "$firstInstanceFile" == "true" ]]; then + test_matrix=$fileFound + test_matrix=$(echo $test_matrix | jq -c '.') + firstInstanceFile="false" + else + test_matrix=$(echo $test_matrix | jq -c '.') + test_matrix=$(echo $test_matrix | jq --argjson matrix "$fileFound" '. += $matrix') + fi + fi + done + test_matrix=$(echo $test_matrix | jq -c 'unique') echo "TESTING_MATRIX=$test_matrix" >> $GITHUB_OUTPUT echo "TEST_RUN=true" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/native_build_check_android.yml b/.github/workflows/native_build_check_android.yml index 9848b5ae164..0c36acb2995 100644 --- a/.github/workflows/native_build_check_android.yml +++ b/.github/workflows/native_build_check_android.yml @@ -1,5 +1,5 @@ # Tests to see that changes to native files do not break the Android build process - name: '[Code Quality] Check Native Android Builds' +name: '[Code Quality] Check Native Android Builds' on: pull_request: diff --git a/.github/workflows/start_slack_thread.yml b/.github/workflows/start_slack_thread.yml index d1c9c524921..69a1c45f2ff 100644 --- a/.github/workflows/start_slack_thread.yml +++ b/.github/workflows/start_slack_thread.yml @@ -33,10 +33,31 @@ jobs: - name: Search Slack for channel ID id: search_slack run: | - id=$(curl -X GET -H 'Authorization: Bearer '"$SLACK_API_TOKEN"' ' \ + fetch_page() { + last_response=$(curl -X GET -H 'Authorization: Bearer '"$SLACK_API_TOKEN"' ' \ -H 'Content-type: application/x-www-form-urlencoded' \ - https://slack.com/api/conversations.list\?limit=1000 | - jq '.channels[] | .name as $data | select($data == "${{inputs.channel_name}}").id' ) + https://slack.com/api/conversations.list\?limit=1000\&cursor=$cursor | jq .) + } + get_id() { + id=$(jq '.channels[] | .name as $data | select($data == "${{inputs.channel_name}}").id' <<< $last_response) + } + + get_cursor() { + cursor=$(jq '.response_metadata.next_cursor' <<< $last_response) + } + + id="" + cursor="" + last_response="" + fetch_page + get_id + + while [[ -z "$id" ]] + do + get_cursor + fetch_page + get_id + done echo SLACK_CHANNEL_ID=${id} >> $GITHUB_OUTPUT start_thread: name: Start thread diff --git a/VAMobile/.detoxrc.json b/VAMobile/.detoxrc.json index fd6d707132b..45067b8a2a8 100644 --- a/VAMobile/.detoxrc.json +++ b/VAMobile/.detoxrc.json @@ -34,7 +34,7 @@ "emulator": { "type": "android.emulator", "device": { - "avdName": "Pixel_4_XL_API_28" + "avdName": "Pixel_6_Pro_API_33" } } }, diff --git a/VAMobile/android/Gemfile.lock b/VAMobile/android/Gemfile.lock index 9513b805106..24d3020d3c3 100644 --- a/VAMobile/android/Gemfile.lock +++ b/VAMobile/android/Gemfile.lock @@ -10,8 +10,8 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.1010.0) - aws-sdk-core (3.213.0) + aws-partitions (1.1020.0) + aws-sdk-core (3.214.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -19,7 +19,7 @@ GEM aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.172.0) + aws-sdk-s3 (1.176.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -113,7 +113,7 @@ GEM google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) fastlane-plugin-slack_bot (1.4.0) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.74.0) + google-apis-androidpublisher_v3 (0.75.0) google-apis-core (>= 0.15.0, < 2.a) google-apis-core (0.15.1) addressable (~> 2.5, >= 2.5.1) @@ -131,7 +131,7 @@ GEM google-apis-core (>= 0.15.0, < 2.a) google-apis-playcustomapp_v1 (0.16.0) google-apis-core (>= 0.15.0, < 2.a) - google-apis-storage_v1 (0.47.0) + google-apis-storage_v1 (0.48.0) google-apis-core (>= 0.15.0, < 2.a) google-cloud-core (1.7.1) google-cloud-env (>= 1.0, < 3.a) @@ -139,7 +139,7 @@ GEM google-cloud-env (2.2.1) faraday (>= 1.0, < 3.a) google-cloud-errors (1.4.0) - google-cloud-storage (1.52.0) + google-cloud-storage (1.53.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-core (~> 0.13) @@ -148,19 +148,21 @@ GEM google-cloud-core (~> 1.6) googleauth (~> 1.9) mini_mime (~> 1.0) - googleauth (1.11.2) + google-logging-utils (0.1.0) + googleauth (1.12.0) faraday (>= 1.0, < 3.a) - google-cloud-env (~> 2.1) + google-cloud-env (~> 2.2) + google-logging-utils (~> 0.1) jwt (>= 1.4, < 3.0) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.7) + http-cookie (1.0.8) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.2) - json (2.8.2) + json (2.9.0) jwt (2.9.3) base64 mini_magick (4.13.2) diff --git a/VAMobile/documentation/design/Components/Alerts and progress/Snackbar.md b/VAMobile/documentation/design/Components/Alerts and progress/Snackbar.md index 7bd8620b2b7..055ace12bee 100644 --- a/VAMobile/documentation/design/Components/Alerts and progress/Snackbar.md +++ b/VAMobile/documentation/design/Components/Alerts and progress/Snackbar.md @@ -57,5 +57,5 @@ Snackbars provide feedback regarding API interactions at the bottom of the scree - If a screen has bottom navigation, the snackbar should open above the navigation. - There should only ever be one snackbar on the screen. Opening a new snackbar will close the previous snackbar. -### Related +## Related * [Snackbar - Material Design](https://m3.material.io/components/snackbar/overview) diff --git a/VAMobile/documentation/design/Components/Selection and input/Checkbox.md b/VAMobile/documentation/design/Components/Selection and input/Checkbox.md index a90b5f6f822..c57638331d0 100644 --- a/VAMobile/documentation/design/Components/Selection and input/Checkbox.md +++ b/VAMobile/documentation/design/Components/Selection and input/Checkbox.md @@ -47,7 +47,7 @@ Allows users to select one or more items from a list. Checkboxes are an easily u * Refer to the [VA Design System for accessibility considerations](https://design.va.gov/components/form/checkbox#accessibility-considerations) * Screenreaders should announce the name, role, and state of each checkbox. -### Related +## Related * [Checkbox - VA Design System](https://design.va.gov/components/form/checkbox) * [Checkbox - USWDS](https://designsystem.digital.gov/components/checkbox/) * [Checkbox - Material Design](https://m3.material.io/components/checkbox/overview) \ No newline at end of file diff --git a/VAMobile/documentation/design/Components/Selection and input/RadioButton.md b/VAMobile/documentation/design/Components/Selection and input/RadioButton.md new file mode 100644 index 00000000000..a916c93d948 --- /dev/null +++ b/VAMobile/documentation/design/Components/Selection and input/RadioButton.md @@ -0,0 +1,37 @@ +--- +title: Radio button +--- + +Radio buttons allow users to select exactly one choice from a group. + +## Examples + +### Default +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/radio-button--default) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=6703-12221&t=Dj0bTSPSPnEJEFCa-4) + + +### Tile +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/radio-button--tile) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=6703-12221&t=Dj0bTSPSPnEJEFCa-4) + + +### Error +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/radio-button--error) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=6703-12221&t=Dj0bTSPSPnEJEFCa-4) + + +## Usage +[Refer to the VA Design System for usage guidance](https://design.va.gov/components/form/radio-button) + +## Code usage +[Open Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/radio-button--docs) + +## Content considerations +* Refer to the [VA Design System for content considerations](https://design.va.gov/components/form/radio-button#content-considerations) + +## Accessibility considerations +* Refer to the [VA Design System for accessibility considerations](https://design.va.gov/components/form/radio-button#accessibility-considerations) +* Screenreaders should announce the name, role, and state of each radio button. + +## Related +* [Radio button - VA Design System](https://design.va.gov/components/form/radio-button) +* [Radio buttons - USWDS](https://designsystem.digital.gov/components/radio-buttons/) +* [Radio button - Material Design](https://m3.material.io/components/radio-button/overview) \ No newline at end of file diff --git a/VAMobile/documentation/design/Components/Typography/Text.md b/VAMobile/documentation/design/Components/Typography/Text.md new file mode 100644 index 00000000000..4c57c965f81 --- /dev/null +++ b/VAMobile/documentation/design/Components/Typography/Text.md @@ -0,0 +1,44 @@ +--- +title: Text +--- + +Text is a typography component for headings, body copy, and display text. + +## Examples + +### Headings +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/text--heading) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=7101-3675&t=iL0TKvx4LGQO6STF-4) + + +### Body +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/text--body) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=7101-3675&t=iL0TKvx4LGQO6STF-4) + + +### Display +**Open in**: [Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/text--display) | [Figma](https://www.figma.com/design/Zzt8z60hCtdEzXx2GFWghH/%F0%9F%93%90-Component-Library---Design-System---VA-Mobile?node-id=7101-3675&t=iL0TKvx4LGQO6STF-4) + + +## Usage + +### When to use Text +- To add content to a screen. + +### When to consider something else +- For bulleted or numbered lists, use the Text list component (coming soon). +- For smaller Navigation copy (such as the bottom tab bar), apply the Navigation text style directly to a text box. + +### How this component works +- This component is built using the [composite typography tokens](/va-mobile-app/design/Foundation/Design%20tokens/Typography#text-styles). +- Paragraph spacing is set to the minimum recommended values to align with accessibility guidelines ([WCAG SC 1.4.12](https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html)). While you can increase the amount of paragraph spacing, you should not decrease without consulting an accessibility specialist. + +### Choosing between variations +There are 9 variations of the Text component. +- Use a Heading variation (large, medium, small, x-small) for headings. +- Use a Body variation (large, medium, small, x-small) for body copy. +- Use the Display variation for larger display text. + +## Code usage +[Open Storybook](https://department-of-veterans-affairs.github.io/va-mobile-library/?path=/docs/text--docs) + +## Related +- Text list (coming soon) \ No newline at end of file diff --git a/VAMobile/documentation/design/Foundation/Design tokens/Typography.md b/VAMobile/documentation/design/Foundation/Design tokens/Typography.md new file mode 100644 index 00000000000..d31bd87cfb1 --- /dev/null +++ b/VAMobile/documentation/design/Foundation/Design tokens/Typography.md @@ -0,0 +1,46 @@ +--- +title: Typography +sidebar_position: 4 +--- + +# Typography + +Typographical selections intended to meet the highest standards of usability and accessibility, while setting a consistent look and feel in order to convey credibility. + +## Typography tokens + +Typography tokens define each property of a text style. They include font family, style, size, line height, and letter spacing. Math is used to calculate values for size and line height. + +- The base font size is 16. Additional sizes are created using a scale of 1.125 +- The default line height is set to 1.5x the font size. For headings, the line height is set to 1.2x. Line heights follow [accessibility best practices](https://department-of-veterans-affairs.github.io/va-mobile-app/docs/QA/QualityAssuranceProcess/Accessibility/a11y-checklist-ux-designers) and should not be decreased without consulting an accessibility specialist. + +### Primitive + + +### Semantic + + +## Text styles + +Text styles (also known as composite tokens) combine each individual typography token into a defined style. They include styles for headings, body copy, and more. All properties are set using typography tokens, except for paragraph spacing. In the mobile app, spacing tokens are used to define paragraph spacing in a text style. + +### Headings + + +### Body + + +### Other + + +## How to use typography tokens + +Designers and engineers are encouraged to use typography tokens to ensure a consistent look and feel throughout the app. Multiple typography tokens are combined to create composite tokens (aka text styles). To use typography tokens and text styles in the app, we recommend a few different approaches: + +- For Headings and Body copy, use the [Text component](/va-mobile-app/design/Components/Typography/Text). +- For larger Display copy, use the [Text component](/va-mobile-app/design/Components/Typography/Text). +- For smaller Navigation copy (such as the bottom tab bar), apply the Navigation text style directly to a text box. + +**Coming soon** +- For bulleted/numbered lists, there will be a separate component in the future. +- For inline links and styling (bold, italics, etc.), there will be a separate component in the future. \ No newline at end of file diff --git a/VAMobile/documentation/design/intro.md b/VAMobile/documentation/design/intro.md index 1ac79477e1d..9ba259aec87 100644 --- a/VAMobile/documentation/design/intro.md +++ b/VAMobile/documentation/design/intro.md @@ -34,6 +34,10 @@ A system to help you write, design, and build digital services on the VA Mobile ### Selection and input - [Checkbox](/va-mobile-app/design/Components/Selection%20and%20input/Checkbox) +- [Radio button](/va-mobile-app/design/Components/Selection%20and%20input/RadioButton) + +### Typography +- [Text](/va-mobile-app/design/Components/Typography/Text) ----- diff --git a/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/AddressUpdateFlow.md b/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/AddressUpdateFlow.md new file mode 100644 index 00000000000..9b25f4c9893 --- /dev/null +++ b/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/AddressUpdateFlow.md @@ -0,0 +1,335 @@ +--- +title: Address Update Flow +--- + +Updating an address is a two step process with different option for what to send in the request body.Below are three scenarios for updating when the user has entered a valid address with a single match.A valid address with multiple suggested address matches. And when a user has entered what the validation service considers and invalid addres but the user would like to override that and use it anyway. + +## Single match valid address + +```rst +POST /v0/user/addresses/validate +``` + +### Validate Address Request + +```json +{ + "addressLine1": "51 W Weber Rd", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryName": "United States", + "countryCodeIso3": "USA", + "stateCode": "OH", + "zipCode": "43202", + "type": "DOMESTIC", + "addressPou": "CORRESPONDENCE" +} +``` + +### Validate Address Response + +The address has a 100% confidence score. The address that's returned can be sent in a new/update request. In this case the address object in the meta data should be passed along in that request. + +```json +{ + "data": [ + { + "id": "a3add173-380c-4387-9d72-276b755aa980", + "type": "suggested_address", + "attributes": { + "addressLine1": "51 W Weber Rd", + "addressLine2": null, + "addressLine3": null, + "addressPou": "CORRESPONDENCE", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryCodeIso3": "USA", + "internationalPostalCode": null, + "province": null, + "stateCode": "OH", + "zipCode": "43202", + "zipCodeSuffix": "1922" + }, + "meta": { + "address": { + "confidenceScore": 100.0, + "addressType": "Domestic", + "deliveryPointValidation": "CONFIRMED", + "residentialDeliveryIndicator": "RESIDENTIAL" + }, + "validationKey": -1398777841 + } + } + ] +} +``` + +```rst +PUT /v0/user/addresses +``` + +### User Address Request + +```json +{ + "addressMetaData": { + "confidenceScore": 100.0, + "addressType": "Domestic", + "deliveryPointValidation": "CONFIRMED", + "residentialDeliveryIndicator": "RESIDENTIAL" + }, + "addressLine1": "51 W Weber Rd", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryName": "United States", + "countryCodeIso3": "USA", + "stateCode": "OH", + "zipCode": "43202", + "addressPou": "CORRESPONDENCE", + "id": 181513 +} +``` + +#### Addresses Response + +```json +{ + "data": { + "id": "b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "type": "async_transaction_vet360_address_transactions", + "attributes": { + "transactionId": "b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "transactionStatus": "COMPLETED_SUCCESS", + "type": "AsyncTransaction::Vet360::AddressTransaction", + "metadata": [] + } + } +} +``` + +## Multiple match addresses + +```rst +POST /v0/user/addresses/validate +``` + +### Multiple Addresses Request + +```json +{ + "addressLine1": "37 1st st", + "addressType": "DOMESTIC", + "city": "Brooklyn", + "countryName": "United States", + "countryCodeIso3": "USA", + "stateCode": "NY", + "zipCode": "11249", + "type": "DOMESTIC", + "addressPou": "CORRESPONDENCE", +} +``` + +### Multiple Addresses Response + +In this case two address matches are returned and should be displayed to the user so they can pick which they'd like to use. As above the `meta.address` object is passed along in the new/update request. + +```json +{ + "data": [ + { + "id": "56c30b81-9162-4f64-86ce-e7eaa3ae0327", + "type": "suggested_address", + "attributes": { + "addressLine1": "37 N 1st St", + "addressLine2": null, + "addressLine3": null, + "addressPou": "CORRESPONDENCE", + "addressType": "DOMESTIC", + "city": "Brooklyn", + "countryCodeIso3": "USA", + "internationalPostalCode": null, + "province": null, + "stateCode": "NY", + "zipCode": "11249", + "zipCodeSuffix": "3939" + }, + "meta": { + "address": { + "confidenceScore": 100.0, + "addressType": "Domestic", + "deliveryPointValidation": "UNDELIVERABLE" + }, + "validationKey": -73046298 + } + }, + { + "id": "671e752c-3292-4a2b-8747-d42b2bd56055", + "type": "suggested_address", + "attributes": { + "addressLine1": "37 S 1st St", + "addressLine2": null, + "addressLine3": null, + "addressPou": "CORRESPONDENCE", + "addressType": "DOMESTIC", + "city": "Brooklyn", + "countryCodeIso3": "USA", + "internationalPostalCode": null, + "province": null, + "stateCode": "NY", + "zipCode": "11249", + "zipCodeSuffix": "4101" + }, + "meta": { + "address": { + "confidenceScore": 100.0, + "addressType": "Domestic", + "deliveryPointValidation": "CONFIRMED", + "residentialDeliveryIndicator": "MIXED" + }, + "validationKey": -73046298 + } + } + ] +} +``` + +```rst +PUT /v0/user/addresses +``` + +### Multiple Addresses Request 2 + +```json +{ + "addressMetaData": { + "confidenceScore": 100.0, + "addressType": "Domestic", + "deliveryPointValidation": "CONFIRMED", + "residentialDeliveryIndicator": "MIXED" + }, + "addressLine1": "37 S 1st St", + "addressPou": "CORRESPONDENCE", + "addressType": "DOMESTIC", + "city": "Brooklyn", + "countryCodeIso3": "USA", + "stateCode": "NY", + "zipCode": "11249", + "zipCodeSuffix": "4101", + "id": 181513 +} +``` + +### Multiple Addresses Response 2 + +```json +{ + "data": { + "id": "b2e51260-00c9-4db6-80f6-b6c7541a9e54b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "type": "async_transaction_vet360_address_transactions", + "attributes": { + "transactionId": "b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "transactionStatus": "COMPLETED_SUCCESS", + "type": "AsyncTransaction::Vet360::AddressTransaction", + "metadata": [] + } + } +} +``` + +## Overridding and 'invalid' address + +```rst +POST /v0/user/addresses/validate +``` + +### Invalid Address Request + +```json +{ + "addressLine1": "4200 Weasel Rd", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryName": "United States", + "countryCodeIso3": "USA", + "stateCode": "OH", + "zipCode": "43202", + "type": "DOMESTIC", + "addressPou": "CORRESPONDENCE" +} +``` + +### Invalid Address Response + +This response comes back with a 0% confidence score. We can let the user override the validation by passing back the `meta.validationKey` in the new/update request. + +```json +{ + "data": [ + { + "id": "6ba2f94b-c143-40da-8c5d-a76a637945b5", + "type": "suggested_address", + "attributes": { + "addressLine1": "4200 Weasel Rd", + "addressLine2": null, + "addressLine3": null, + "addressPou": "CORRESPONDENCE", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryCodeIso3": "USA", + "internationalPostalCode": null, + "province": null, + "stateCode": "OH", + "zipCode": "43202", + "zipCodeSuffix": null + }, + "meta": { + "address": { + "confidenceScore": 0.0, + "addressType": "Domestic", + "deliveryPointValidation": "MISSING_ZIP" + }, + "validationKey": 377261722 + } + } + ] +} +``` + +```rst +PUT /v0/user/addresses +``` + +### User Addresses Request + +```json +{ + "validationKey": 377261722, + "addressLine1": "4200 Weasel Rd", + "addressType": "DOMESTIC", + "city": "Columbus", + "countryName": "United States", + "countryCodeIso3": "USA", + "stateCode": "OH", + "zipCode": "43202", + "type": "DOMESTIC", + "addressPou": "CORRESPONDENCE", + "id": 181513 +} +``` + +### User Addresses Response + +```json +{ + "data": { + "id": "b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "type": "async_transaction_vet360_address_transactions", + "attributes": { + "transactionId": "b2e51260-00c9-4db6-80f6-b6c7541a9e54", + "transactionStatus": "COMPLETED_SUCCESS", + "type": "AsyncTransaction::Vet360::AddressTransaction", + "metadata": [] + } + } +} +``` diff --git a/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/Auth Diagrams.md b/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/Auth Diagrams.md index 08bf84f414a..fc4ecf8a3a1 100644 --- a/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/Auth Diagrams.md +++ b/VAMobile/documentation/docs/Engineering/BackEnd/Architecture/Auth Diagrams.md @@ -2,10 +2,11 @@ title: Authentication Diagrams --- -### Username and Password Authorization Flow +## Username and Password Authorization Flow + ![Username and Password Authorization Flow](../../../../static/img/backend/username-and-password-authorization-flow.png) -``` +```yaml sequenceDiagram participant User participant App @@ -16,10 +17,11 @@ sequenceDiagram App-->>User: Display auth result ``` -### Biometrics Flow for Username and Password Initial Login +## Biometrics Flow for Username and Password Initial Login + ![Biometrics Flow for Username and Password Initial Login](../../../../static/img/backend/biometrics-flow-for-username-and-password-initial-login.png) -``` +```yaml sequenceDiagram participant User participant Keychain @@ -34,9 +36,11 @@ sequenceDiagram App-->>User: Display auth result ``` -### Biometrics Flow for Username and Password Subsequent Login +## Biometrics Flow for Username and Password Subsequent Login + ![Biometrics Flow for Username and Password Subsequent Login](../../../../static/img/backend/biometrics-flow-for-username-and-password-subsequent-login.png) -``` + +```yaml sequenceDiagram participant User participant Keychain @@ -53,9 +57,11 @@ sequenceDiagram App-->>User: Display auth result ``` -### VA: Health and Benefits Biometrics Initial Login +## VA: Health and Benefits Biometrics Initial Login + ![Health and Benefits Biometrics Initial Login](../../../../static/img/backend/health-and-benefits-biometrics-initial-login.png) -``` + +```yaml sequenceDiagram participant User participant Secure App Storage @@ -80,9 +86,11 @@ sequenceDiagram App-->>User: Display Auth Result ``` -### VA: Health and Benefits Biometrics Subsequent Login +## VA: Health and Benefits Biometrics Subsequent Login + ![Health and Benefits Biometrics Subsequent Login](../../../../static/img/backend/health-and-benefits-biometrics-subsequent-login.png) -``` + +```yaml sequenceDiagram participant User participant Secure App Storage @@ -99,4 +107,4 @@ sequenceDiagram App-->>User: Display Auth Result ``` -In order to regenerate these graphs, add 'mermaid' to the end of the \`\`\` at the beginning of each codeblock \ No newline at end of file +In order to regenerate these graphs, add 'mermaid' to the end of the \`\`\` at the beginning of each codeblock. diff --git a/VAMobile/documentation/docs/Engineering/BackEnd/Testing/Postman.md b/VAMobile/documentation/docs/Engineering/BackEnd/Testing/Postman.md index 82c4ab7d4a9..f92aa537471 100644 --- a/VAMobile/documentation/docs/Engineering/BackEnd/Testing/Postman.md +++ b/VAMobile/documentation/docs/Engineering/BackEnd/Testing/Postman.md @@ -3,7 +3,7 @@ title: Postman --- ## Postman Collection -In the mobile module for vets-api, there is a [postman collection](https://github.com/department-of-veterans-affairs/vets-api/blob/95afe01b82a4041450ca0cb7b6d6552e68c241c5/modules/mobile/docs/MobileAPI%20Integration%20Test%20Collection.postman_collection.json) that can be downloaded and used to run commands against +In the mobile module for vets-api, there is a [postman collection](https://github.com/department-of-veterans-affairs/vets-api/blob/master/modules/mobile/docs/Mobile%20Endpoints.postman_collection.json) that can be downloaded and used to run commands against the staging instances. In order to use the collection, download the json file. After installing [Postman](https://www.postman.com), go to the collection section of Postman. From there, you can click "import", and drag @@ -13,4 +13,4 @@ the file into the import window. The top directory `Mobile Endpoints` contains the settings for authorization. After aquiring a [token](./ApiTokens.md), click on the directory itself, open the `Authorization` tab, and paste the token here. Every endpoint within the directory will now use -this token for the requests. \ No newline at end of file +this token for the requests. diff --git a/VAMobile/documentation/docs/Engineering/DevOps/Automation Code Docs/GitHub Actions/ReleaseIssues.md b/VAMobile/documentation/docs/Engineering/DevOps/Automation Code Docs/GitHub Actions/ReleaseIssues.md index 2b61093dc3f..b15131e1289 100644 --- a/VAMobile/documentation/docs/Engineering/DevOps/Automation Code Docs/GitHub Actions/ReleaseIssues.md +++ b/VAMobile/documentation/docs/Engineering/DevOps/Automation Code Docs/GitHub Actions/ReleaseIssues.md @@ -49,3 +49,20 @@ Because the release is tied into a commit and not the current state of the branc 5. Run `git pull` to ensure you have the latest changes 6. Tag the branch with the version we're trying to release: `git tag -a RC-vX.XX.0-XXXXXX-XXXX -m RC-vX.XX.0-XXXXXX-XXXX` 7. Push the tag `git push origin RC-vX.XX.0-XXXXXX-XXXX` + +## Release Ticket Failure + +Outlined below are the steps to follow when the automation to create a release ticket and Slack coordination thread fails due to issues like incorrect GitHub username assignment. + +1. Update the [release_ticket](https://github.com/department-of-veterans-affairs/va-mobile-app/blob/develop/.github/ISSUE_TEMPLATE/release_ticket.md) template with the correct GitHub username and push to Github +2. Determine the version number of the build (vX.X.X) and RC tag RC-vX.XX.0-XXXXXX-XXXX you want to delete +3. Delete the local release candidate tag: `git tag --delete RC-vX.XX.0-XXXXXX-XXXX` +4. Delete the remote tag: `git push --delete origin ` +5. Delete the local release branch : `git branch -d ` +6. Delete the remote release branch: `git push origin --delete ` +7. Manually ran the [new_release_branch](https://github.com/department-of-veterans-affairs/va-mobile-app/blob/develop/.github/workflows/new_release_branch.yml) workflow using workflow_dispatch. +8. Confirm that: + 1. New RC tag. + 2. New release branch. + 3. release ticket has been created. + 4. Slack thread coordination has been triggered on va-mobile-app channel. \ No newline at end of file diff --git a/VAMobile/documentation/docs/Engineering/DevOps/Making pull requests.md b/VAMobile/documentation/docs/Engineering/DevOps/Making pull requests.md index 8183976f1bb..1720705cafa 100644 --- a/VAMobile/documentation/docs/Engineering/DevOps/Making pull requests.md +++ b/VAMobile/documentation/docs/Engineering/DevOps/Making pull requests.md @@ -4,18 +4,23 @@ position: 2 --- ## Install git + [Git - Installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + ### On Mac + Open terminal and run `git —version` If you do not already have it installed it will prompt you to install it. ### On Windows + [Git - Downloading Package](https://git-scm.com/download/win) ## sublime text -[Sublime Text - Text Editing, Done Right](https://www.sublimetext.com/) +[Sublime Text - Text Editing, Done Right](https://www.sublimetext.com/) ## Install GitHub Desktop + [GitHub Desktop | Simple collaboration from your desktop](https://desktop.github.com/) [Getting started with GitHub Desktop - GitHub Docs](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/overview/getting-started-with-github-desktop) @@ -23,157 +28,152 @@ Open terminal and run `git —version` If you do not already have it installed i Open the zip file. When Finder comes up, you will want to drag the application into the Applications folder -![](../../../static/img/making_changes/ss1.png) +![Mac downloads directory](../../../static/img/making_changes/ss1.png) You can then open the app from either the finder window or using quick search `⌘ + Space` and type GitHub desktop You may see a warning the first time you open the app, click Open -![](../../../static/img/making_changes/ss2.png) +![example warning](../../../static/img/making_changes/ss2.png) When the app opens it may ask you to log into GitHub. Once you are logged in you should see a screen like this: -![](../../../static/img/making_changes/ss3.png) +![getting started screen](../../../static/img/making_changes/ss3.png) Wait until your repositories list loads on the right -![](../../../static/img/making_changes/ss4.png) +![list of repositories in the app](../../../static/img/making_changes/ss4.png) Scroll or use search until you find `department-of-veterans-affairs/va-mobile-app` When you click on the repository name, you should get an option to clone the repository -![](../../../static/img/making_changes/ss5.png) +![highlighted text for the va-mobile-app repo](../../../static/img/making_changes/ss5.png) Click the clone button to pop up a modal. Choose the local path on your machine where you want to save it and click the clone button -![](../../../static/img/making_changes/ss6.png) +![example of fetching by URL](../../../static/img/making_changes/ss6.png) -![](../../../static/img/making_changes/ss7.png) +![cloning loading screen](../../../static/img/making_changes/ss7.png) -![](../../../static/img/making_changes/ss8.png) +![status update screen with no changes](../../../static/img/making_changes/ss8.png) ## Create a new branch + To create a branch, you first need to know what base you need. The base of the branch determines what code changes are available to your branch when you start it. If we think of develop as a trunk, then the two branches shown below will have slightly different code checked in because of where they are branched from. You can see that the yellow branch will have started and be missing two gray commits that the blue branch will have because of where it was based. -![](../../../static/img/making_changes/ss10.png) +![example branching model with dots and lines](../../../static/img/making_changes/ss10.png) This means we need to pay attention the to base branch when we make new branches. -In most cases, you will probably have two cases to choose from : +In most cases, you will probably have two cases to choose from: + 1. I am making new changes that need to get added to the app or wherever, but NOT for the release ticket. For these you will likely need to base off of the `develop` branch. 2. I am making change FOR a release ticket, such as what’s new or content changes that have to be in the next release. For these you will need to base it on the correct release branch and will need to do some extra work. ### If your new branch is based on `develop` + Click on the Current Branch tab at the top -![](../../../static/img/making_changes/ss11.png) +![comparing your branch to develop](../../../static/img/making_changes/ss11.png) There are a few ways to create a new branch. You can type in a branch name in the search, then click the `New Branch` or the `Create New Branch` button. -![](../../../static/img/making_changes/ss12.png) - +![searching for a branch name](../../../static/img/making_changes/ss12.png) You can also press `⌘ + Shift + N` to create a new branch from anywhere in the application. You will see this modal. Just enter your branch name and click `Create Branch` -![](../../../static/img/making_changes/ss13.png) +![creating a new branch](../../../static/img/making_changes/ss13.png) Once you have created your branch, you should see this: -![](../../../static/img/making_changes/ss14.png) +![status screen showing no changes](../../../static/img/making_changes/ss14.png) You can now start making your changes to the repository. There is no need to publish your branch at this time, we can make all of your changes first and then publish it. ### If your changes are for a release + You will need to copy the release branch from the remote repository to start. This is called pulling a remote. To do is in GH desktop, you will simple search for the branch on the server and double click it. Click on the current branch tab, type `release` into the search and double click the release branch you want to update. It should pre prefixed with `origin/` like you see below for `origin/release/v1.12.0`. Click the branch name and your GH Desktop will pull down that branch history and change to that branch for you. -![](../../../static/img/making_changes/ss15.png) +![searching for a release branch](../../../static/img/making_changes/ss15.png) Now that we have our starting place, we can then create a branch based on `release/v1.12.0`. Create a new branch any of the ways listed above, but when the create branch modal pops up, you will need to change the base branch from develop to the correct release branch. -![](../../../static/img/making_changes/ss16.png) +![release branch appearing in search results](../../../static/img/making_changes/ss16.png) Click the `release/vx.y.x` that is the correct version and click `Create Branch` You now have a branch that will update for only the release branch that you can now start making changes on. ## Open the repository in Sublime text + Open Sublime Text from your applications folder or using quick search `⌘ + Space` In GitHub Desktop, click on the Current Repository tab at the top and right click on `va-mobile-app`. Select `Reveal in Finder` -![](../../../static/img/making_changes/ss17.png) +![opening the repo](../../../static/img/making_changes/ss17.png) Click on the `va-mobile-app` text at the top of finder so that a folder icon pops up. Drag that icon onto the sublime text icon that should be visible in your dock area. -![](../../../static/img/making_changes/ss18.gif) +![a mac desktop opening a code editor](../../../static/img/making_changes/ss18.gif) Sublime text should open a new window with your files in a sidebar on the left and a black text editor in the middle. You can now navigate the files in the repo in order to make your changes. ## Making and saving changes + Once you have made changes to the files you want to update, you will need to save the changes in sublime to make them show up in GH Desktop. You can Save All changes with `Option(⌥) + ⌘ + S` If you now look at GH Desktop, you should see a list of changes in the left-hand tab. -![](../../../static/img/making_changes/ss19.png) +![changes active in the app UI](../../../static/img/making_changes/ss19.png) If you click on a file, you can see the set of changes for each file (called a diff). Green indicates a line was added. Red indicates the line was deleted. -![](../../../static/img/making_changes/ss20.png) -![](../../../static/img/making_changes/ss21.png) +![example of viewing changed files](../../../static/img/making_changes/ss20.png) +![another example of viewing changed files](../../../static/img/making_changes/ss21.png) ## Committing Changes + Once we have all the changes we want to make, we need to save the changes to our git history so that the repository is updated. We call this committing changes to git. To do so in GH Desktop, simple check the box to the left of each file that you want to save changes from. You can save all the changes at once or split up changes in a couple of commits if you want to add changes by some type of change grouping (i.e. all image updates in one commit, all text updates in a second). Its not necessary to do more than one commit, but if you make a lot of changes it can be helpful to break it up in case you make a mistake you need to undo(revert). -![](../../../static/img/making_changes/ss22.png) +![three circled checkboxes](../../../static/img/making_changes/ss22.png) Once you have selected all the changes you want to commit, you will need to enter a summary message and commit the changes. Add a summary message that explains the changes in case someone needs to review the history and can easily tell what you were up to. In this case I am making my message “update what’s new text for iOS and android”. Click `Commit to ` to save the changes to git. -![](../../../static/img/making_changes/ss23.png) +![example commit](../../../static/img/making_changes/ss23.png) GH Desktop should then show you a screen that says No local changes again. If you have more changes or more commits, go ahead and do those now. Once you have all the changes you want to make, you will need to publish your branch so that you can make a pull request. ## Publish your branch + In order to make a Pull Request and add your changes back onto the base branch, you will need to copy your local branch up onto the GitHub server. To do this, you just need to go to the GH Desktop app, and click either the `Publish Branch` tab at the top or the `Publish Branch` button in the Publish your branch area. The branch should get pushed up to the repository and you should then see an area to `Create Pull Request` -![](../../../static/img/making_changes/ss24.png) +![publish branch options circled](../../../static/img/making_changes/ss24.png) -![](../../../static/img/making_changes/ss25.png) +![status screen showing no changes](../../../static/img/making_changes/ss25.png) Now the only thing left to do is create a pull request so that others can review your changes before they are added to the repository. ## Create a Pull Request + Click the Create Pull Request button. This should open a browser window that takes you to a Pull Request template in the repository. -![](../../../static/img/making_changes/ss26.png) +![Github UI with an open pull request](../../../static/img/making_changes/ss26.png) Follow the template to add changes and explain to reviewers what is being added or subtracted from the code base. You should also connect the ticket to this PR request so that the two move through the ZenHub pipelines together. To do this, you will need the [ZenHub Browser Extension for Chrome and Firefox](https://www.zenhub.com/extension?utm_term=zenhub%20chrome%20extension&utm_campaign=Brand&utm_source=adwords&utm_medium=ppc&hsa_acc=8479887336&hsa_cam=14577630669&hsa_grp=127140912459&hsa_ad=544547662444&hsa_src=g&hsa_tgt=kwd-865948335962&hsa_kw=zenhub%20chrome%20extension&hsa_mt=e&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAuP-OBhDqARIsAD4XHpeArSRObIEEcSVF64ECWjuMc6zvVhYdBryYnkuwlxx1H2SghSnixR4aAlVyEALw_wcB) installed. Once this is installed, there should be a button under the text input for you to search the issues in our repo. -![](../../../static/img/making_changes/ss27.png) +![connecting an issue to zenhub](../../../static/img/making_changes/ss27.png) Click `Connect Issue` and search for the ticket by title or number -![](../../../static/img/making_changes/ss28.png) -![](../../../static/img/making_changes/ss29.png) +![searching for an issue](../../../static/img/making_changes/ss28.png) +![finding the issue you need](../../../static/img/making_changes/ss29.png) Once you have connected the issue, you should see something like this: -![](../../../static/img/making_changes/ss30.png) - -Next, you will need to add any specific reviewers you need. If you don’t know, you can leave it empty. Click the reviewers section on the right-hand side and search for folks you need to review. - -![](../../../static/img/making_changes/ss31.png) -![](../../../static/img/making_changes/ss32.png) - -Click on the user’s name to add them as a reviewer. You should see a check next to their name if you’re successful - -![](../../../static/img/making_changes/ss33.png) - -Click outside the box when you are done adding people. You should now see a list of reviewers with orange dots next to their names to indicate that they have not yet started a review - -![](../../../static/img/making_changes/ss34.png) +![github UI with the issue connected](../../../static/img/making_changes/ss30.png) Click the green `Create pull request` button to finish your work and send the PR for review. diff --git a/VAMobile/documentation/docs/Engineering/DevOps/Overview.md b/VAMobile/documentation/docs/Engineering/DevOps/Overview.md index cf370ccc995..ce9363015bf 100644 --- a/VAMobile/documentation/docs/Engineering/DevOps/Overview.md +++ b/VAMobile/documentation/docs/Engineering/DevOps/Overview.md @@ -4,6 +4,7 @@ postion: 1 --- ## Releases + Our releases are made live every other Tuesday morning. A GitHub Action runs every Tuesday morning to check and see if there is a staged build ready for developer release in the Apple App Store. For Play Store, it checks to see if there is a newer build than the production lane waiting in the Pre-Prod Stash lane. If there is, they are released to production at that time and sends a message to the main va-mobile-app channel in DSVA slack. If not, it completes silently. Release branches are cut by an Action every other Wednesday that follows a release. The release branch acts as a freeze on the develop branch for the next release that allows QA to run regressions from a static point and allows any last-minute changes to be added before being merged to main and build for review in the stores. This release branch being created then starts automation that creates the release ticket in GitHub and assigns the relevant people. @@ -13,13 +14,19 @@ Releases coincide with the last day of a sprint and new release branches are cut Release process approval ends with an authorized person (currently a VA Product Owner) releasing the app for build and upload to the stores by running the `/approve` command in the automated release ticket. This is accomplish by adding a comment to the issue in the form of `/approve vX.Y.Z` where X.Y.Z is the next version number. This version number should be present in the title of the ticket. Once the release is approved, the build system will create and upload production versions of the app to the App Stores for review. Barring any issues, these should be released on the next Tuesday when the release Action runs. -##### NOTE: *Because chrontab notation doesn't have a way to schedule a job at an interval , i.e. every two weeks, the release action has to be scheduled for EVERY Tuesday. This means that if the approve command is run before the Tuesday in the middle of the sprint, the releases will go out a week early.* + +:::note +Because chrontab notation doesn't have a way to schedule a job at an interval , i.e. every two weeks, the release action has to be scheduled for EVERY Tuesday. This means that if the approve command is run before the Tuesday in the middle of the sprint, the releases will go out a week early. +::: ## QA Builds + ### Daily Builds + Regular QA builds are distributed every weekday. These builds are based on the most current commit on the develop branch in order to provide QA with the most up-to-date versions as possible and can be augmented with the other types of builds. ### On Demand Builds + In addition to our automatically scheduled builds, we also have the ability to create QA or UAT builds at any time from any branch, also known as On Demand builds. The [On Demand Build Workflow](https://github.com/department-of-veterans-affairs/va-mobile-app/actions/workflows/on_demand_build.yml), which can also be found on the left hand sidebar in [GitHub Actions](https://github.com/department-of-veterans-affairs/va-mobile-app/actions), allows us to specify a branch and an environment to create a build from ([steps listed out in QA documentation](https://department-of-veterans-affairs.github.io/va-mobile-app/docs/QA/QualityAssuranceProcess/Resources#on-demand-build)). ### On Demand Build Script diff --git a/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx b/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx deleted file mode 100644 index 388fb7bdf94..00000000000 --- a/VAMobile/documentation/docs/Engineering/FrontEnd/CustomHooks/useIsScreenReaderEnabled.mdx +++ /dev/null @@ -1,8 +0,0 @@ -import HooksInfo from '../../../../src/components/HooksInfo' - -export const exampleString = `const screenReaderEnabled = useIsScreenReaderEnabled()\n -const setFocus = useCallback(() => { - if (ref.current && screenReaderEnabled) {} -}` - - diff --git a/VAMobile/documentation/docs/Engineering/FrontEnd/RemoteConfig/index.md b/VAMobile/documentation/docs/Engineering/FrontEnd/RemoteConfig/index.md new file mode 100644 index 00000000000..6412b2003ee --- /dev/null +++ b/VAMobile/documentation/docs/Engineering/FrontEnd/RemoteConfig/index.md @@ -0,0 +1,48 @@ +--- +title: Remote Config +--- + +Remote Configuration (Feature Flipper/Toggles) + +## Background + +Due of the growing complexity of the Flagship app and the types of features we are incorporating, we have an increasing need for the ability to manage aspects of the app remotely. In mobile, as in web, the best way to do this is by incorporating a remote configuration that allows features, behavior, and appearance aspects of the app to be updated without issuing a full app update. + +[Firebase's Remote Config](https://firebase.google.com/docs/remote-config) product allows us to store and modify values remotely, enable or disable certain app features, as well as roll them out to a certain percentage of users at a time. + +## Environments + +The values set in Firebase are for production only. Any overrides we'll use for development or in QA will be stored and overridden in our FE code in `src/utils/remoteConfig.ts`. The app will only fetch values from Firebase if it detects that our `ENVIRONMENT === 'Production'`. Otherwise it will use the defaults for staging/dev that are set in `remoteConfig.ts` + +## Guidelines + +1. The feature for consideration should be relatively self-contained and require a minimal amount of logic to switch between its enabled and disabled state (e.g. request appointment flow) +2. Addition of a new remote config value should be approved by the mobile platform team +3. Values should be named using snake case (i.e. `my_test_value`) +4. Values should be named using the feature by itself, and not any boolean indicating prefix or suffix such as `is` or `enabled` + +## Data Schema + +While the number of remote config values we have will be small, it's important that we set some guidelines about naming conventions and structure of our configurations as they grow. + +Firebase allows for 4 different data types: + +* String +* Boolean +* Number +* JSON + +For the foreseeable future, we'll only make use of the Boolean data type. + +The data schema will be a flat structure consisting of booleans: + +### Example + +```json +{ + "SIS": true, + "prescriptions": false, + "appointment_requests": false +} +``` + diff --git a/VAMobile/documentation/docs/Flagship design library/Components/Selection and Input/Form Elements/RadioButton.md b/VAMobile/documentation/docs/Flagship design library/Components/Selection and Input/Form Elements/RadioButton.md index e8bcbdd9cc0..2449adc1a5a 100644 --- a/VAMobile/documentation/docs/Flagship design library/Components/Selection and Input/Form Elements/RadioButton.md +++ b/VAMobile/documentation/docs/Flagship design library/Components/Selection and Input/Form Elements/RadioButton.md @@ -2,31 +2,4 @@ title: Radio button --- -Radio buttons allow users to select exactly one choice from a group. - -## Examples - -### Master component - - -### Examples - - -## Usage - -[Refer to the VA Design System for usage guidance](https://design.va.gov/components/form/radio-button) - -## Content considerations -* Refer to the [VA Design System for content considerations](https://design.va.gov/components/form/radio-button/#content-considerations) - -## Accessibility considerations -* Refer to the [VA Design System for accessibility considerations](https://design.va.gov/components/form/radio-button/#accessibility-considerations) -* Screenreaders should announce the name, role, and state of each checkbox. - -## Code usage -Link to Storybook coming soon - -## Related -* [Radio button - VA Design System](https://design.va.gov/components/form/radio-button) -* [Radio buttons - USWDS](https://designsystem.digital.gov/components/radio-buttons/) -* [Radio button - Material Design](https://m3.material.io/components/radio-button/overview) \ No newline at end of file +See documentation in [Design System](/va-mobile-app/design/Components/Selection%20and%20input/RadioButton). \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Components/documentation-guide.md b/VAMobile/documentation/docs/Flagship design library/Components/documentation-guide.md new file mode 100644 index 00000000000..a4eed3ed9c5 --- /dev/null +++ b/VAMobile/documentation/docs/Flagship design library/Components/documentation-guide.md @@ -0,0 +1,42 @@ +--- +title: Documentation Guide +sidebar_position: 1 +--- + +# Flagship Component Documentation Guide + +## Who does the work? + +Updating the documentation for a new component should be a collaboration between the design system team and the Flagship team when the component either currently lives within the design system or will be moved there in the future. It is recommended that you reach out to the Design System team to determine if a new component will remain in the Flagship team’s library or if it will be moved to the design system. + +If a new component is exclusive to the VAHB app and will **not** become part of the design system, the Flagship team member should move forward with detailed documentation of the component. When possible, please align with the current documentation outline that is being used by the design system team for consistency (see the [button component](https://department-of-veterans-affairs.github.io/va-mobile-app/design/Components/Buttons%20and%20links/Button) as an example). + +:::note +Guidance on writing documentation and templates for the documentation are included in the “Documentation resources” section below. +::: + +If the new component **will** eventually live within the design system, please coordinate with the Design System team so that they can update the [design system documentation](https://department-of-veterans-affairs.github.io/va-mobile-app/design/Intro) with the new component. The Flagship team member should document how the component is used with the VAHB mobile app, while the Design System team will focus on documenting how the component can be used universally. + +* **Design system team** documents: + * The various ways a component can be used. +* **Flagship team** documents: + * How the mobile app uses the component specifically (where, when, etc.). + +## Where does the documentation live? +We have an area on the documentation site for the [Flagship design library](https://department-of-veterans-affairs.github.io/va-mobile-app/docs/Intro#). Within that section, there is another section for [Components](https://department-of-veterans-affairs.github.io/va-mobile-app/docs/Flagship%20design%20library/Components/Overview). Currently, most of the documentation is engineering-focused and is not used to document the components (or their usage) themselves. Please use this area of the documentation site to house this documentation moving forward. + +Reference the list in the “What should we document?” section below as a guide to what should be updated (including the name of the page itself) vs. what should be added as a new page on the documentation site. + +## What should we document? +The design system team is responsible for documenting any components where the master lives (or will eventually live) within their library. The Flagship team is responsible for documenting any components where the master lives within their library. + +However, in many cases, the master component lives within the design system’s library (or will in the future) and the Flagship team will use instances of the master component in a specific way. In those cases, the Flagship team should document how they are using the component within the VA: Health and Benefits mobile app. + +## Documentation resources +We have several resources available to assist with writing documentation. + +* [Writing component documentation](https://department-of-veterans-affairs.github.io/va-mobile-app/design/About/Contributing%20to%20the%20design%20system/writing-component-documentation/) (documentation / guidance) +* [Documentation template](https://github.com/department-of-veterans-affairs/va-mobile-app/issues/new?assignees=&labels=component-documentation%2C+ux&template=common_component.md&title=Common+Component+Ticket%3A%5BInsert+name+of+component+here%5D) (in Github) + * _Can copy the markdown out of the template_ +* [Documentation template](https://docs.google.com/document/d/1DJoTdwXxUrjmCv8S9XwNvn4uVbd66jyE0XUwqzgZtc4/edit#heading=h.bhvl2fy62vsv) (in Google Docs) + * _Can use this and then convert to markdown_ \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Content/content-style-guide.md b/VAMobile/documentation/docs/Flagship design library/Content/content-style-guide.md index 30d4a3eb393..847c4a99610 100644 --- a/VAMobile/documentation/docs/Flagship design library/Content/content-style-guide.md +++ b/VAMobile/documentation/docs/Flagship design library/Content/content-style-guide.md @@ -4,15 +4,15 @@ sidebar_position: 1 --- ## Voice and tone -We follow the [VA design system content principles](https://design.va.gov/content-style-guide/content-principles). In following these principles, we create consistent, clear, and customer-centered content that is based on Veteran feedback. +We follow the [VA design system content principles](https://design.va.gov/content-style-guide/content-principles). In following these principles, we create consistent, clear, and user-centered content that is based on Veteran feedback. -In addition, we follow [VA plain language standards](https://design.va.gov/content-style-guide/content-principles/plain-language) to help Veterans and their families find and understand the information they need. +In addition, we follow [VA plain language standards](https://design.va.gov/content-style-guide/plain-language/) to help Veterans and their families find and understand the information they need. Since we create content for health-related features, we also follow the [VA content guidelines for health content](https://design.va.gov/content-style-guide/health-content). ## Accessible and inclusive language We write for all Veterans and those who care for them. Therefore, we use people-first language that is inclusive of the wide range of abilities and experiences of our users. -We avoid words that are insensitive to the disabilities faced by our users. For example, we don’t use “view” or “see,” since a number of our users are blind or low-vision. We also avoid idioms, such as “at your fingertips” or “give an arm or a leg.” Not only are idioms often insensitive to Veterans’ experience but also idioms don’t follow plain language standards. +We avoid words that are insensitive to the disabilities faced by our users. For example, we don’t use “see” since a number of our users are blind or low-vision. We also avoid idioms, such as “at your fingertips” or “give an arm or a leg.” Not only are idioms often insensitive to Veterans’ experience, but also idioms don’t follow plain language standards. Resources to consider: @@ -26,25 +26,22 @@ We follow [VA.gov content style guide rules](https://design.va.gov/content-style ### Capitalization -- Screen names are title case. With the new navigation design, we will [change to sentence case for screen titles](https://github.com/department-of-veterans-affairs/va-mobile-app/issues/2575). -- All other headings in the app are sentence case. -- Buttons - - For native actions, we use title case for iOS and all caps for Android. - - For interface buttons, we use sentence case. - +- For native actions, we use title case for iOS and all caps for Android. +- For interface buttons, we use sentence case. ### Times and time zones -- We currently use `AM` and `PM` (both letters capitalized and no punctuation) since this is default formatting in React Native. +- Due to default formatting in React Native, when times/time zones aren't hardcoded, our formatting differs from VA.gov. For example, React Native formats as `AM` and `PM` (both letters capitalized and no punctuation) and `EST` (three-letter format). +- When times and timezones are hardcoded, we follow the VA.gov content style guide. ## Word choice, spelling, and naming conventions ### Content briefs -We use [content briefs](https://github.com/department-of-veterans-affairs/va.gov-team/tree/master/products/content/content-briefs) to ensure consistent word choice and usage with other VA teams. VA Sitewide Content and IA team creates content briefs, sometimes in collaboration with the VA Mobile App content designer. +We use [content briefs](https://github.com/department-of-veterans-affairs/va.gov-team/tree/master/products/content/content-briefs) to ensure consistent word choice and usage with other VA teams. VA.gov's content team creates content briefs, sometimes in collaboration with the VA Mobile App content designer. ### [Word List](https://design.va.gov/content-style-guide/word-list) We use standard American English spelling in Merriam-Webster Dictionary. The words on the VA.gov word list are exceptions or need clarification. ### [Naming conventions](https://design.va.gov/content-style-guide/naming-and-labels) -We follow VA.gov content style guide’s [rules for naming and labels](https://design.va.gov/content-style-guide/naming-and-labels) for tools, products, benefits, offices, and programs. -In most cases, VA.gov will have already established a name for a tool, benefit, etc. For cases in which we would like to suggest a different name or need help with naming an app-specific feature, we work closely with VA Sitewide Content team to ensure alignment. +We follow VA.gov content style guide’s [rules for naming and labels](https://design.va.gov/content-style-guide/naming-and-labels) for tools, products, benefits, offices, and programs. +In most cases, VA.gov will have already established a name for a tool, benefit, etc. For cases in which we'd like to suggest a different name or need help with naming an app-specific feature, we work closely with VA.gov's content team to ensure alignment. ## Error messages VA.gov’s design system includes a section on [how to help users recover from errors](https://design.va.gov/patterns/help-users-to/recover-from-errors). It details the structure, style, and tone for error and informational messages. diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/_category_.json b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/_category_.json deleted file mode 100644 index a5092ce2692..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Icons", - "position": 3 -} - diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/_iconPathSection.mdx b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/_iconPathSection.mdx deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/checkboxIcons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/checkboxIcons.md deleted file mode 100644 index d25ce6cd4d8..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/checkboxIcons.md +++ /dev/null @@ -1,18 +0,0 @@ -import { ReactComponent as CheckBoxEmpty} from '@componentsDocs/VAIcon/svgs/checkbox/CheckBoxEmpty.svg'; -import { ReactComponent as CheckBoxError} from '@componentsDocs/VAIcon/svgs/checkbox/CheckBoxError.svg'; -import { ReactComponent as CheckBoxFilled} from '@componentsDocs/VAIcon/svgs/checkbox/CheckBoxFilled.svg'; -import { ReactComponent as CheckBoxIntermediate} from '@componentsDocs/VAIcon/svgs/checkbox/CheckBoxIntermediate.svg'; -import IconsPathSection from '@site/src/components/IconsPathSection' - -# Checkbox - -:::info - -::: - -Name | Icon | File Name -:---: | :---: | :---: -Checkbox Empty | | CheckBoxEmpty.svg -Checkbox Error | | CheckBoxError.svg -Checkbox Filled | | CheckBoxFilled.svg -Checkbox Intermediate | | CheckBoxIntermediate.svg diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/commonIcons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/commonIcons.md deleted file mode 100644 index afa6f5a49c3..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/commonIcons.md +++ /dev/null @@ -1,48 +0,0 @@ -import { ReactComponent as Add} from '@componentsDocs/VAIcon/svgs/Add.svg'; -import { ReactComponent as Building} from '@componentsDocs/VAIcon/svgs/Building.svg'; -import { ReactComponent as CheckMark} from '@componentsDocs/VAIcon/svgs/CheckMark.svg'; -import { ReactComponent as CircleCheckMark} from '@componentsDocs/VAIcon/svgs/CircleCheckMark.svg'; -import { ReactComponent as Compose} from '@componentsDocs/VAIcon/svgs/Compose.svg'; -import { ReactComponent as ExclamationTriangle} from '@componentsDocs/VAIcon/svgs/ExclamationTriangle.svg'; -import { ReactComponent as ExternalLink} from '@componentsDocs/VAIcon/svgs/ExternalLink.svg'; -import { ReactComponent as Folder} from '@componentsDocs/VAIcon/svgs/Folder.svg'; -import { ReactComponent as Inbox} from '@componentsDocs/VAIcon/svgs/Inbox.svg'; -import { ReactComponent as Info} from '@componentsDocs/VAIcon/svgs/Info.svg'; -import { ReactComponent as Minus} from '@componentsDocs/VAIcon/svgs/Minus.svg'; -import { ReactComponent as PaperClip} from '@componentsDocs/VAIcon/svgs/PaperClip.svg'; -import { ReactComponent as Phone} from '@componentsDocs/VAIcon/svgs/Phone.svg'; -import { ReactComponent as QuestionMark} from '@componentsDocs/VAIcon/svgs/QuestionMark.svg'; -import { ReactComponent as Remove} from '@componentsDocs/VAIcon/svgs/Remove.svg'; -import { ReactComponent as Reply} from '@componentsDocs/VAIcon/svgs/Reply.svg'; -import { ReactComponent as Trash} from '@componentsDocs/VAIcon/svgs/Trash.svg'; -import { ReactComponent as Unread} from '@componentsDocs/VAIcon/svgs/Unread.svg'; -import { ReactComponent as VideoCamera} from '@componentsDocs/VAIcon/svgs/VideoCamera.svg'; -import IconsPathSection from '@site/src/components/IconsPathSection' - -# Common - -:::info - -::: - -Name | Icon | File Location -:---: | :---: | :---: -Add | | Add.svg -Building | | Building.svg -Check Mark | | CheckMark.svg -Check Mark in Circle | | CircleCheckMark.svg -Compose | | Compose.svg -Exclamation Triangle | | ExclamationTriangle.svg -External Link | | ExternalLink.svg -Folder | | Folder.svg -Inbox | | Inbox.svg -Info | | Info.svg -Minus | | Minus.svg -Paper Clip | | PaperClip.svg -Phone | | Phone.svg -Question Mark | | QuestionMark.svg -Remove | | Remove.svg -Reply | | Reply.svg -Trash | | Trash.svg -Unread | | Unread.svg -Video Camera | | VideoCamera.svg \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/index.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/index.md deleted file mode 100644 index 61943e252b1..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Icons ---- - -Icons are used sparingly throughout the VA mobile app as a way to enhance user understanding and wayfinding. - - - -* [Icons in Figma](https://www.figma.com/file/QVLPB3eOunmKrgQOuOt0SU/%F0%9F%93%90-DesignLibrary2.0---VAMobile?type=design&node-id=4156%3A7676&t=LWuS4oyNuplsuZBa-1) \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/linksIcons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/linksIcons.md deleted file mode 100644 index df891a21a5a..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/linksIcons.md +++ /dev/null @@ -1,27 +0,0 @@ -import { ReactComponent as Calendar} from '@componentsDocs/VAIcon/svgs/links/Calendar.svg'; -import { ReactComponent as Chat} from '@componentsDocs/VAIcon/svgs/links/Chat.svg'; -import { ReactComponent as CircleExternalLink} from '@componentsDocs/VAIcon/svgs/links/CircleExternalLink.svg'; -import { ReactComponent as CirclePhone} from '@componentsDocs/VAIcon/svgs/links/CirclePhone.svg'; -import { ReactComponent as Directions} from '@componentsDocs/VAIcon/svgs/links/Directions.svg'; -import { ReactComponent as PhoneTTY} from '@componentsDocs/VAIcon/svgs/links/PhoneTTY.svg'; -import { ReactComponent as RightArrowBlueCircle} from '@componentsDocs/VAIcon/svgs/links/right-arrow-blue-circle.svg'; -import { ReactComponent as Text} from '@componentsDocs/VAIcon/svgs/links/Text.svg'; -import IconsPathSection from '@site/src/components/IconsPathSection' - -# Links - -:::info - -::: - - -Name | Icon | File Name -:---: | :---: | :---: -Calendar | | Calendar.svg -Chat | | Chat.svg -Directions | | Directions.svg -External Link in Circle | | CircleExternalLink.svg -Phone in Circle | | CirclePhone.svg -Phone TTY | | PhoneTTY.svg -Right Arrow Blue Circle | | right-arrow-blue-circle.svg -Text | | Text.svg diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/radioBtnIcons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/radioBtnIcons.md deleted file mode 100644 index 2945864240d..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/radioBtnIcons.md +++ /dev/null @@ -1,15 +0,0 @@ -import { ReactComponent as RadioEmpty} from '@componentsDocs/VAIcon/svgs/radio/RadioEmpty.svg'; -import { ReactComponent as RadioFilled} from '@componentsDocs/VAIcon/svgs/radio/RadioFilled.svg'; -import IconsPathSection from '@site/src/components/IconsPathSection' - - -# Radio Button - -:::info - -::: - -Name | Icon | File Name -:---: | :---: | :---: -Radio Empty/Disabled | | RadioEmpty.svg -Radio Filled | | RadioFilled.svg diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/webviewIcons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/webviewIcons.md deleted file mode 100644 index b4a17ae0c8e..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/Icons/webviewIcons.md +++ /dev/null @@ -1,16 +0,0 @@ -import { ReactComponent as ExternalLink} from '@componentsDocs/VAIcon/svgs/ExternalLink.svg'; -import { ReactComponent as Lock} from '@componentsDocs/VAIcon/svgs/Lock.svg'; -import { ReactComponent as Redo} from '@componentsDocs/VAIcon/svgs/Redo.svg'; -import IconsPathSection from '@site/src/components/IconsPathSection' - -# Webview - -:::info - -::: - -Name | Icon | File Name -:---: | :---: | :---: -External Link | | ExternalLink.svg -Lock | | Lock.svg -Redo | | Redo.svg diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/color-palette.md b/VAMobile/documentation/docs/Flagship design library/Foundation/color-palette.md deleted file mode 100644 index 2432de774a3..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/color-palette.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Color palette -sidebar_position: 2 ---- - -The VA mobile app has two color themes: Light and Dark. [The VA mobile app themes](https://www.figma.com/file/bGO6g5cCvWycrNjoK66PXc/VA-Mobile-Design-Tokens?node-id=151%3A76) use colors from the [VA style guide](https://design.va.gov/foundation/color-palette), and only deviate if necessary for accessibility purposes. - - - -**Themes** -- [Light theme in Figma](https://www.figma.com/file/yXL0MkEKyAPGXPZqRH0VFZ/VA-Mobile-light-theme?node-id=183%3A441) -- [Dark theme in Figma](https://www.figma.com/file/gOhb2kZvoQiXiGigqWZhnx/VA-Mobile-dark-theme?node-id=183%3A441) - -## Front-end -Colors in code can be found under `src/styles/themes/VAColors.ts`. Any new colors should be added `src/styles/themes/VAColors.ts` and then used in `src/styles/themes/standardTheme.ts` or `src/styles/themescolorSchemes.ts` - -Some text, components(ex. snackbar), or icons use different colors than the default color set for each font. You can find the general guidelines for what colors to use for most text, components, and icons in the [VA Mobile app Design Library](https://www.figma.com/file/QVLPB3eOunmKrgQOuOt0SU/VAMobile-DesignLibrary1.0-%F0%9F%93%90?node-id=501%3A40&t=P62TR9FmT9E6a4O2-1). \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/color.md b/VAMobile/documentation/docs/Flagship design library/Foundation/color.md new file mode 100644 index 00000000000..c8e31eab793 --- /dev/null +++ b/VAMobile/documentation/docs/Flagship design library/Foundation/color.md @@ -0,0 +1,6 @@ +--- +title: Color +sidebar_position: 2 +--- + +See documentation in [Design System](/va-mobile-app/design/Foundation/Design%20tokens/Color). \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/icons.md b/VAMobile/documentation/docs/Flagship design library/Foundation/icons.md new file mode 100644 index 00000000000..673709ccdac --- /dev/null +++ b/VAMobile/documentation/docs/Flagship design library/Foundation/icons.md @@ -0,0 +1,6 @@ +--- +title: Icons +sidebar_position: 5 +--- + +See documentation in [Design System](/va-mobile-app/design/Foundation/Icons). \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/layout.md b/VAMobile/documentation/docs/Flagship design library/Foundation/layout.md deleted file mode 100644 index c45ed11022f..00000000000 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/layout.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Layout -sidebar_position: 4 ---- - - - -* [Grid in Figma](https://www.figma.com/file/QVLPB3eOunmKrgQOuOt0SU/%F0%9F%93%90-DesignLibrary2.0---VAMobile?type=design&node-id=3859%3A7737&t=EuJmlpcIxjibtKua-1) \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/spacing.md b/VAMobile/documentation/docs/Flagship design library/Foundation/spacing.md new file mode 100644 index 00000000000..8a53ad7844b --- /dev/null +++ b/VAMobile/documentation/docs/Flagship design library/Foundation/spacing.md @@ -0,0 +1,6 @@ +--- +title: Spacing +sidebar_position: 4 +--- + +See documentation in [Design System](/va-mobile-app/design/Foundation/Design%20tokens/Spacing). \ No newline at end of file diff --git a/VAMobile/documentation/docs/Flagship design library/Foundation/typography.md b/VAMobile/documentation/docs/Flagship design library/Foundation/typography.md index 2451440b90e..102a8092899 100644 --- a/VAMobile/documentation/docs/Flagship design library/Foundation/typography.md +++ b/VAMobile/documentation/docs/Flagship design library/Foundation/typography.md @@ -1,70 +1,6 @@ --- title: Typography -sidebar_position: 5 +sidebar_position: 3 --- -Typography generally follows [VA.gov’s guidance](https://design.va.gov/foundation/typography) with some adjustments. - -* The mobile app doesn’t use CSS pixel measurements to define font sizes. Instead, we use points (PT) on iOS and density-independent pixels (DP) on Android. This allows our fonts to scale appropriately for all screen densities across devices. Below are resources that describe this in more detail: - * [Guidance from W3C](https://w3c.github.io/wcag2ict/#guidance-when-applying-css-pixel-to-non-web-documents-and-software) - * [Fonts in mobile apps for developers](https://www.skoumal.com/en/fonts-in-mobile-apps-for-developers/) - * [Mobile design 101: pixels, points and resolutions](https://medium.com/@fluidui/mobile-design-101-pixels-points-and-resolutions-f60413035243) -* With native and OS specific components, we utilize OS defined typography. - - - - - -## Front-end -To support the common usage of colors for each font style, defaults colors have been set for each type of font under `src/styles/themes/standardTheme.ts`(See `buildTypography` function). Colors for each font style are based on the [Design Tokens - Design Library](https://www.figma.com/file/bGO6g5cCvWycrNjoK66PXc/%F0%9F%93%90-DesignTokens1.0---Library---VAMobile?node-id=115%3A157&t=RpifEcByzqSp4on7-1) file. \ No newline at end of file +See documentation in [Design System](/va-mobile-app/design/Foundation/Design%20tokens/Typography). \ No newline at end of file diff --git a/VAMobile/documentation/docs/QA/QualityAssuranceProcess/index.md b/VAMobile/documentation/docs/QA/QualityAssuranceProcess/index.md index d73a766cef1..0cf90b5199a 100644 --- a/VAMobile/documentation/docs/QA/QualityAssuranceProcess/index.md +++ b/VAMobile/documentation/docs/QA/QualityAssuranceProcess/index.md @@ -37,7 +37,7 @@ The following testing methods will be employed during development and testing of | Integration Testing | In contrast to unit tests, integration tests run across individual modules of code to validate that separately developed modules are working together properly. Integration tests are also used to validate that the VA Mobile App front end interfaces with other systems and services, such as the VA.gov APIs, as designed. | Developers | | End-to-end Testing | End-to-end testing, or system testing, looks to validate that the system as a whole works as intended. These tests are similar in nature to integration tests but are focused on the superset of delivered software and its connections to other systems. End-to-end testing will be done prior to release and will consist of both manual and automated testing to ensure adequate coverage of the delivered functionality. | Developers, QA, Product | | User Acceptance Testing | User Acceptance Testing, sometimes referred to as "UAT" or just Acceptance Testing, involves the product team and other stakeholders interacting with the application to simulate real-world usage and signing off that the delivered software functions as defined in the designs and requirements. We will leverage pre-production distribution tools such as TestFlight to get the app in the hands of stakeholders to facilitate Acceptance Testing. | Product, Stakeholder community | -| Accessibility Testing | Accessibility is a major requirement for the VA Mobile App and requires additional consideration beyond the standard testing process. QA will include accessibility checks in the manual functional testing activities. For a more detailed plan on accessibility testing approach see the [Mobile Accessibility Testing Plan](https://github.com/department-of-veterans-affairs/va.gov-team/blob/master/products/va-mobile-app/testing/Accessibility%20Test%20Plan.md). | Developers, QA | +| Accessibility Testing | Accessibility is a major requirement for the VA Mobile App and requires additional consideration beyond the standard testing process. QA will include accessibility checks in the manual functional testing activities. For a more detailed plan on accessibility testing approach see the [Mobile Accessibility Testing Plan](../QualityAssuranceProcess/Accessibility/testing-plan.md). | Developers, QA | | Compatibility Testing | Software may behave differently depending on the specific device and operating system that it is running on. In order to validate that the software developed will work as intended across a variety of devices we will also perform manual functional testing of each feature on a variety of physical devices and OSs as defined on the [compatibility page](../QualityAssuranceProcess/Compatibility.md). ## Testing accounts and data diff --git a/VAMobile/documentation/docs/UX/Foundations/Information-Architecture.md b/VAMobile/documentation/docs/UX/Foundations/Information-Architecture.md index 4f3fd64b994..ee1952145be 100644 --- a/VAMobile/documentation/docs/UX/Foundations/Information-Architecture.md +++ b/VAMobile/documentation/docs/UX/Foundations/Information-Architecture.md @@ -37,9 +37,9 @@ Understanding what’s guiding the app’s current information architecture and ### Sitemap/flow diagram A sitemap is a planning tool that visually shows how information will be grouped and labeled, where content will be located, and how a user will move through the app. This adaptation of a standard sitemap includes the system display logic for screens that have variants, key actions (buttons, links), common processes and points where it makes use of native mobile integrations. **This is the source of truth for the app’s IA.** - + -[VA Mobile App - Detailed sitemap 2.0 (FigJam)](https://www.figma.com/file/TEEgHdlibzCilCj4LviHVF/VA-Mobile-app---Detailed-Sitemap-2.0?type=whiteboard&node-id=0%3A1&t=NOXEk15mCNO0XQ5Q-1) +[VA Mobile App - Detailed sitemap 2.0](https://www.figma.com/design/bTPnmfYSuj1ICA4AqHMiQg/Sitemap%2FFlow-Diagram-2.0---%F0%9F%9A%A2-Shipped-(FJ)---VA-Mobile?node-id=0-1&t=5sKeYKmQ1pUk0rr1-1) diff --git a/VAMobile/documentation/docs/UX/How-We-Work/designing-ui.md b/VAMobile/documentation/docs/UX/How-We-Work/designing-ui.md index b81043d94ed..ef42b3d57ef 100644 --- a/VAMobile/documentation/docs/UX/How-We-Work/designing-ui.md +++ b/VAMobile/documentation/docs/UX/How-We-Work/designing-ui.md @@ -58,7 +58,7 @@ Once designs are ready to be handed off to the engineering team, you can review ### IA/Flows 1. Document the IA of your feature & where it lives in the app - - See: [Determining Navigation & Information Architecture Placement for New VA Mobile App Features](https://docs.google.com/document/d/1XQcYxnCifloaBFNKL2C9JNS7KIj6wEhb4VokPGxBZU8/edit) and [VA Mobile app: Detailed sitemap (future state 9-30-22](https://app.mural.co/invitation/mural/adhoccorporateworkspace2583/1655989910332?sender=u28718b63c8993f515e0b2240&key=6f96be43-72c9-4ae6-b529-a2941eb14ba9) + - See: [VA Mobile app - IA documentation](https://department-of-veterans-affairs.github.io/va-mobile-app/docs/UX/Foundations/Information-Architecture#ia-documentation) for the app's sitemap and guidance on adding new features 2. Update category screens, if needed 3. Document intended flow 4. Defined back labels and screen title diff --git a/VAMobile/documentation/docs/UX/Resources.md b/VAMobile/documentation/docs/UX/Resources.md index acc0eb1e275..7a3a2b42c48 100644 --- a/VAMobile/documentation/docs/UX/Resources.md +++ b/VAMobile/documentation/docs/UX/Resources.md @@ -56,6 +56,8 @@ VA Mobile app [UX resources on github](https://github.com/department-of-veterans * This shows all the MVP components laid out as a library visible and inspectable in Invision. Deprecated July 2021. * [Library style sheets (deprecated)](https://adhoc.invisionapp.com/share/AX108RJZPB6E#/screens/445194518) Shows the components from the design library. Deprecated July 2021. +### Figma 1.0 (before 2022) +* [Figma files](https://github.com/department-of-veterans-affairs/va.gov-team/tree/master/products/va-mobile-app/ux-design/figma-files-1.0) that represent MVP feature work, prior to restructuring the IA & Navigation. Deprecated Q1 2022. ### Components * [MVP Mobile App UI Styles on Google Docs (deprecated)](https://docs.google.com/document/d/1VC-CLWnhevB8HLBBHPwkSJvECn8EBie8HOkJylKE1lo/edit?usp=sharing) \ No newline at end of file diff --git a/VAMobile/documentation/yarn.lock b/VAMobile/documentation/yarn.lock index 9aac5a74730..82095c26a34 100644 --- a/VAMobile/documentation/yarn.lock +++ b/VAMobile/documentation/yarn.lock @@ -6878,9 +6878,9 @@ multicast-dns@^7.2.5: thunky "^1.0.2" nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== negotiator@0.6.3: version "0.6.3" diff --git a/VAMobile/e2e/detoxMapping.json b/VAMobile/e2e/detoxMapping.json new file mode 100644 index 00000000000..5562c4e229b --- /dev/null +++ b/VAMobile/e2e/detoxMapping.json @@ -0,0 +1,408 @@ +{ + "directory": { + "appointments": ["Appointments", "AppointmentsExpanded"], + "authorizedServices": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "Claims", + "DirectDeposit", + "DisabilityRatings", + "PersonalInformationScreen", + "VALetters", + "MilitaryInformation", + "Payments", + "Prescriptions", + "Messages", + "VeteranStatusCard" + ], + "claimsAndAppeals": ["Appeals", "AppealsExpanded", "Claims"], + "contactInformation": ["ContactInformation", "VALetters"], + "decisionLetters": ["DecisionLetters"], + "demographics": ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"], + "directDeposit": ["DirectDeposit"], + "disabilityRating": ["DisabilityRatings", "VeteranStatusCard"], + "facilities": ["Cerner"], + "letters": ["VALetters"], + "militaryService": ["MilitaryInformation", "VeteranStatusCard"], + "notifications": ["SettingsScreen", "PushNotifications"], + "payments": ["Payments"], + "personalInformation": ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"], + "prescriptions": ["Prescriptions"], + "secureMessaging": ["Messages"], + "types": [ + "AvailabilityFramework", + "Cerner", + "ContactInformation", + "VALetters", + "LoginScreen", + "Onboarding", + "ProfileScreen", + "PushNotifications", + "SettingsScreen", + "SignIn", + "VaccineRecords", + "Claims", + "Appeals", + "AppealsExpanded", + "DisabilityRatings", + "Appointments", + "AppointmentsExpanded", + "Prescriptions", + "Messages", + "MilitaryInformation", + "HomeScreen", + "VeteransCrisisLine", + "VeteranStatusCard", + "DirectDeposit", + "Payments", + "PersonalInformationScreen" + ], + "vaccines": ["VaccineRecords"], + "components": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "LoginScreen": ["LoginScreen"], + "AppealDetailsScreen": ["Appeals", "AppealsExpanded"], + "ClaimDetailsScreen": ["Claims"], + "ClaimLettersScreen": ["Claims"], + "ClaimsAndAppealsListView": ["Appeals", "AppealsExpanded", "Claims"], + "ClaimsHistoryScreen": ["Claims"], + "NeedHelpData": ["Appeals", "AppealsExpanded", "Claims"], + "NoClaimsAndAppeals": ["Appeals", "AppealsExpanded", "Claims"], + "NoClaimsAndAppealsAccess": ["Appeals", "AppealsExpanded", "Claims"], + "ClaimsScreen": ["Appeals", "AppealsExpanded", "Claims"], + "DisabilityRatingsScreen": ["DisabilityRatings", "VeteranStatusCard"], + "Letters": ["VALetters"], + "Appointments": ["Appointments", "AppointmentsExpanded"], + "CernerAlert": ["Cerner"], + "HealthHelp": ["Cerner"], + "Pharmacy": ["Prescriptions"], + "SecureMessaging": ["Messages"], + "Vaccines": ["VaccineRecords"], + "ContactVAScreen": ["HomeScreen"], + "ProfileScreen": [ + "ProfileScreen", + "ContactInformation", + "MilitaryInformation", + "PersonalInformationScreen", + "SettingsScreen", + "VALetters", + "Payments" + ], + "ContactInformationScreen": ["ContactInformation", "VALetters"], + "MilitaryInformationScreen": ["MilitaryInformation", "VeteranStatusCard"], + "PersonalInformationScreen": ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"], + "VeteransCrisisLineScreen": ["VeteransCrisisLine", "SignIn"], + "VeteranStatusScreen": ["VeteranStatusCard"], + "OnboardingCarousel": ["Onboarding"], + "DirectDepositScreen": ["DirectDeposit"], + "PaymentHistory": ["Payments"], + "SplashScreen": ["Onboarding", "LoginScreen"], + "BenefitsScreen": ["DisabilityRatings", "Claims", "Appeals", "VALetters"], + "HealthScreen": ["Appointments", "AppointmentsExpanded", "Cerner", "Prescriptions", "Messages", "VaccineRecords"], + "HomeScreen": ["HomeScreen", "ProfileScreen", "VeteranStatusCard"], + "SettingsScreen": ["SettingsScreen"], + "PaymentsScreen": ["Payments", "DirectDeposit"], + "slices": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "translations": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "utils": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "device": [], + "BiometricsPreferenceScreen": [], + "SyncScreen": [], + "WebviewScreen": [], + "styles": [] + }, + "files": { + "accounts.ts": ["DirectDeposit"], + "appointments.ts": ["Appointments", "AppointmentsExpanded"], + "claims.ts": ["Claims", "Appeals", "AppealsExpanded"], + "common.ts": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "countries.ts": ["ContactInformation"], + "militaryPostOffices.ts": ["ContactInformation"], + "militaryStates.ts": ["ContactInformation"], + "screens.ts": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "secureMessaging.ts": ["Messages"], + "states.ts": ["ContactInformation"], + "appointments.json": ["Appointments", "AppointmentsExpanded"], + "claims.json": ["Claims", "Appeals", "AppealsExpanded"], + "contactInformation.json": ["ContactInformation", "VALetters"], + "decisionLetters.json": ["DecisionLetters"], + "disablityRating.json": ["DisabilityRatings"], + "getAuthorizedServices.json": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "Claims", + "DirectDeposit", + "DisabilityRatings", + "PersonalInformationScreen", + "VALetters", + "MilitaryInformation", + "Payments", + "Prescriptions", + "Messages", + "VeteranStatusCard" + ], + "getFacilitiesInfo.json": ["Cerner"], + "getFacilitiesInfoCerner.json": ["Cerner"], + "letters.json": ["VALetters"], + "notifications.json": ["SettingsScreen", "PushNotifications"], + "payments.json": ["Payments"], + "personalInformation.json": ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"], + "prescriptions.json": ["Prescriptions"], + "profile.json": [ + "ProfileScreen", + "ContactInformation", + "MilitaryInformation", + "PersonalInformationScreen", + "SettingsScreen", + "VALetters", + "Payments" + ], + "secureMessaging.json": ["Messages"], + "vaccine.json": ["VaccineRecords"], + "decisionLetters.ts": ["DecisionLetters"], + "demographics.ts": ["PersonalInformationScreen", "VeteranStatusCard", "HomeScreen", "ProfileScreen"], + "disabilityRating.ts": ["DisabilityRatings"], + "letters.ts": ["VALetters"], + "notifications.ts": ["SettingsScreen", "PushNotifications"], + "payments.ts": ["Payments"], + "profile.ts": [ + "ProfileScreen", + "ContactInformation", + "MilitaryInformation", + "PersonalInformationScreen", + "SettingsScreen", + "VALetters", + "Payments" + ], + "vaccine.ts": ["VaccineRecords"], + "api.ts": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "App.tsx": [ + "Appeals", + "AppealsExpanded", + "Appointments", + "AppointmentsExpanded", + "AvailabilityFramework", + "Cerner", + "Claims", + "ContactInformation", + "DecisionLetters", + "DirectDeposit", + "DisabilityRatings", + "HomeScreen", + "LoginScreen", + "Messages", + "MilitaryInformation", + "Navigation", + "Onboarding", + "Payments", + "PersonalInformationScreen", + "Prescriptions", + "ProfileScreen", + "SettingsScreen", + "VaccineRecords", + "VALetters", + "VeteransCrisisLine", + "VeteranStatusCard" + ], + "analytics.ts": [], + "backButtonLabels.ts": [], + "documentTypes.ts": [], + "errors.ts": [], + "linking.tsx": [], + "namespaces.ts": [], + "store.ts": [], + "utils.ts": [] + } +} diff --git a/VAMobile/e2e/tests/Appeals.e2e.ts b/VAMobile/e2e/tests/Appeals.e2e.ts index 1ac75e392fa..e9ebacf7ed7 100644 --- a/VAMobile/e2e/tests/Appeals.e2e.ts +++ b/VAMobile/e2e/tests/Appeals.e2e.ts @@ -14,7 +14,6 @@ export const AppealsIdConstants = { REVIEW_PAST_EVENTS_ID: 'reviewPastEventsTestID', ISSUES_TAB_ID: 'appealIssues', STATUS_TAB_ID: 'appealStatus', - APPEALS_DETAILS_ID: 'appealsDetailsTestID', APPEAL_DETAILS_TEXT: 'Appeal details', APPEAL_TYPE_TEXT: 'Appeal for compensation', APPEAL_SUBMITTED_TEXT: 'Received June 12, 2008', @@ -86,7 +85,7 @@ describe('Appeals', () => { }) it('should scroll to the bottom of the appeals screen', async () => { - await element(by.id(AppealsIdConstants.APPEALS_DETAILS_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.APPEALS_DETAILS_ID)).scrollTo('bottom') }) it('should tap on the links in the need help section', async () => { diff --git a/VAMobile/e2e/tests/AppealsExpanded.e2e.ts b/VAMobile/e2e/tests/AppealsExpanded.e2e.ts index 46f4779e9f1..aee827a2d70 100644 --- a/VAMobile/e2e/tests/AppealsExpanded.e2e.ts +++ b/VAMobile/e2e/tests/AppealsExpanded.e2e.ts @@ -180,7 +180,7 @@ describe('AppealsExpanded', () => { if (appealInfo[2] === 'Opt in to the new decision review process') { await waitFor(element(by.text(appealInfo[2]))) .toBeVisible() - .whileElement(by.id('appealsDetailsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPEALS_DETAILS_ID)) .scroll(300, 'down') await element(by.text(appealInfo[2])).tap() await element(by.text(CommonE2eIdConstants.LEAVING_APP_LEAVE_TEXT)).tap() diff --git a/VAMobile/e2e/tests/Appointments.e2e.ts b/VAMobile/e2e/tests/Appointments.e2e.ts index bb4322740c9..daa99b1819b 100644 --- a/VAMobile/e2e/tests/Appointments.e2e.ts +++ b/VAMobile/e2e/tests/Appointments.e2e.ts @@ -23,13 +23,7 @@ const lastYear = lastYearDateTime.get('year') export const Appointmentse2eConstants = { APPOINTMENT_DESCRIPTION: "Here are your appointments. This list includes appointments you've requested but not yet confirmed.", - ADD_TO_CALENDAR_ID: 'addToCalendarTestID', - GET_DIRECTIONS_ID: 'directionsTestID', - PHONE_NUMBER_ASSISTANCE_LINK_ID: 'CallVATestID', - PHONE_NUMBER_ID: 'CallTTYTestID', - PATIENT_CANCELLATION: 'You canceled this appointment.', VA_PAST_APPOINTMENT: 'To schedule another appointment, please visit VA.gov or call your VA medical center.', - DATE_RANGE_INITIAL_TEXT: 'Past 3 months', APPOINTMENT_CANCEL_REQUEST_TEXT: device.getPlatform() === 'ios' ? 'Cancel Request' : 'Cancel Request ', } @@ -47,31 +41,26 @@ describe('Appointments Screen', () => { .scroll(200, 'down') await element(by.text('Vilanisi Reddy')).tap() if (device.getPlatform() === 'android') { - await element(by.id(Appointmentse2eConstants.ADD_TO_CALENDAR_ID)).atIndex(0).tap() + await device.disableSynchronization() + await element(by.id(CommonE2eIdConstants.ADD_TO_CALENDAR_ID)).atIndex(0).tap() await device.takeScreenshot('appointmentCalendar') await device.launchApp({ newInstance: false }) - await element(by.id(Appointmentse2eConstants.GET_DIRECTIONS_ID)).atIndex(0).tap() + await element(by.id(CommonE2eIdConstants.GET_DIRECTIONS_ID)).atIndex(0).tap() await element(by.text(CommonE2eIdConstants.LEAVING_APP_LEAVE_TEXT)).tap() await device.takeScreenshot('appointmentGetDirections') await device.launchApp({ newInstance: false }) - await device.disableSynchronization() - await element(by.id(Appointmentse2eConstants.PHONE_NUMBER_ID)).atIndex(0).tap() - await device.takeScreenshot('appointmentVALocationPhoneNumber') - await device.launchApp({ newInstance: false }) - - await element(by.id(Appointmentse2eConstants.PHONE_NUMBER_ASSISTANCE_LINK_ID)).atIndex(0).tap() - await device.takeScreenshot('apointmentVALocationTTY') - await device.launchApp({ newInstance: false }) + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() await element(by.id('UpcomingApptDetailsTestID')).scrollTo('bottom') - await element(by.id(Appointmentse2eConstants.PHONE_NUMBER_ID)).atIndex(1).tap() + await element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(1).tap() await device.takeScreenshot('appointmentCancelPhoneNumber') await device.launchApp({ newInstance: false }) - await element(by.id(Appointmentse2eConstants.PHONE_NUMBER_ASSISTANCE_LINK_ID)).atIndex(1).tap() + await element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(1).tap() await device.takeScreenshot('appointmentCancelTTY') await device.launchApp({ newInstance: false }) await device.enableSynchronization() @@ -89,7 +78,7 @@ describe('Appointments Screen', () => { await element(by.id('Cancel request')).tap() await element(by.text(Appointmentse2eConstants.APPOINTMENT_CANCEL_REQUEST_TEXT)).tap() await expect(element(by.text('Request canceled'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() }) it('verify the appointment details after cancel', async () => { @@ -106,21 +95,21 @@ describe('Appointments Screen', () => { await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('top') await element(by.id('apptsPastID')).tap() if (device.getPlatform() === 'android') { - await expect(element(by.text(Appointmentse2eConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0)).toExist() + await expect(element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0)).toExist() } else { - await expect(element(by.text(Appointmentse2eConstants.DATE_RANGE_INITIAL_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT))).toExist() } }) it('should show the same date field after cancelling', async () => { await element(by.id('getDateRangeTestID')).tap() if (device.getPlatform() === 'android') { - await element(by.text(Appointmentse2eConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0).tap() + await element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0).tap() await element(by.id('pastApptsDateRangeCancelID')).tap() - await expect(element(by.text(Appointmentse2eConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0)).toExist() + await expect(element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0)).toExist() } else { await element(by.id('pastApptsDateRangeCancelID')).tap() - await expect(element(by.text(Appointmentse2eConstants.DATE_RANGE_INITIAL_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT))).toExist() } }) diff --git a/VAMobile/e2e/tests/AppointmentsExpanded.e2e.ts b/VAMobile/e2e/tests/AppointmentsExpanded.e2e.ts index 46d00f5bd0f..18026f5513b 100644 --- a/VAMobile/e2e/tests/AppointmentsExpanded.e2e.ts +++ b/VAMobile/e2e/tests/AppointmentsExpanded.e2e.ts @@ -2,8 +2,11 @@ import { by, device, element, expect, waitFor } from 'detox' import { CommonE2eIdConstants, loginToDemoMode, openAppointments, openHealth, toggleRemoteConfigFlag } from './utils' -export const Appointmentse2eConstants = { - GET_DIRECTIONS_ID: 'directionsTestID', +export const AppointmentsExpandede2eConstants = { + PATIENT_CANCELLATION: 'You canceled this appointment.', + VIDEO_VISIT_PREP_LINK_ID: 'prepareForVideoVisitTestID', + APPT_DIRECTIONS_ID: 'directionsTestID', + VA_APPT_CANCEL_ID: 'vaLinkApptsCancelTestID', } const checkMedicationWording = async ({ @@ -44,12 +47,12 @@ const checkMedicationWording = async ({ if (appointmentType === 'ATLAS' || appointmentType === 'Home' || appointmentType === 'GFE') { await expect(element(by.text('Get your device ready to join.'))).toExist() - await expect(element(by.id('prepareForVideoVisitTestID'))).toExist() - await waitFor(element(by.id('prepareForVideoVisitTestID'))) + await expect(element(by.id(AppointmentsExpandede2eConstants.VIDEO_VISIT_PREP_LINK_ID))).toExist() + await waitFor(element(by.id(AppointmentsExpandede2eConstants.VIDEO_VISIT_PREP_LINK_ID))) .toBeVisible() .whileElement(by.id(pastAppointment ? 'PastApptDetailsTestID' : 'UpcomingApptDetailsTestID')) .scroll(300, 'down') - await element(by.id('prepareForVideoVisitTestID')).tap() + await element(by.id(AppointmentsExpandede2eConstants.VIDEO_VISIT_PREP_LINK_ID)).tap() await expect(element(by.text('Appointments help'))).toExist() await element(by.text('Close')).tap() } else if (appointmentType === 'Claim') { @@ -73,7 +76,7 @@ const checkMedicationWording = async ({ ).not.toExist() await expect(element(by.text('Learn more about claim exam appointments'))).not.toExist() await expect(element(by.text('Get your device ready to join.'))).not.toExist() - await expect(element(by.id('prepareForVideoVisitTestID'))).not.toExist() + await expect(element(by.id(AppointmentsExpandede2eConstants.VIDEO_VISIT_PREP_LINK_ID))).not.toExist() } } else { await expect(element(by.text('Prepare for your appointment'))).not.toExist() @@ -191,16 +194,16 @@ const checkUpcomingApptDetails = async ( if (locationAddress != undefined) { await expect(element(by.text(locationAddress))).toExist() if (appointmentStatus !== 'Pending' && appointmentType !== 'CC') { - await expect(element(by.id('directionsTestID'))).toExist() - await expect(element(by.id('CallVATestID')).atIndex(0)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(0)).toExist() + await expect(element(by.id(AppointmentsExpandede2eConstants.APPT_DIRECTIONS_ID))).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() } } else { await expect(element(by.text('Where to attend'))).not.toExist() } if (!pastAppointment) { if (appointmentStatus === 'Confirmed') { - await expect(element(by.id('addToCalendarTestID'))).toExist() + await expect(element(by.id(CommonE2eIdConstants.ADD_TO_CALENDAR_ID))).toExist() if ( appointmentType === 'Atlas' || appointmentType === 'Home' || @@ -226,8 +229,8 @@ const checkUpcomingApptDetails = async ( await expect(element(by.text('Middletown VA Clinic'))).toExist() } } - await expect(element(by.id('CallVATestID')).atIndex(1)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(1)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(1)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(1)).toExist() } } else if (appointmentStatus === 'Canceled') { if ( @@ -267,9 +270,9 @@ const checkUpcomingApptDetails = async ( await expect(element(by.text('Middletown VA Clinic'))).toExist() } } - await expect(element(by.id('CallVATestID')).atIndex(1)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(1)).toExist() - await expect(element(by.id('vaLinkApptsCancelTestID'))).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(1)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(1)).toExist() + await expect(element(by.id(AppointmentsExpandede2eConstants.VA_APPT_CANCEL_ID))).toExist() } } else if (appointmentStatus === 'Pending') { if (appointmentType !== 'CC') { @@ -330,8 +333,8 @@ const checkUpcomingApptDetails = async ( if (appointmentType != 'Phone' && appointmentType != 'CC') { await expect(element(by.text('Middletown VA Clinic'))).toExist() } - await expect(element(by.id('CallVATestID')).atIndex(1)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(1)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(1)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(1)).toExist() } } await checkMedicationWording({ appointmentType, appointmentStatus, pastAppointment }) @@ -346,36 +349,36 @@ const scrollToThenTap = async (text: string, pastAppointment: string) => { text === 'At VA Palo Alto Health Care System' || text === 'At Hampton VA Medical Center' ) { - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } if (pastAppointment !== '') { try { await waitFor(element(by.text(text))) .toBeVisible() - .whileElement(by.id('appointmentsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(250, 'down') } catch (ex) { await waitFor(element(by.text(text))) .toBeVisible() - .whileElement(by.id('appointmentsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(250, 'up') } } else { await waitFor(element(by.text(text))) .toBeVisible() - .whileElement(by.id('appointmentsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(300, 'down') try { await waitFor(element(by.text(text))) .toBeVisible() - .whileElement(by.id('appointmentsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(250, 'down') } catch (ex) { await waitFor(element(by.text(text))) .toBeVisible() - .whileElement(by.id('appointmentsTestID')) + .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(250, 'up') } } @@ -395,7 +398,7 @@ export async function apppointmentVerification(pastAppointment = false) { await waitFor(element(by.text('Upcoming'))) .toExist() .withTimeout(10000) - await element(by.id('appointmentsTestID')).scrollTo('top') + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('top') await element(by.text('Past')).tap() } await scrollToThenTap('Vilanisi Reddy', pastAppointmentString) @@ -423,7 +426,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled CC appt', async () => { await scrollToThenTap('Jim Smith', pastAppointmentString) await expect(element(by.text('Canceled community care appointment'))).toExist() - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await checkUpcomingApptDetails( 'CC', @@ -489,7 +492,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled VA video connect - Onsite appt', async () => { await scrollToThenTap('Sami Alsahhar - Onsite - Canceled', pastAppointmentString) - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await expect(element(by.text('Canceled video appointment at VA location'))).toExist() await expect( element(by.text('If you need to reschedule this appointment, call us or schedule a new appointment on VA.gov.')), @@ -515,9 +518,9 @@ export async function apppointmentVerification(pastAppointment = false) { if (pastAppointment) { await element(by.text('Past')).tap() if (device.getPlatform() === 'android') { - await element(by.text('Past 3 months')).atIndex(1).tap() + await element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(1).tap() } else { - await element(by.text('Past 3 months')).atIndex(0).tap() + await element(by.text(CommonE2eIdConstants.DATE_RANGE_INITIAL_TEXT)).atIndex(0).tap() } await element(by.text('All of 2023')).tap() await element(by.text('Done')).tap() @@ -570,7 +573,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled VA video connect - ATLAS appt', async () => { await scrollToThenTap('Sami Alsahhar - ATLAS - Canceled', pastAppointmentString) await expect(element(by.text('Canceled video appointment at an ATLAS location'))).toExist() - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await expect( element( by.text( @@ -632,7 +635,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled VA video connect - Home appt', async () => { await scrollToThenTap('Sami Alsahhar - HOME - Canceled', pastAppointmentString) - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await expect(element(by.text('Canceled video appointment'))).toExist() await checkUpcomingApptDetails( 'Home', @@ -681,7 +684,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled VA video connect - GFE appt', async () => { await scrollToThenTap('Sami Alsahhar - GFE - Canceled', pastAppointmentString) - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await checkUpcomingApptDetails( 'GFE', 'Canceled', @@ -711,12 +714,12 @@ export async function apppointmentVerification(pastAppointment = false) { await waitFor(element(by.text('Upcoming'))) .toExist() .withTimeout(10000) - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } else { await element(by.text('Past')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } await scrollToThenTap('At Fort Collins VA Clinic - Claim - Canceled', pastAppointmentString) await expect(element(by.text('Fort Collins VA Clinic - Claim - Canceled canceled this appointment.'))).toExist() @@ -803,12 +806,12 @@ export async function apppointmentVerification(pastAppointment = false) { await waitFor(element(by.text('Upcoming'))) .toExist() .withTimeout(10000) - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } else { await element(by.text('Past')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } await scrollToThenTap('At Central California VA Health Care System', pastAppointmentString) @@ -857,7 +860,7 @@ export async function apppointmentVerification(pastAppointment = false) { ), ).toExist() if (!pastAppointment) { - await expect(element(by.id(Appointmentse2eConstants.GET_DIRECTIONS_ID))).toExist() + await expect(element(by.id(CommonE2eIdConstants.GET_DIRECTIONS_ID))).toExist() } await expect(element(by.text('Go to VA.gov to find your VA facility'))).toExist() await element(by.text('Appointments')).tap() @@ -872,8 +875,8 @@ export async function apppointmentVerification(pastAppointment = false) { ), ), ).toExist() - await expect(element(by.id('CallVATestID')).atIndex(0)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() await element(by.text('Appointments')).tap() }) @@ -887,10 +890,10 @@ export async function apppointmentVerification(pastAppointment = false) { ), ).toExist() if (!pastAppointment) { - await expect(element(by.id(Appointmentse2eConstants.GET_DIRECTIONS_ID))).toExist() + await expect(element(by.id(CommonE2eIdConstants.GET_DIRECTIONS_ID))).toExist() } - await expect(element(by.id('CallVATestID')).atIndex(0)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() await element(by.text('Appointments')).tap() }) @@ -901,16 +904,16 @@ export async function apppointmentVerification(pastAppointment = false) { await waitFor(element(by.text('Upcoming'))) .toExist() .withTimeout(10000) - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } else { await element(by.text('Past')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } await scrollToThenTap('John Jones', pastAppointmentString) @@ -935,7 +938,7 @@ export async function apppointmentVerification(pastAppointment = false) { ), ).toExist() if (!pastAppointment) { - await expect(element(by.id(Appointmentse2eConstants.GET_DIRECTIONS_ID))).toExist() + await expect(element(by.id(CommonE2eIdConstants.GET_DIRECTIONS_ID))).toExist() } await expect(element(by.text('Go to VA.gov to find your VA facility'))).toExist() await element(by.text('Appointments')).tap() @@ -976,8 +979,8 @@ export async function apppointmentVerification(pastAppointment = false) { ), ), ).toExist() - await expect(element(by.id('CallVATestID')).atIndex(0)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() await element(by.text('Appointments')).tap() }) @@ -990,8 +993,8 @@ export async function apppointmentVerification(pastAppointment = false) { ), ), ).toExist() - await expect(element(by.id('CallVATestID')).atIndex(0)).toExist() - await expect(element(by.id('CallTTYTestID')).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0)).toExist() + await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() await element(by.text('Appointments')).tap() }) @@ -1002,20 +1005,20 @@ export async function apppointmentVerification(pastAppointment = false) { await waitFor(element(by.text('Upcoming'))) .toExist() .withTimeout(10000) - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } else { await element(by.text('Past')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() - await element(by.id('appointmentsTestID')).scrollTo('bottom') - await element(by.id('next-page')).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() + await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.NEXT_PAGE_ID)).tap() } await scrollToThenTap('Jane Jones', pastAppointmentString) @@ -1068,7 +1071,7 @@ export async function apppointmentVerification(pastAppointment = false) { it(pastAppointmentString + 'verify canceled phone appt', async () => { await scrollToThenTap('Phone consultation-Canceled', pastAppointmentString) - await expect(element(by.text('You canceled this appointment.'))).toExist() + await expect(element(by.text(AppointmentsExpandede2eConstants.PATIENT_CANCELLATION))).toExist() await checkUpcomingApptDetails( 'Phone', 'Canceled', diff --git a/VAMobile/e2e/tests/AvailabilityFramework.e2e.ts b/VAMobile/e2e/tests/AvailabilityFramework.e2e.ts index c838ec428fa..7c110d27221 100644 --- a/VAMobile/e2e/tests/AvailabilityFramework.e2e.ts +++ b/VAMobile/e2e/tests/AvailabilityFramework.e2e.ts @@ -173,8 +173,10 @@ export async function runTests(testRun, AFNavigationArray, x) { }) it('should verify AF use case 2 Update available for: ' + testRun, async () => { - await enableAF(AFNavigationArray[x][1], 'DenyContent', true) - await verifyAF(AFNavigationArray[x], 'DenyContent', true) + if (testRun != 'WG_StartNewMessage' && testRun != 'WG_ReplyMessage') { + await enableAF(AFNavigationArray[x][1], 'DenyContent', true) + await verifyAF(AFNavigationArray[x], 'DenyContent', true) + } }) } diff --git a/VAMobile/e2e/tests/Cerner.e2e.ts b/VAMobile/e2e/tests/Cerner.e2e.ts index 3831539e16b..286b7e4f658 100644 --- a/VAMobile/e2e/tests/Cerner.e2e.ts +++ b/VAMobile/e2e/tests/Cerner.e2e.ts @@ -20,7 +20,6 @@ export const CernerIdConstants = { CERNER_NOTE_HEADING_ID: 'cernerAlertTestID', CERNER_NOTE_RECORDS_SHOW_TEXT: "You'll need to use our My VA Health portal to manage your care at these facilities:", CERNER_NOTE_FACILITY_TEXT: 'Cary VA Medical Center', - CERNER_NOTE_FACILITY_2_TEXT: 'Cheyenne VA Medical Center', CERNER_NOTE_MESSAGES_TEXT: 'Sending a message to a care team at these facilities:', CERNER_NOTE_MESSAGES_HEADER_TEXT: 'Your care team uses My VA Health', CERNER_HOME_SUBTEXT_TEXT: 'Information from My VA Health portal not included.', @@ -40,17 +39,17 @@ beforeAll(async () => { await openDeveloperScreen() await waitFor(element(by.text('Remote Config'))) .toBeVisible() - .whileElement(by.id('developerScreenTestID')) + .whileElement(by.id(CommonE2eIdConstants.DEVELOPER_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text('Remote Config')).tap() await waitFor(element(by.text('cernerTrueForDemo'))) .toBeVisible() - .whileElement(by.id('remoteConfigTestID')) + .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(200, 'down') await element(by.text('cernerTrueForDemo')).tap() await waitFor(element(by.text('Apply Overrides'))) .toBeVisible() - .whileElement(by.id('remoteConfigTestID')) + .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(200, 'down') await element(by.text('Apply Overrides')).tap() @@ -63,7 +62,7 @@ describe(':android: Cerner Notice', () => { it('should match the cerner subtext on home screen', async () => { await waitFor(element(by.text(CernerIdConstants.CERNER_HOME_SUBTEXT_TEXT))) .toBeVisible() - .whileElement(by.id('homeScreenID')) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await expect(element(by.text(CernerIdConstants.CERNER_HOME_SUBTEXT_TEXT))).toExist() }) @@ -96,9 +95,7 @@ describe(':android: Cerner Notice', () => { await element(by.id(CernerIdConstants.HEALTH_CATEGORY_ID)).scrollTo('top') await openAppointments() await expect(element(by.id(CernerIdConstants.CERNER_NOTE_HEADING_ID))).toExist() - await expect( - element(by.text("You'll need to use our My VA Health portal to manage your care at these facilities:")), - ).not.toExist() + await expect(element(by.text(CernerIdConstants.CERNER_NOTE_RECORDS_SHOW_TEXT))).not.toExist() }) it('should match the cerner notice design', async () => { @@ -108,7 +105,7 @@ describe(':android: Cerner Notice', () => { .whileElement(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)) .scroll(200, 'down') await expect(element(by.text(CernerIdConstants.CERNER_NOTE_FACILITY_TEXT))).toExist() - await expect(element(by.text(CernerIdConstants.CERNER_NOTE_FACILITY_2_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CHEYENNE_FACILITY_TEXT))).toExist() await expect(element(by.id(CernerIdConstants.GO_TO_VA_HEALTH_LINK_ID))).toExist() }) @@ -124,7 +121,7 @@ describe(':android: Cerner Notice', () => { await element(by.id(CommonE2eIdConstants.APPOINTMENTS_SCROLL_ID)).swipe('down') await element(by.text(CernerIdConstants.CERNER_NOTE_HEADING_TEXT)).tap() await expect(element(by.text(CernerIdConstants.CERNER_NOTE_FACILITY_TEXT))).not.toExist() - await expect(element(by.text(CernerIdConstants.CERNER_NOTE_FACILITY_2_TEXT))).not.toExist() + await expect(element(by.text(CommonE2eIdConstants.CHEYENNE_FACILITY_TEXT))).not.toExist() }) it('tap on messages and verify the cerner notification is present and collapsed', async () => { @@ -136,9 +133,9 @@ describe(':android: Cerner Notice', () => { it('verify the correct information is displayed for multiple facilities', async () => { await element(by.id(CernerIdConstants.CERNER_NOTE_HEADING_ID)).tap() - await expect(element(by.text('Sending a message to a care team at these facilities:'))).toExist() - await expect(element(by.text('Cheyenne VA Medical Center'))).toExist() - await expect(element(by.text('Cary VA Medical Center'))).toExist() + await expect(element(by.text(CernerIdConstants.CERNER_NOTE_MESSAGES_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CHEYENNE_FACILITY_TEXT))).toExist() + await expect(element(by.text(CernerIdConstants.CERNER_NOTE_FACILITY_TEXT))).toExist() await expect(element(by.text("You'll need to use our My VA Health portal to send your message"))).toExist() await expect(element(by.id(CernerIdConstants.GO_TO_VA_HEALTH_LINK_ID))).toExist() }) diff --git a/VAMobile/e2e/tests/Claims.e2e.ts b/VAMobile/e2e/tests/Claims.e2e.ts index 3e1cbe51138..6ebde3a95b0 100644 --- a/VAMobile/e2e/tests/Claims.e2e.ts +++ b/VAMobile/e2e/tests/Claims.e2e.ts @@ -12,7 +12,6 @@ import { } from './utils' export const ClaimsE2eIdConstants = { - ALERT_FILE_REQUEST_BUTTON_ID: 'Review file requests', CLAIM_1_ID: 'Compensation Received December 05, 2021 Step 1 of 5: Claim received Moved to this step on December 05, 2021', CLAIM_2_ID: 'Compensation Received December 04, 2021 Step 5 of 5: Complete Moved to this step on December 04, 2021', @@ -23,8 +22,6 @@ export const ClaimsE2eIdConstants = { 'Compensation Received March 22, 2019 Step 3 of 5: Evidence gathering, review, and decision Moved to this step on July 18, 2019', CLAIM_6_ID: 'Dependency Received January 01, 2016 Step 4 of 5: Preparation for notification Moved to this step on July 30, 2016', - CLOSED_CLAIM_DECISION_LETTER_ID: - 'Compensation Decision letter ready Received January 01, 2021 Step 5 of 5: Complete Moved to this step on April 09, 2021', CLAIM_3_STATUS_STEP_1_ID: 'Step 1 of 5. Claim received. Complete.', CLAIM_3_STATUS_STEP_2_ID: 'Step 2 of 5. Initial review. Current step. Step 1 complete.', CLAIM_3_STATUS_STEP_3_ID: 'Step 3 of 5. Evidence gathering, review, and decision. Incomplete.', @@ -38,18 +35,12 @@ export const ClaimsE2eIdConstants = { CLAIM_4_STATUS_STEP_6_ID: 'Step 6 of 8. Preparing decision letter. Incomplete.', CLAIM_4_STATUS_STEP_7_ID: 'Step 7 of 8. Final review. Incomplete.', CLAIM_4_STATUS_STEP_8_ID: 'Step 8 of 8. Claim decided. Incomplete.', - GET_CLAIMS_LETTER_BUTTON_ID: 'getClaimLettersTestID', FILE_REQUEST_BUTTON_ID: 'Step3FileRequestButton', CURRENT_STEP_TEXT: 'Current step', - TAKE_OR_SELECT_PHOTOS_CAMERA_OPTION_TEXT: device.getPlatform() === 'ios' ? 'Camera' : 'Camera ', - TAKE_OR_SELECT_PHOTOS_PHOTO_GALLERY_OPTION_TEXT: device.getPlatform() === 'ios' ? 'Photo Gallery' : 'Photo gallery ', - SELECT_A_FILE_FILE_FOLDER_OPTION_TEXT: device.getPlatform() === 'ios' ? 'File Folder' : 'File folder ', SELECT_A_FILE_TEXT: 'Select a file', TAKE_OR_SELECT_PHOTOS_TEXT: 'Take or select photos', ACCEPTED_FILE_TYPES_TEXT: 'PDF (unlocked), GIF, JPEG, JPG, BMP, TXT', MAXIMUM_FILE_SIZE_LABEL: '50 megabytes', - CLAIMS_HISTORY_SCREEN_ID: 'claimsHistoryID', - CLAIMS_DETAILS_BACK_ID: 'claimsDetailsBackTestID', CLAIMS_STATUS_ID: 'claimsStatusID', CLAIMS_FILES_ID: 'claimsFilesID', CLAIMS_WHY_COMBINE_LINK_ID: 'claimDetailsWhyWeCombineLinkID', @@ -85,7 +76,7 @@ describe('Claims Screen', () => { }) it('Verify the claim status detail page (8-step claim)', async () => { - await scrollToIDThenTap(ClaimsE2eIdConstants.CLAIM_4_ID, ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID) + await scrollToIDThenTap(ClaimsE2eIdConstants.CLAIM_4_ID, CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID) await expect(element(by.id(ClaimsE2eIdConstants.CLAIMS_STATUS_ID))).toExist() await expect(element(by.id(ClaimsE2eIdConstants.CLAIMS_FILES_ID))).toExist() await expect(element(by.id(ClaimsE2eIdConstants.CLAIM_4_STATUS_STEP_1_ID))).toExist() @@ -97,11 +88,11 @@ describe('Claims Screen', () => { await expect(element(by.id(ClaimsE2eIdConstants.CLAIM_4_STATUS_STEP_7_ID))).toExist() await expect(element(by.id(ClaimsE2eIdConstants.CLAIM_4_STATUS_STEP_8_ID))).toExist() await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_SCREEN_ID)).scrollTo('top') - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('Verify the claim status detail page (5-step claim)', async () => { - await scrollToIDThenTap(ClaimsE2eIdConstants.CLAIM_3_ID, ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID) + await scrollToIDThenTap(ClaimsE2eIdConstants.CLAIM_3_ID, CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID) await expect(element(by.id(ClaimsE2eIdConstants.CLAIMS_STATUS_ID))).toExist() await expect(element(by.id(ClaimsE2eIdConstants.CLAIMS_FILES_ID))).toExist() await expect(element(by.id(ClaimsE2eIdConstants.CLAIM_3_STATUS_STEP_1_ID))).toExist() @@ -165,7 +156,7 @@ describe('Claims Screen', () => { }) it('should navigate back to the claims history page', async () => { - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('automatically expands and scrolls to current step and dates match', async () => { @@ -175,11 +166,11 @@ describe('Claims Screen', () => { it('should verify that the review file request alert is visible', async () => { await expect(element(by.label('You have 3 file requests')).atIndex(1)).toExist() - await waitFor(element(by.id(ClaimsE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID))).toExist() + await waitFor(element(by.id(CommonE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID))).toExist() }) it('should verify that user is sent to File requests screen', async () => { - await element(by.id(ClaimsE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID)).tap() + await element(by.id(CommonE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID)).tap() await expect(element(by.text('You have 3 file requests from VA'))).toExist() await expect(element(by.text('Dental disability - More information needed'))).toExist() }) @@ -219,16 +210,20 @@ describe('Claims Screen', () => { it('should verify details of claim on step 1', async () => { await element(by.id(ClaimsE2eIdConstants.ASK_FOR_CLAIM_DECISION_BACK)).tap() await element(by.id(ClaimsE2eIdConstants.FILE_REQUEST_BACK)).tap() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)).scrollTo('top') await element(by.id(ClaimsE2eIdConstants.CLAIM_1_ID)).tap() await expect(element(by.id('Step 1 of 5. Claim received. Current step.'))).toExist() await expect(element(by.text(ClaimsE2eIdConstants.CURRENT_STEP_TEXT))).toExist() await expect(element(by.text('Thank you. VA received your claim'))).toExist() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('should verify details of claim on step 2', async () => { + await waitFor(element(by.id(ClaimsE2eIdConstants.CLAIM_3_ID))) + .toBeVisible() + .whileElement(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)) + .scroll(100, 'down') await element(by.id(ClaimsE2eIdConstants.CLAIM_3_ID)).tap() await expect(element(by.id('Step 2 of 5. Initial review. Current step. Step 1 complete.'))).toExist() await expect( @@ -272,7 +267,7 @@ describe('Claims Screen', () => { // } else { // await element(by.id(ClaimsE2eIdConstants.SELECT_A_FILE_TEXT)).atIndex(1).tap() // } - // await expect(element(by.text(ClaimsE2eIdConstants.SELECT_A_FILE_FILE_FOLDER_OPTION_TEXT))).toExist() + // await expect(element(by.text(CommonE2eIdConstants.FILE_FOLDER_TEXT))).toExist() // await expect(element(by.text(CommonE2eIdConstants.CANCEL_PLATFORM_SPECIFIC_TEXT))).toExist() // }) @@ -300,8 +295,8 @@ describe('Claims Screen', () => { // } else { // await element(by.id(ClaimsE2eIdConstants.TAKE_OR_SELECT_PHOTOS_TEXT)).atIndex(1).tap() // } - // await expect(element(by.text(ClaimsE2eIdConstants.TAKE_OR_SELECT_PHOTOS_CAMERA_OPTION_TEXT))).toExist() - // await expect(element(by.text(ClaimsE2eIdConstants.TAKE_OR_SELECT_PHOTOS_PHOTO_GALLERY_OPTION_TEXT))).toExist() + // await expect(element(by.text(CommonE2eIdConstants.CAMERA_TEXT))).toExist() + // await expect(element(by.text(CommonE2eIdConstants.PHOTO_GALLERY_TEXT))).toExist() // }) // it('should navigate back to the claim details screen', async () => { @@ -315,10 +310,10 @@ describe('Claims Screen', () => { // }) it('should verify details of claim on step 3 w/ waiver', async () => { - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() await waitFor(element(by.id(ClaimsE2eIdConstants.CLAIM_5_ID))) .toBeVisible() - .whileElement(by.id(ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID)) + .whileElement(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)) .scroll(100, 'down') await element(by.id(ClaimsE2eIdConstants.CLAIM_5_ID)).tap() await setTimeout(2000) @@ -341,29 +336,32 @@ describe('Claims Screen', () => { ), ), ).toExist() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('should verify details of claim on step 4', async () => { await waitFor(element(by.id(ClaimsE2eIdConstants.CLAIM_6_ID))) .toBeVisible() - .whileElement(by.id(ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID)) + .whileElement(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)) .scroll(100, 'down') await element(by.id(ClaimsE2eIdConstants.CLAIM_6_ID)).tap() await expect( element(by.id('Step 4 of 5. Preparation for notification. Current step. Step 1 through 3 complete.')), ).toExist() await expect(element(by.text('We are preparing your claim decision packet to be mailed.'))).toExist() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('should verify details of claim on step 5', async () => { - await element(by.id(ClaimsE2eIdConstants.CLAIMS_HISTORY_SCREEN_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)).scrollTo('top') await element(by.id(ClaimsE2eIdConstants.CLAIM_2_ID)).tap() - await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_SCREEN_ID)).scrollTo('bottom') + await waitFor(element(by.id('Step 5 of 5. Complete. Complete.'))) + .toBeVisible() + .whileElement(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_SCREEN_ID)) + .scroll(100, 'down') await element(by.id('Step 5 of 5. Complete. Complete.')).tap() await expect(element(by.text('Complete')).atIndex(1)).toExist() - await element(by.id(ClaimsE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_BACK_ID)).tap() }) it('should tap on the closed tab', async () => { @@ -371,7 +369,7 @@ describe('Claims Screen', () => { }) it('verify the status details page of closed claim with decision letter', async () => { - await element(by.id(ClaimsE2eIdConstants.CLOSED_CLAIM_DECISION_LETTER_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLOSED_CLAIM_DECISION_LETTER_ID)).tap() await expect(element(by.text('Decision letter ready'))).toExist() await expect( element( diff --git a/VAMobile/e2e/tests/ContactInformation.e2e.ts b/VAMobile/e2e/tests/ContactInformation.e2e.ts index 3660979a305..36a6a9a9d66 100644 --- a/VAMobile/e2e/tests/ContactInformation.e2e.ts +++ b/VAMobile/e2e/tests/ContactInformation.e2e.ts @@ -4,7 +4,6 @@ import { setTimeout } from 'timers/promises' import { CommonE2eIdConstants, loginToDemoMode, openContactInfo, openProfile, toggleRemoteConfigFlag } from './utils' export const ContactInfoE2eIdConstants = { - CONTACT_INFO_PAGE_ID: 'ContactInfoTestID', MAILING_ADDRESS_ID: 'Mailing address 3101 N Fort Valley Rd Flagstaff, AZ, 86001', MAILING_ADDRESS_2_ID: 'Mailing address 3101 N Fort Valley Rd, 2 Flagstaff, AZ, 86001', HOME_ADDRESS_ID: 'Home address Add your home address', @@ -15,7 +14,6 @@ export const ContactInfoE2eIdConstants = { HOW_WE_USE_TEXT: 'How we use your contact information', COUNTRY_PICKER_ID: 'countryPickerTestID', STREET_ADDRESS_LINE_1_ID: 'streetAddressLine1TestID', - STREET_ADDRESS_LINE_2_ID: 'streetAddressLine2TestID', STREET_ADDRESS_LINE_3_ID: 'streetAddressLine3TestID', MILITARY_POST_OFFICE_ID: 'militaryPostOfficeTestID', CITY_TEST_ID: 'cityTestID', @@ -23,12 +21,8 @@ export const ContactInfoE2eIdConstants = { ZIP_CODE_ID: 'zipCodeTestID', PHONE_NUMBER_EXTENSION_ID: 'phoneNumberExtensionTestID', PHONE_NUMBER_ID: 'phoneNumberTestID', - CANCEL_DELETE_TEXT: device.getPlatform() === 'ios' ? 'Delete Changes' : 'Delete Changes ', - CANCEL_KEEP_EDITING_TEXT: device.getPlatform() === 'ios' ? 'Keep Editing' : 'Keep Editing ', REMOVE_KEEP_TEXT: 'Keep', REMOVE_REMOVE_TEXT: 'Remove', - SAVE_TEXT: 'Save', - DISMISS_TEXT: 'Dismiss', EDIT_ADDRESS_ID: 'EditAddressTestID', COUNTRY_PICKER_CONFIRM_ID: 'countryPickerConfirmID', STATE_PICKER_CONFIRM_ID: 'statePickerConfirmID', @@ -82,10 +76,10 @@ export async function fillHomeAddressFields() { export async function validateAddresses(addressID: string, addressType: string) { it('update the ' + addressType + ' address', async () => { - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('top') await waitFor(element(by.id(addressID))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(50, 'down') await element(by.id(addressID)).tap() }) @@ -103,12 +97,12 @@ export async function validateAddresses(addressID: string, addressType: string) await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_BACK_ID)).tap() await setTimeout(2000) await expect(element(by.text('Delete changes to your ' + addressType.toLowerCase() + ' address?'))).toExist() - await expect(element(by.text(ContactInfoE2eIdConstants.CANCEL_DELETE_TEXT))).toExist() - await expect(element(by.text(ContactInfoE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() }) it(addressType + ': verify fields are filled on keep editing', async () => { - await element(by.text(ContactInfoE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() await expect(element(by.text('United States'))).toExist() await expect(element(by.text('3101 N Fort Valley Rd')).atIndex(0)).toExist() await expect(element(by.text('2'))).toExist() @@ -119,15 +113,15 @@ export async function validateAddresses(addressID: string, addressType: string) it(addressType + ': verify contact info screen is displayed on delete', async () => { await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_BACK_ID)).tap() - await element(by.text(ContactInfoE2eIdConstants.CANCEL_DELETE_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT)).tap() await expect(element(by.id(addressID))).toExist() }) it('should open and update the ' + addressType + ' address', async () => { - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('top') await waitFor(element(by.id(addressID))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(100, 'down') await element(by.id(addressID)).tap() await element(by.id(CommonE2eIdConstants.CONTACT_INFO_STREET_ADDRESS_LINE_2_ID)).typeText('2') @@ -170,7 +164,7 @@ export async function validateAddresses(addressID: string, addressType: string) try { await setTimeout(5000) await expect(element(by.text(addressType + ' address saved'))).toExist() - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} }) @@ -183,7 +177,7 @@ export async function validatePhoneNumbers(phoneID: string, phoneType: string) { it('should open the ' + phoneType + ' phone number', async () => { await waitFor(element(by.id(phoneID))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(100, 'down') await element(by.id(phoneID)).tap() }) @@ -223,12 +217,12 @@ export async function validatePhoneNumbers(phoneID: string, phoneType: string) { await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_BACK_ID)).tap() await setTimeout(2000) await expect(element(by.text('Delete changes to your ' + phoneType.toLowerCase() + ' phone number?'))).toExist() - await expect(element(by.text(ContactInfoE2eIdConstants.CANCEL_DELETE_TEXT))).toExist() - await expect(element(by.text(ContactInfoE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() }) it(phoneType + ': verify fields are filled on keep editing', async () => { - await element(by.text(ContactInfoE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() await expect(element(by.text('276-608-6180')).atIndex(0)).toExist() await expect(element(by.text('1234'))).toExist() }) @@ -236,14 +230,14 @@ export async function validatePhoneNumbers(phoneID: string, phoneType: string) { it(phoneType + ': verify contact info screen is displayed on delete', async () => { await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_BACK_ID)).tap() await setTimeout(2000) - await element(by.text(ContactInfoE2eIdConstants.CANCEL_DELETE_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT)).tap() await expect(element(by.id(phoneID))).toExist() }) it('should update the ' + phoneType + ' with an extension', async () => { await waitFor(element(by.id(phoneID))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(100, 'down') await element(by.id(phoneID)).tap() if (phoneType === 'Work') { @@ -269,17 +263,17 @@ export async function validatePhoneNumbers(phoneID: string, phoneType: string) { try { await setTimeout(2000) await expect(element(by.text(phoneType + ' phone saved'))).toExist() - await waitFor(element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT))) + await waitFor(element(by.text(CommonE2eIdConstants.DISMISS_TEXT))) .toBeVisible() .withTimeout(4000) - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} }) it(phoneType + ': verify user can remove the extension', async () => { await waitFor(element(by.id(phoneID))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(100, 'down') await element(by.id(phoneID)).tap() await element(by.id(ContactInfoE2eIdConstants.PHONE_NUMBER_EXTENSION_ID)).clearText() @@ -291,20 +285,20 @@ export async function validatePhoneNumbers(phoneID: string, phoneType: string) { try { await setTimeout(2000) await expect(element(by.text(phoneType + ' phone saved'))).toExist() - await waitFor(element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT))) + await waitFor(element(by.text(CommonE2eIdConstants.DISMISS_TEXT))) .toBeVisible() .withTimeout(4000) - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} }) } export async function removeContactInfoFeature(contactInfoTypeText: string, type: string) { it('should tap remove ' + type + ' and verify remove pop up appears', async () => { - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('top') await waitFor(element(by.id(contactInfoTypeText))) .toBeVisible() - .whileElement(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(100, 'down') await element(by.id(contactInfoTypeText)).tap() await element(by.text('Remove ' + type)).tap() @@ -333,10 +327,10 @@ export async function removeContactInfoFeature(contactInfoTypeText: string, type await setTimeout(2000) await element(by.text(ContactInfoE2eIdConstants.REMOVE_REMOVE_TEXT)).tap() try { - await waitFor(element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT))) + await waitFor(element(by.text(CommonE2eIdConstants.DISMISS_TEXT))) .toBeVisible() .withTimeout(4000) - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} if (type === 'home phone' || type === 'work phone') { await expect(element(by.text('Add your ' + type + ' number'))).toExist() @@ -428,7 +422,7 @@ describe(':ios: Contact Info Screen', () => { it('verify how we use your contact information link', async () => { await expect(element(by.id(ContactInfoE2eIdConstants.HOW_WE_USE_CONTACT_INFO_LINK_ID))).toExist() await element(by.id(ContactInfoE2eIdConstants.HOW_WE_USE_CONTACT_INFO_LINK_ID)).tap() - await expect(element(by.text('How we use your contact information')).atIndex(0)).toExist() + await expect(element(by.text(ContactInfoE2eIdConstants.HOW_WE_USE_TEXT)).atIndex(0)).toExist() await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_CLOSE_ID)).atIndex(0).tap() }) @@ -443,7 +437,7 @@ describe(':ios: Contact Info Screen', () => { removeContactInfoFeature(ContactInfoE2eIdConstants.MOBILE_PHONE_ID, 'mobile phone') it('should open the email address', async () => { - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('bottom') await element(by.id(ContactInfoE2eIdConstants.EMAIL_ADDRESS_ID)).tap() }) @@ -464,12 +458,12 @@ describe(':ios: Contact Info Screen', () => { try { await setTimeout(5000) await expect(element(by.text('Email address saved'))).toExist() - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} }) it('should update the email address and remove the +', async () => { - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('bottom') await element(by.id(ContactInfoE2eIdConstants.EMAIL_ADDRESS_ID)).tap() await element(by.id(ContactInfoE2eIdConstants.EMAIL_ADDRESS_EDIT_ID)).clearText() await element(by.id(ContactInfoE2eIdConstants.EMAIL_ADDRESS_EDIT_ID)).typeText('attended1@gmail.com') @@ -481,9 +475,9 @@ describe(':ios: Contact Info Screen', () => { try { await setTimeout(5000) await expect(element(by.text('Email address saved'))).toExist() - await element(by.text(ContactInfoE2eIdConstants.DISMISS_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() } catch (ex) {} - await element(by.id(ContactInfoE2eIdConstants.CONTACT_INFO_PAGE_ID)).scrollTo('top') + await element(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)).scrollTo('top') }) removeContactInfoFeature(ContactInfoE2eIdConstants.EMAIL_ADDRESS_ID, 'email address') diff --git a/VAMobile/e2e/tests/DecisionLetters.e2e.ts b/VAMobile/e2e/tests/DecisionLetters.e2e.ts index 0d348afbf13..f8436d5a95f 100644 --- a/VAMobile/e2e/tests/DecisionLetters.e2e.ts +++ b/VAMobile/e2e/tests/DecisionLetters.e2e.ts @@ -11,14 +11,12 @@ import { } from './utils' export const DecisionLettersE2eIDConstants = { - CLOSED_CLAIM_DECISION_LETTER_ID: - 'Compensation Decision letter ready Received January 01, 2021 Step 5 of 5: Complete Moved to this step on April 09, 2021', - GET_CLAIMS_LETTER_BUTTON_ID: 'getClaimLettersTestID', DECISION_CLAIM_LETTER_1_ID: 'March 11, 2023 letter Notification Letter (e.g. VA 20-8993, VA 21-0290, PCGL)', DECISION_CLAIM_LETTER_2_ID: 'September 21, 2022 letter Decision Rating Letter', CLAIMS_HISTORY_TEXT: 'Claims history', CLAIM_LETTERS_BACK_ID: 'claimLettersBackTestID', TO_DECISION_LETTERS_ID: 'toClaimLettersID', + GET_CLAIMS_LETTER_BUTTON_ID: 'getClaimLettersTestID', } beforeAll(async () => { @@ -35,7 +33,7 @@ describe('Decision Letters Screen', () => { }) it('verify the status details page of closed claim with decision letter', async () => { - await element(by.id(DecisionLettersE2eIDConstants.CLOSED_CLAIM_DECISION_LETTER_ID)).tap() + await element(by.id(CommonE2eIdConstants.CLOSED_CLAIM_DECISION_LETTER_ID)).tap() await expect(element(by.id(DecisionLettersE2eIDConstants.GET_CLAIMS_LETTER_BUTTON_ID))).toExist() }) diff --git a/VAMobile/e2e/tests/DirectDeposit.e2e.ts b/VAMobile/e2e/tests/DirectDeposit.e2e.ts index 8fdb94e1252..dd3ab57cef6 100644 --- a/VAMobile/e2e/tests/DirectDeposit.e2e.ts +++ b/VAMobile/e2e/tests/DirectDeposit.e2e.ts @@ -15,7 +15,6 @@ export const DirectDepositConstants = { 'You can find your 9-digit routing number on the bottom left side of a check. You can find your account number in the bottom center of a check.', WHERE_CAN_I_FIND_ID: 'directDepositFindTheseNumbersID', CANCEL_CONFIRM_TEXT: 'Delete changes to your direct deposit information?', - CANCEL_CONFIRM_BUTTON_TEXT: device.getPlatform() === 'ios' ? 'Delete Changes' : 'Delete Changes ', SAVE_ID: 'directDepositSaveID', BACK_ID: 'directDepositBackID', DIRECT_DEPOSIT_EDIT_SCROLL_ID: 'DirectDepositEditAccount', @@ -79,7 +78,7 @@ describe('Direct Deposit Screen', () => { await expect(element(by.text('Check your direct deposit information'))).toExist() await expect(element(by.text('Enter a 9-digit routing number'))).toExist() await element(by.id(DirectDepositConstants.BACK_ID)).tap() - await element(by.text(DirectDepositConstants.CANCEL_CONFIRM_BUTTON_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT)).tap() }) it('should fill out Account form for checking', async () => { @@ -100,7 +99,7 @@ describe('Direct Deposit Screen', () => { await expect(element(by.text('*************4567'))).toExist() await expect(element(by.text('Checking account'))).toExist() await expect(element(by.text('Direct deposit information saved'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() }) it('should fill out Account form for savings', async () => { @@ -121,7 +120,7 @@ describe('Direct Deposit Screen', () => { await expect(element(by.text('Savings account'))).toExist() await setTimeout(2000) await expect(element(by.text('Direct deposit information saved'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() }) it('should show cancel confirmation after user enters information', async () => { @@ -131,7 +130,7 @@ describe('Direct Deposit Screen', () => { await element(by.id(DirectDepositConstants.DIRECT_DEPOSIT_EDIT_ROUTING_NUM_ID)).typeText('053100300\n') await element(by.id(DirectDepositConstants.BACK_ID)).tap() await expect(element(by.text(DirectDepositConstants.CANCEL_CONFIRM_TEXT))).toExist() - await element(by.text(DirectDepositConstants.CANCEL_CONFIRM_BUTTON_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT)).tap() await expect(element(by.text(DirectDepositConstants.SCREEN_TITLE))).toExist() }) diff --git a/VAMobile/e2e/tests/HomeScreen.e2e.ts b/VAMobile/e2e/tests/HomeScreen.e2e.ts index a067ade839e..62790a7b9ff 100644 --- a/VAMobile/e2e/tests/HomeScreen.e2e.ts +++ b/VAMobile/e2e/tests/HomeScreen.e2e.ts @@ -4,11 +4,9 @@ import { setTimeout } from 'timers/promises' import { CommonE2eIdConstants, checkImages, disableAF, enableAF, loginToDemoMode, verifyAF } from './utils' export const HomeE2eIdConstants = { - PAYMENTS_BTN_ID: 'Payments', VETERAN_STATUS_TEXT: 'Proof of Veteran status', - LOCATION_FINDER_ROW_TEXT: 'Find a VA location', + LOCATION_FINDER_TEXT: 'Find a VA location', CONTACT_VA_ROW_TEXT: 'Contact us', - HOME_PAGE_MILITARY_BRANCH: 'United States Coast Guard', CONTACT_VA_TITLE: 'Call My V-A 4 1 1', CONTACT_VA_BODY: 'My V-A 4 1 1 is our main V-A information line. We can help connect you to any of our V-A contact centers.', @@ -19,11 +17,9 @@ export const HomeE2eIdConstants = { PRESCRIPTIONS_BUTTON_SUBTEXT_TEXT: '10 ready to refill', ANNOUNCEMENT_BANNER_TEXT: 'Learn about PACT Act on VA.gov', DISABILITY_RATING_TITLE_TEXT: 'Disability rating', - DISABILITY_RATING_PERCENT_TEXT: '100%', DISABILITY_RATING_SUBTEXT_TEXT: 'service connected', MONTHLY_PAYMENT_TITLE_TEXT: 'Monthly compensation payment', MONTHLY_PAYMENT_AMOUNT_TEXT: '$3,084.75', - HOME_SCREEN_SCROLL_ID: 'homeScreenID', } beforeAll(async () => { @@ -37,7 +33,8 @@ describe('Home Screen', () => { }) it(':android: should disable AF use case 3', async () => { - await disableAF(undefined, 'WG_Home', undefined, 'AllowFunction') + await device.uninstallApp() + await device.installApp() await device.launchApp({ newInstance: true, permissions: { notifications: 'YES' } }) await loginToDemoMode() }) @@ -112,7 +109,7 @@ describe('Home Screen', () => { await element(by.text(CommonE2eIdConstants.HOME_TAB_BUTTON_TEXT)).tap() await waitFor(element(by.text(HomeE2eIdConstants.APPOINTMENTS_BUTTON_SUBTEXT_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(HomeE2eIdConstants.APPOINTMENTS_BUTTON_SUBTEXT_TEXT)).atIndex(0).tap() await expect(element(by.text(CommonE2eIdConstants.UPCOMING_APPT_BUTTON_TEXT))).toExist() @@ -122,7 +119,7 @@ describe('Home Screen', () => { await element(by.text(CommonE2eIdConstants.HOME_TAB_BUTTON_TEXT)).tap() await waitFor(element(by.text(HomeE2eIdConstants.CLAIMS_BUTTON_SUBTEXT_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(HomeE2eIdConstants.CLAIMS_BUTTON_SUBTEXT_TEXT)).tap() await expect(element(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID))).toExist() @@ -132,7 +129,7 @@ describe('Home Screen', () => { await element(by.text(CommonE2eIdConstants.HOME_TAB_BUTTON_TEXT)).tap() await waitFor(element(by.text(HomeE2eIdConstants.MESSAGES_BUTTON_SUBTEXT_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(HomeE2eIdConstants.MESSAGES_BUTTON_SUBTEXT_TEXT)).tap() await expect(element(by.id(CommonE2eIdConstants.START_NEW_MESSAGE_BUTTON_ID))).toExist() @@ -142,7 +139,7 @@ describe('Home Screen', () => { await element(by.text(CommonE2eIdConstants.HOME_TAB_BUTTON_TEXT)).tap() await waitFor(element(by.text(HomeE2eIdConstants.PRESCRIPTIONS_BUTTON_SUBTEXT_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(HomeE2eIdConstants.PRESCRIPTIONS_BUTTON_SUBTEXT_TEXT)).tap() await expect(element(by.id(CommonE2eIdConstants.PRESCRIPTION_REFILL_BUTTON_ID))).toExist() @@ -155,27 +152,27 @@ describe('Home Screen', () => { } catch (e) {} await waitFor(element(by.text(HomeE2eIdConstants.MONTHLY_PAYMENT_AMOUNT_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') - await expect(element(by.text(HomeE2eIdConstants.HOME_PAGE_MILITARY_BRANCH))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_BRANCH_COAST_GUARD))).toExist() await expect(element(by.text(HomeE2eIdConstants.VETERAN_STATUS_TEXT))).toExist() const militaryBadge = await element(by.id('United States Coast Guard Emblem')).takeScreenshot( 'MilitaryServiceBadgeHome', ) checkImages(militaryBadge) await expect(element(by.text(HomeE2eIdConstants.DISABILITY_RATING_TITLE_TEXT))).toExist() - await expect(element(by.text(HomeE2eIdConstants.DISABILITY_RATING_PERCENT_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.DISABILITY_RATING_PERCENT_TEXT))).toExist() await expect(element(by.text(HomeE2eIdConstants.DISABILITY_RATING_SUBTEXT_TEXT))).toExist() await expect(element(by.text(HomeE2eIdConstants.MONTHLY_PAYMENT_TITLE_TEXT))).toExist() await expect(element(by.text(HomeE2eIdConstants.MONTHLY_PAYMENT_AMOUNT_TEXT))).toExist() }) it('should show home page VA Resources content', async () => { - await waitFor(element(by.text(HomeE2eIdConstants.LOCATION_FINDER_ROW_TEXT))) + await waitFor(element(by.text(HomeE2eIdConstants.LOCATION_FINDER_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') - await expect(element(by.text(HomeE2eIdConstants.LOCATION_FINDER_ROW_TEXT))).toExist() + await expect(element(by.text(HomeE2eIdConstants.LOCATION_FINDER_TEXT))).toExist() await expect(element(by.text(HomeE2eIdConstants.CONTACT_VA_ROW_TEXT))).toExist() }) @@ -206,7 +203,7 @@ describe('Home Screen', () => { try { await element(by.text('Skip this update')).tap() } catch (e) {} - await element(by.text(HomeE2eIdConstants.LOCATION_FINDER_ROW_TEXT)).tap() + await element(by.text(HomeE2eIdConstants.LOCATION_FINDER_TEXT)).tap() await setTimeout(5000) await device.takeScreenshot('HomeFindAVALocationScreenshot') }) @@ -215,7 +212,7 @@ describe('Home Screen', () => { await element(by.text('Done')).tap() await waitFor(element(by.text(HomeE2eIdConstants.ANNOUNCEMENT_BANNER_TEXT))) .toBeVisible() - .whileElement(by.id(HomeE2eIdConstants.HOME_SCREEN_SCROLL_ID)) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await expect(element(by.text(HomeE2eIdConstants.ANNOUNCEMENT_BANNER_TEXT))).toExist() }) diff --git a/VAMobile/e2e/tests/LoginScreen.e2e.ts b/VAMobile/e2e/tests/LoginScreen.e2e.ts index 1be4a16dddf..e70374713a4 100644 --- a/VAMobile/e2e/tests/LoginScreen.e2e.ts +++ b/VAMobile/e2e/tests/LoginScreen.e2e.ts @@ -3,7 +3,6 @@ import { by, element, expect, waitFor } from 'detox' import { CommonE2eIdConstants, checkImages } from './utils' export const LoginE2eIdConstants = { - LOGIN_PAGE_ID: 'Login-page', LOGIN_FIND_VA_BUTTON_ID: 'Find a VA location', LOGIN_APP_VERSION_ID: 'AppVersionTestID', } diff --git a/VAMobile/e2e/tests/Messages.e2e.ts b/VAMobile/e2e/tests/Messages.e2e.ts index fa91c9bc234..e73ff99233c 100644 --- a/VAMobile/e2e/tests/Messages.e2e.ts +++ b/VAMobile/e2e/tests/Messages.e2e.ts @@ -27,9 +27,6 @@ export const MessagesE2eIdConstants = { REVIEW_MESSAGE_REPLY_ID: 'replyTestID', ONLY_USE_MESSAGES_TEXT: 'Only use messages for non-urgent needs', ATTACHMENTS_BUTTON_ID: 'messagesAttachmentsAddFilesID', - ATTACHMENT_CAMERA_TEXT: device.getPlatform() === 'ios' ? 'Camera' : 'Camera ', - ATTACHMENT_PHOTO_GALLERY_TEXT: device.getPlatform() === 'ios' ? 'Photo Gallery' : 'Photo gallery ', - ATTACHMENT_FILE_FOLDER_TEXT: device.getPlatform() === 'ios' ? 'File Folder' : 'File folder ', MESSAGE_INPUT_ID: 'reply field', SEND_BUTTON_ID: 'sendButtonTestID', SELECT_A_FILE_ID: 'messagesSelectAFileID', @@ -44,12 +41,9 @@ export const MessagesE2eIdConstants = { START_NEW_MESSAGE_SAVE_ID: 'startNewMessageSaveTestID', START_NEW_MESSAGE_CANCEL_ID: 'startNewMessageCancelTestID', MESSAGE_CANCEL_DELETE_TEXT: device.getPlatform() === 'ios' ? 'Delete' : 'Delete ', - MESSAGE_CANCEL_KEEP_EDITING_TEXT: device.getPlatform() === 'ios' ? 'Keep Editing' : 'Keep Editing ', MESSAGE_CANCEL_SAVE_TEXT: device.getPlatform() === 'ios' ? 'Save' : 'Save ', - VIEW_MESSAGE_ID: 'viewMessageTestID', EDIT_DRAFT_MESSAGE_FIELD_ID: 'messageText', EDIT_DRAFT_CANCEL_ID: 'editDraftCancelTestID', - EDIT_DRAFT_CANCEL_DELETE_TEXT: device.getPlatform() === 'ios' ? 'Delete Changes' : 'Delete Changes ', EDIT_DRAFT_CANCEL_SAVE_TEXT: device.getPlatform() === 'ios' ? 'Save Changes' : 'Save Changes ', EDIT_DRAFT_PAGE_TEST_ID: 'editDraftTestID', BACK_TO_MESSAGES_ID: 'backToMessagesID', @@ -65,12 +59,12 @@ export const MessagesE2eIdConstants = { const tapItems = async (items: string, type: string) => { // if (type === 'url' || type === 'map' || type === 'email') { // if (items != 'https://www.va.gov/') { - // await element(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') + // await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') // } // } await waitFor(element(by.text(items))) .toBeVisible() - .whileElement(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)) + .whileElement(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)) .scroll(50, 'down') await device.disableSynchronization() await element(by.text(items)).tap() @@ -247,7 +241,7 @@ describe('Messages Screen', () => { }) it('should tap reply and verify the correct information is displayed', async () => { - await element(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') await element(by.id(MessagesE2eIdConstants.REVIEW_MESSAGE_REPLY_ID)).tap() await expect(element(by.id('To RATANA, NARIN '))).toExist() await expect(element(by.id('Subject Medication: Naproxen side effects'))).toExist() @@ -258,7 +252,7 @@ describe('Messages Screen', () => { it('reply: verify talk to the veterans crisis line now is displayed', async () => { await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BTN_ID)).tap() - await expect(element(by.text('Veterans Crisis Line'))).toExist() + await expect(element(by.text(CommonE2eIdConstants.VETERAN_CRISIS_LINE_HEADING_TEXT))).toExist() await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BACK_ID)).tap() }) @@ -287,9 +281,9 @@ describe('Messages Screen', () => { it('verify tap select a file action sheet options are correct', async () => { await element(by.id(MessagesE2eIdConstants.ATTACHMENTS_BUTTON_ID)).tap() await element(by.id(MessagesE2eIdConstants.SELECT_A_FILE_ID)).tap() - await expect(element(by.text(MessagesE2eIdConstants.ATTACHMENT_CAMERA_TEXT))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.ATTACHMENT_PHOTO_GALLERY_TEXT))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.ATTACHMENT_FILE_FOLDER_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CAMERA_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.PHOTO_GALLERY_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.FILE_FOLDER_TEXT))).toExist() }) it('should close the action sheet and tap cancel', async () => { @@ -312,15 +306,15 @@ describe('Messages Screen', () => { await expect(element(by.text("If you save as a draft, we'll remove the attachments."))).toExist() await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_DELETE_TEXT))).toExist() await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_SAVE_TEXT))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() }) it('should tap keep editing and send the message', async () => { - await element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() await element(by.id(MessagesE2eIdConstants.REPLY_PAGE_TEST_ID)).scroll(300, 'down', NaN, 0.8) await element(by.id(MessagesE2eIdConstants.SEND_BUTTON_ID)).tap() await expect(element(by.text('Message sent'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() }) it('should tap and move a message', async () => { @@ -329,7 +323,7 @@ describe('Messages Screen', () => { await element(by.text('Custom Folder 2')).tap() await element(by.id(MessagesE2eIdConstants.MOVE_PICKER_CONFIRM_ID)).tap() await expect(element(by.text('Message moved to Custom Folder 2'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() await element(by.id(MessagesE2eIdConstants.BACK_TO_MESSAGES_ID)).tap() }) @@ -346,14 +340,14 @@ describe('Messages Screen', () => { it(':ios: new message: verify talk to the veterans crisis line now', async () => { await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BTN_ID)).tap() - await expect(element(by.text('Veterans Crisis Line'))).toExist() + await expect(element(by.text(CommonE2eIdConstants.VETERAN_CRISIS_LINE_HEADING_TEXT))).toExist() await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BACK_ID)).tap() }) it(':ios: verify only use messages for non-urgent needs information', async () => { await element(by.id(MessagesE2eIdConstants.START_NEW_MESSAGE_ID)).scroll(300, 'down', NaN, 0.8) await element(by.id(MessagesE2eIdConstants.START_NEW_MESSAGE_ONLY_USE_MESSAGES_ID)).tap() - await expect(element(by.text('Only use messages for non-urgent needs'))) + await expect(element(by.text(MessagesE2eIdConstants.ONLY_USE_MESSAGES_TEXT))) await expect(element(by.text('Your care team may take up to 3 business days to reply.'))).toExist() await expect(element(by.text('If you need help sooner, use one of these urgent communication options:'))).toExist() await device.disableSynchronization() @@ -434,11 +428,11 @@ describe('Messages Screen', () => { await expect(element(by.text("If you save as a draft, we'll remove the attachments."))).toExist() await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_DELETE_TEXT))).toExist() await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_SAVE_TEXT))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() }) it(':ios: verify the previous made fields are filled on keep editing', async () => { - await element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() await expect(element(by.text('VA Flagship mobile applications interface_DAYT29'))).toExist() await expect(element(by.text('Medication'))).toExist() }) @@ -469,7 +463,7 @@ describe('Messages Screen', () => { 'Va Flagship Mobile Applications Interface 2_dayt29 November 16, 2024 Appointment: Preparing for your visit', ), ).tap() - await element(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') await expect(element(by.text('Melvin Freeman\nUSMC Veteran'))).toExist() await expect(element(by.text('See you at your appointment. Please do not forget to fast.'))).toExist() await expect(element(by.text('Testing '))).toExist() @@ -483,7 +477,7 @@ describe('Messages Screen', () => { }) it('verify message threads with more than two lines', async () => { - await element(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') messageCollapsed = await device.takeScreenshot('MessageCollapsed') checkImages(messageCollapsed) await element( @@ -491,7 +485,7 @@ describe('Messages Screen', () => { 'Please fast for at least 12 hours before your upcoming visit on October 19th. Eating or drinking anything besides water will have an effect on your blood lab results. Thank you.', ), ).tap() - await element(by.id(MessagesE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') messageExpanded = await device.takeScreenshot('MessageExpanded') await element(by.text('Sent')).tap() await element(by.text('Messages')).tap() @@ -514,19 +508,19 @@ describe('Messages Screen', () => { await element(by.id(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_ID)).tap() await expect(element(by.text('Delete changes to draft?'))).toExist() await expect(element(by.text("If you save your changes, we'll remove the attachments."))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_DELETE_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT))).toExist() await expect(element(by.text(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_SAVE_TEXT))).toExist() - await expect(element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT))).toExist() }) it('drafts: verify the previous made fields are filled on keep editing', async () => { - await element(by.text(MessagesE2eIdConstants.MESSAGE_CANCEL_KEEP_EDITING_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_KEEP_EDITING_TEXT)).tap() await expect(element(by.text('Testing'))).toExist() }) it('verify that the draft is still in the list after cancel', async () => { await element(by.id(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_ID)).tap() - await element(by.text(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_DELETE_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.CANCEL_DELETE_CHANGES_BUTTON_TEXT)).tap() await expect(element(by.text('Test: Test Inquiry'))).toExist() }) @@ -544,7 +538,7 @@ describe('Messages Screen', () => { await element(by.id(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_ID)).tap() await element(by.text(MessagesE2eIdConstants.EDIT_DRAFT_CANCEL_SAVE_TEXT)).tap() await expect(element(by.text('Draft saved'))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() }) it('should open a draft message and verify it can be deleted', async () => { diff --git a/VAMobile/e2e/tests/MilitaryInformation.e2e.ts b/VAMobile/e2e/tests/MilitaryInformation.e2e.ts index 18e7b514ed3..f3a243561fa 100644 --- a/VAMobile/e2e/tests/MilitaryInformation.e2e.ts +++ b/VAMobile/e2e/tests/MilitaryInformation.e2e.ts @@ -11,7 +11,6 @@ import { } from './utils' export const MilitaryInformationE2eIdConstants = { - MILITARY_DATE_TEXT: 'July 13, 1970 – August 31, 1998', SERVICE_INFORMATION_INCORRECT_ID: 'militaryServiceIncorrectLinkID', SERVICE_INFORMATION_INCORRECT_SWIPE: 'IncorrectServiceTestID', SERVICE_INFORMATION_INCORRECT_BODY_LABEL_1: @@ -45,7 +44,7 @@ export async function verifyMilitaryInfo(militaryBranch: string) { await expect(element(by.text(militaryBranch))).toExist() await openMilitaryInformation() await expect(element(by.text(militaryBranch)).atIndex(0)).toExist() - await expect(element(by.text(MilitaryInformationE2eIdConstants.MILITARY_DATE_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_PERIOD_OF_SERVICE))).toExist() }) } diff --git a/VAMobile/e2e/tests/Navigation.e2e.ts b/VAMobile/e2e/tests/Navigation.e2e.ts index 7288c8f382b..54ccefc04f1 100644 --- a/VAMobile/e2e/tests/Navigation.e2e.ts +++ b/VAMobile/e2e/tests/Navigation.e2e.ts @@ -1,3 +1,12 @@ +/* +Description: +Detox script that runs dark mode, landscape, and font size accessibility tests. +The script can run either as a full suite or a subset: +* Full suite: The script will check every page outlined in navigationDic. A full suite run occurs either on the nightly dev build or when you check "run full e2e test" in the workflow options (if running manually). +* Subset: The script will only check the pages where the test name given in the array matches the test name typed into the "List tests to test in" workflow option. +When to update: +This script should be updated whenever a new feature/new page that has the bottom nav bar is added to the app. See https://department-of-veterans-affairs.github.io/va-mobile-app/docs/QA/QualityAssuranceProcess/Automation/AddingNewFeatures for more information. +*/ import { by, device, element, expect, waitFor } from 'detox' import { setTimeout } from 'timers/promises' @@ -37,18 +46,6 @@ const navigationDic = { ['Claims.e2e', ['Claims', 'Claims history', 'Active'], 'Your active claims, decision reviews, and appeals'], ['Claims.e2e', ['Claims', 'Claims history', 'Received July 20, 2021'], 'Claim details'], //['Claims.e2e', ['Claims', 'Claims history', 'Received July 20, 2021', 'Submit evidence'], 'Submit evidence'], - ['Claims.e2e', ['Claims', 'Claims history', 'Received January 01, 2021', 'Review file requests'], 'File requests'], - [ - 'Claims.e2e', - [ - 'Claims', - 'Claims history', - 'Received January 01, 2021', - 'Review file requests', - 'Dental disability - More information needed', - ], - 'Dental disability - More information needed', - ], ['Claims.e2e', ['Claims', 'Claims history', 'Received July 20, 2021', 'Files'], 'JESSE_GRAY_600246732_526.pdf'], [['Appeals.e2e', 'AppealsExpanded.e2e'], ['Claims', 'Claims history', 'Received July 17, 2008'], 'Appeal details'], [ @@ -96,8 +93,6 @@ const featureID = { 'Received July 20, 2021': 'claimsHistoryID', 'Received January 01, 2021': 'claimsHistoryID', 'Received July 17, 2008': 'claimsHistoryID', - 'Review file requests': 'claimStatusDetailsID', - 'Dental disability - More information needed': 'fileRequestPageTestID', 'Review letters': 'lettersPageID', Health: 'healthCategoryTestID', Appointments: 'appointmentsTestID', @@ -110,6 +105,8 @@ const featureID = { let scrollID let textResized +/*Constants for accessibility related command line options. +Any new accessibility related command line options should be added here. */ export const NavigationE2eConstants = { DARK_MODE_OPTIONS: device.getPlatform() === 'ios' ? 'xcrun simctl ui booted appearance dark' : 'adb shell "cmd uimode night yes"', @@ -127,6 +124,12 @@ export const NavigationE2eConstants = { DISPLAY_RESIZING_RESET: 'adb shell wm density reset', } +/* +Takes a screenshot for each accessibility option and compares it to a known screenshot (when done locally). +param key: Dictionary key from navigationDic. Corresponds to the sections given on the lower nav bar (Home, Health, Benefits, Payments) +param navigationDicValue: Dictionary value from navigationDic. Corresponds to the feature in the section that has a lower nav bar +param accessibilityFeatureType: String value that tells the test what accessability test to run or null value that verifies that a feature is in the right place navigation wise +*/ const accessibilityOption = async (key, navigationDicValue, accessibilityFeatureType: string | null) => { const navigationArray = navigationDicValue if (accessibilityFeatureType === 'landscape') { @@ -215,12 +218,7 @@ const navigateToPage = async (key, navigationDicValue) => { } else { const subNavigationArray = navigationArray[1] for (let k = 0; k < subNavigationArray.length - 1; k++) { - if (subNavigationArray[k] === 'Review file requests') { - await waitFor(element(by.id(CommonE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID))) - .toBeVisible() - .whileElement(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_SCREEN_ID)) - .scroll(100, 'up') - } else if (subNavigationArray[k] === 'Received July 17, 2008') { + if (subNavigationArray[k] === 'Received July 17, 2008') { await waitFor(element(by.text('Received July 17, 2008'))) .toBeVisible() .whileElement(by.id(CommonE2eIdConstants.CLAIMS_HISTORY_SCROLL_ID)) @@ -247,12 +245,7 @@ const navigateToPage = async (key, navigationDicValue) => { await element(by.text(subNavigationArray[k])).tap() } - if (subNavigationArray.slice(-1)[0] === 'Review file requests') { - await waitFor(element(by.id(CommonE2eIdConstants.ALERT_FILE_REQUEST_BUTTON_ID))) - .toBeVisible() - .whileElement(by.id(CommonE2eIdConstants.CLAIMS_DETAILS_SCREEN_ID)) - .scroll(100, 'up') - } else if (subNavigationArray.slice(-1)[0] === 'Get prescription details') { + if (subNavigationArray.slice(-1)[0] === 'Get prescription details') { await waitFor(element(by.label('CAPECITABINE 500MG TAB.'))) .toBeVisible() .whileElement(by.id(CommonE2eIdConstants.PRESCRIPTION_HISTORY_SCROLL_ID)) diff --git a/VAMobile/e2e/tests/Onboarding.e2e.ts b/VAMobile/e2e/tests/Onboarding.e2e.ts index 7a6c41c3f69..a5ffd9c8017 100644 --- a/VAMobile/e2e/tests/Onboarding.e2e.ts +++ b/VAMobile/e2e/tests/Onboarding.e2e.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script that follows the Sign in Splash screens (onboarding) test case found in testRail (VA Mobile App > RC Regression Test > Manual > First Launch / Sign In) +When to update: +This script should be updated whenever new things are added/changed to the onboarding flow. +*/ import { by, device, element, expect } from 'detox' import { CommonE2eIdConstants, checkImages, loginToDemoMode } from './utils' diff --git a/VAMobile/e2e/tests/Payments.e2e.ts b/VAMobile/e2e/tests/Payments.e2e.ts index 04c750c24b2..f719f1f9c69 100644 --- a/VAMobile/e2e/tests/Payments.e2e.ts +++ b/VAMobile/e2e/tests/Payments.e2e.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script that follows the VA Payment History test case found in testRail (VA Mobile App > RC Regression Test > Manual > Payments Page - Elements) +When to update: +This script should be updated whenever new things are added/changed in payments or if anything is changed in src/store/api/demo/mocks/payments.json. +*/ import { by, device, element, expect, waitFor } from 'detox' import { CommonE2eIdConstants, loginToDemoMode, openPayments, openVAPaymentHistory } from './utils' diff --git a/VAMobile/e2e/tests/PersonalInformationScreen.e2e.ts b/VAMobile/e2e/tests/PersonalInformationScreen.e2e.ts index 7e527f70531..8666ded18f5 100644 --- a/VAMobile/e2e/tests/PersonalInformationScreen.e2e.ts +++ b/VAMobile/e2e/tests/PersonalInformationScreen.e2e.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script that follows the Personal Information, Personal Info - Gender Identity, and Personal Info - Preferred Name test cases found in testRail (VA Mobile App > RC Regression Test > Manual > Profile Page - Elements) +When to update: +This script should be updated whenever new things are added/changed in personal information, gender identity, or preferred name or if anything is changed in src/store/api/demo/mocks/personalInformation.json or src/store/api/demo/mocks/demographics.json. +*/ import { by, device, element, expect, waitFor } from 'detox' import { setTimeout } from 'timers/promises' @@ -32,6 +38,11 @@ export const PersonalInfoConstants = { PERSONAL_INFO_SCROLL_ID: 'PersonalInformationTestID', } +/** This function will scroll to and tap the link. +* @param text: String text of either the text of the link (if id is false) or the testID of the link (if id is true) +* @param scrollID: String text of the testID of the page with the scrollView +* @param id: Boolean value for whether the link is searching by.text or by.id +* */ const scrollToThenTap = async (text: string, scrollID?: string, id?: boolean) => { if (scrollID != undefined) { await element(by.id(scrollID)).atIndex(0).scrollTo('bottom') @@ -47,6 +58,9 @@ const scrollToThenTap = async (text: string, scrollID?: string, id?: boolean) => } } +/** This function will check the nearest VA center and call links. This script is only run on the Android simulator because the iOS simulator does not have phone capabilities +* @param scrollID: String text of the testID of the page with the scrollView +* */ const checkLocatorAndContactLinks = async (scrollID?: string) => { await device.disableSynchronization() await scrollToThenTap(PersonalInfoConstants.NEAREST_CENTER_LINK_ID, scrollID, true) @@ -67,6 +81,9 @@ const checkLocatorAndContactLinks = async (scrollID?: string) => { await device.enableSynchronization() } +/** This function will update the gender identity and verify that the new gender identity is displayed. +* @param genderIdentityOption: String text of the gender identity option to verify +* */ export async function updateGenderIdentify(genderIdentityOption) { it('should update gender identity for ' + genderIdentityOption, async () => { await element(by.id(PersonalInfoConstants.PERSONAL_INFO_SCROLL_ID)).scrollTo('bottom') @@ -80,7 +97,7 @@ export async function updateGenderIdentify(genderIdentityOption) { await expect(element(by.text(PersonalInfoConstants.PERSONAL_INFORMATION_TEXT))).toExist() await expect(element(by.text('Gender identity saved'))).toExist() await expect(element(by.text(genderIdentityOption))).toExist() - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() await element(by.id(PersonalInfoConstants.PERSONAL_INFO_SCROLL_ID)).scrollTo('bottom') await element(by.id(PersonalInfoConstants.GENDER_IDENTITY_ROW_ID)).tap() @@ -102,10 +119,10 @@ describe('Personal Info Screen', () => { await expect(element(by.text('Date of birth'))).toExist() await expect(element(by.text('January 01, 1950'))).toExist() - await expect(element(by.text('Preferred name'))).toExist() + await expect(element(by.text(PersonalInfoConstants.PREFERRED_NAME_HEADER_TEXT))).toExist() await expect(element(by.text('Sharing your preferred name is optional.'))).toExist() - await expect(element(by.text('Gender identity'))).toExist() + await expect(element(by.text(PersonalInfoConstants.GENDER_IDENTITY_HEADER_TEXT))).toExist() await expect(element(by.text('Woman'))).toExist() }) @@ -143,7 +160,7 @@ describe('Personal Info Screen', () => { await expect(element(by.text(PersonalInfoConstants.PREFERRED_NAME_HEADER_TEXT)).atIndex(0)).toExist() await element(by.id(PersonalInfoConstants.PREFERRED_NAME_ID)).replaceText('Kimberlee') await element(by.id(PersonalInfoConstants.PREFERRED_NAME_ID)).tapReturnKey() - await element(by.text('Save')).tap() + await element(by.text(CommonE2eIdConstants.SAVE_TEXT)).tap() await expect(element(by.text(PersonalInfoConstants.PERSONAL_INFORMATION_TEXT)).atIndex(0)).toExist() await expect(element(by.text('Preferred name saved'))).toExist() diff --git a/VAMobile/e2e/tests/Prescriptions.e2e.ts b/VAMobile/e2e/tests/Prescriptions.e2e.ts index 23eced83151..1dee3829c45 100644 --- a/VAMobile/e2e/tests/Prescriptions.e2e.ts +++ b/VAMobile/e2e/tests/Prescriptions.e2e.ts @@ -38,7 +38,6 @@ export const PrescriptionsE2eIdConstants = { "This list shows refill requests you've submitted. It also shows refills the V-A pharmacy is processing.", PRESCRIPTION_TRACKING_GET_TRACKING_ID: 'getPrescriptionTrackingTestID', PRESCRIPTION_REFILL_NAME_TEXT: 'AMLODIPINE BESYLATE 10MG TAB', - PRESCRIPTION_REFILL_DIALOG_YES_TEXT: device.getPlatform() === 'ios' ? 'Request Refill' : 'Request Refill ', PRESCRIPTION_REFILL_REQUEST_SUMMARY_TEXT: 'We got your refill requests', PRESCRIPTION_REFILL_REQUEST_SUMMARY_HEADER_TEXT: 'Refill request summary', PRESCRIPTION_REFILL_REQUEST_SUMMARY_NAME_TEXT: 'AMLODIPINE BESYLATE 10MG TAB', @@ -422,7 +421,7 @@ describe('Prescriptions Screen', () => { it('verify refill request summary screen information', async () => { await element(by.id(PrescriptionsE2eIdConstants.PRESCRIPTION_REQUEST_REFILL_ID)).tap() - await element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_DIALOG_YES_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.PRESCRIPTION_REFILL_DIALOG_YES_TEXT)).tap() await expect(element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_REQUEST_SUMMARY_TEXT))).toExist() await expect( element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_REQUEST_SUMMARY_HEADER_TEXT)), @@ -459,7 +458,7 @@ describe('Prescriptions Screen', () => { .scroll(500, 'down') await element(by.label(PrescriptionsE2eIdConstants.PRESCRIPTION_DETAILS_LABEL)).atIndex(0).tap() await element(by.id(PrescriptionsE2eIdConstants.PRESCRIPTION_REQUEST_REFILL_ID)).tap() - await element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_DIALOG_YES_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.PRESCRIPTION_REFILL_DIALOG_YES_TEXT)).tap() await expect(element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_REQUEST_SUMMARY_TEXT))).toExist() await expect( element(by.text(PrescriptionsE2eIdConstants.PRESCRIPTION_REFILL_REQUEST_SUMMARY_HEADER_TEXT)), diff --git a/VAMobile/e2e/tests/ProfileScreen.e2e.ts b/VAMobile/e2e/tests/ProfileScreen.e2e.ts index e63159af5e3..2200e225797 100644 --- a/VAMobile/e2e/tests/ProfileScreen.e2e.ts +++ b/VAMobile/e2e/tests/ProfileScreen.e2e.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script that follows the profile page test case found in testRail (VA Mobile App > RC Regression Test > Manual > Profile Page - Elements) +When to update: +This script should be updated whenever new menu options are added/changed in the profile page. +*/ import { by, element, expect, waitFor } from 'detox' import { CommonE2eIdConstants, loginToDemoMode, openProfile } from './utils' @@ -5,7 +11,6 @@ import { CommonE2eIdConstants, loginToDemoMode, openProfile } from './utils' export const ProfileE2eIdConstants = { PROFILE_TEXT: 'Profile', BANNER_NAME_ID: 'Kimberly Washington', - BANNER_BRANCH_ID: 'United States Coast Guard', } beforeAll(async () => { @@ -27,6 +32,6 @@ describe('Profile Screen', () => { it('should show profile banner elements', async () => { await expect(element(by.text(ProfileE2eIdConstants.BANNER_NAME_ID))).toExist() - await expect(element(by.text(ProfileE2eIdConstants.BANNER_BRANCH_ID))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_BRANCH_COAST_GUARD))).toExist() }) }) diff --git a/VAMobile/e2e/tests/PushNotifications.e2e.ts b/VAMobile/e2e/tests/PushNotifications.e2e.ts index ec3984364f6..a7014ea8bf7 100644 --- a/VAMobile/e2e/tests/PushNotifications.e2e.ts +++ b/VAMobile/e2e/tests/PushNotifications.e2e.ts @@ -1,9 +1,15 @@ +/* +Description: +Detox script that follows the notifications test cases found in testRail (VA Mobile App > Active/Organized Cases > Home > Profile > Settings > Notifications) +More information about detox and mocking user notifications can be found here: https://wix.github.io/Detox/docs/guide/mocking-user-notifications +When to update: +This script should be updated whenever any new notification types are added to the app and or if anything changes on how the notification is displayed in the app. +*/ import { by, device, element, expect, waitFor } from 'detox' import { backButton, loginToDemoMode } from './utils' const PushNotificationsConstants = { - HEALTH_SCREEN_TITLE: 'Health', MESSAGE_COMPOSE_BUTTON_TEXT: 'Start new message', REVIEW_MESSAGE_SCREEN_TITLE: 'Review message', } @@ -19,6 +25,7 @@ const mockNotification = { }, } +//This script is only run on iOS because there are additional requirements that can't be met for Android describe(':ios: Push Notifications', () => { it('dead state: should navigate to appropriate screen when launching', async () => { await device.launchApp({ diff --git a/VAMobile/e2e/tests/SettingsScreen.e2e.ts b/VAMobile/e2e/tests/SettingsScreen.e2e.ts index a9c5aec0a9e..b67a31a8c4b 100644 --- a/VAMobile/e2e/tests/SettingsScreen.e2e.ts +++ b/VAMobile/e2e/tests/SettingsScreen.e2e.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script that follows the settings test case found in testRail (VA Mobile App > RC Regression Test > Manual > Profile Page - Elements) +When to update: +This script should be updated whenever new items are added to the settings screen list or there are any changes within the settings screen options. +*/ import { by, device, element, expect, waitFor } from 'detox' import { setTimeout } from 'timers/promises' @@ -63,6 +69,7 @@ describe('Settings Screen', () => { await element(by.id(SettingsE2eIdConstants.BACK_TO_SETTINGS_SCREEN_ID)).tap() }) + //The share the app dialog in the android simulator does not go away on device.launchApp. For this reason this test is only run on iOS. it('should show "Share the app" screen', async () => { if (device.getPlatform() === 'ios') { await element(by.id(SettingsE2eIdConstants.SHARE_APP_ROW_ID)).tap() diff --git a/VAMobile/e2e/tests/SignIn.e2e.ts b/VAMobile/e2e/tests/SignIn.e2e.ts index 30743d6eaee..c28c8449a77 100644 --- a/VAMobile/e2e/tests/SignIn.e2e.ts +++ b/VAMobile/e2e/tests/SignIn.e2e.ts @@ -4,14 +4,11 @@ import { setTimeout } from 'timers/promises' import { CommonE2eIdConstants } from './utils' export const SignE2eIdConstants = { - LOGIN_PAGE_ID: 'Login-page', LOA_P1_TEXT: - 'Before we give you access to your VA claim and health care information, we need to make sure you’re you. This helps us protect you from fraud and identity theft.', - LOA_P2_TEXT: 'If you haven’t yet verified your identity, we’ll help you complete the process when you sign in.', - LOA_GATE_EXPAND_MSG_ID: 'loaGateExpandMsgID', - LOA_GATE_READ_MORE_P1: - 'We’ll verify your identity through a secure process from ID.me or Login.gov. This trusted partner provides the strongest identity verification system available.', - LOA_GATE_READ_MORE_P2: 'To complete the process on your smartphone, you’ll need these items:', + 'You’ll need to sign in with an identity-verified account through one of our account providers. Identity verification helps us protect all Veterans’ information and prevent scammers from stealing your benefits.', + LOA_P2_TEXT: + 'Don’t yet have a verified account? Continue to the sign-in page. Follow the instructions to create a Login.gov or ID.me account. Then come back here and sign in. We’ll help you verify your identity for your account.', + LOA_P3_TEXT: 'Not sure if your account is verified? Sign in now. We’ll tell you if you need to verify.', CONTINUE_SIGN_IN_BTN_ID: 'Continue to sign in', } @@ -34,7 +31,7 @@ describe('Sign In', () => { await expect(element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BTN_ID))).toExist() await expect(element(by.text(SignE2eIdConstants.LOA_P1_TEXT))).toExist() await expect(element(by.text(SignE2eIdConstants.LOA_P2_TEXT))).toExist() - await expect(element(by.id(SignE2eIdConstants.LOA_GATE_EXPAND_MSG_ID))).toExist() + await expect(element(by.text(SignE2eIdConstants.LOA_P3_TEXT))).toExist() await expect(element(by.id(SignE2eIdConstants.CONTINUE_SIGN_IN_BTN_ID))).toExist() }) @@ -43,12 +40,6 @@ describe('Sign In', () => { await element(by.id(CommonE2eIdConstants.SIGN_IN_BTN_ID)).tap() await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BTN_ID)).tap() await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BACK_ID)).tap() - await element(by.id(SignE2eIdConstants.LOA_GATE_EXPAND_MSG_ID)).tap() - await expect(element(by.text(SignE2eIdConstants.LOA_GATE_READ_MORE_P1))).toExist() - await expect(element(by.text(SignE2eIdConstants.LOA_GATE_READ_MORE_P2))).toExist() - await element(by.id(SignE2eIdConstants.LOA_GATE_EXPAND_MSG_ID)).tap() - await expect(element(by.text(SignE2eIdConstants.LOA_GATE_READ_MORE_P1))).not.toExist() - await expect(element(by.text(SignE2eIdConstants.LOA_GATE_READ_MORE_P2))).not.toExist() await element(by.id(SignE2eIdConstants.CONTINUE_SIGN_IN_BTN_ID)).tap() await setTimeout(7000) await device.takeScreenshot('VALoginWebview') diff --git a/VAMobile/e2e/tests/VaccineRecords.e2e.ts b/VAMobile/e2e/tests/VaccineRecords.e2e.ts index fb1d2a7cf4f..887010569cd 100644 --- a/VAMobile/e2e/tests/VaccineRecords.e2e.ts +++ b/VAMobile/e2e/tests/VaccineRecords.e2e.ts @@ -4,9 +4,10 @@ Detox script that follows the vaccines - view list of all immunization records a When to update: This script should be updated whenever new things are added/changed in vaccines or if anything is changed in src/store/api/demo/mocks/vaccine.json. */ +import { combineReducers } from '@reduxjs/toolkit' import { by, element, expect } from 'detox' -import { checkImages, loginToDemoMode, openHealth, openVaccineRecords } from './utils' +import { CommonE2eIdConstants, checkImages, loginToDemoMode, openHealth, openVaccineRecords } from './utils' export const VaccinesE2eIdConstants = { VACCINE_1_ID: 'COVID-19 vaccine January 14, 2021', @@ -43,7 +44,7 @@ describe('Vaccine Records Screen', () => { await expect(element(by.id('Type And Dosage COVID-19, mRNA, LNP-S, PF, 100 mcg/ 0.5 mL dose'))).toExist() await expect(element(by.id('Manufacturer Moderna US, Inc.'))).toExist() await expect(element(by.id('Series status None noted'))) - await expect(element(by.text('Cheyenne VA Medical Center'))).toExist() + await expect(element(by.text(CommonE2eIdConstants.CHEYENNE_FACILITY_TEXT))).toExist() await expect(element(by.text('2360 East Pershing Boulevard'))).toExist() await expect(element(by.text('Cheyenne, WY 82001-5356'))).toExist() await expect(element(by.text('Reaction'))).toExist() diff --git a/VAMobile/e2e/tests/VeteranStatusCard.e2e.ts b/VAMobile/e2e/tests/VeteranStatusCard.e2e.ts index d8356dda8b1..6339b541a77 100644 --- a/VAMobile/e2e/tests/VeteranStatusCard.e2e.ts +++ b/VAMobile/e2e/tests/VeteranStatusCard.e2e.ts @@ -20,11 +20,8 @@ import { export const VeteranStatusCardConstants = { VETERAN_STATUS_ID: 'veteranStatusButtonID', - VETERAN_STATUS_NAME_TEXT: 'Kimberly Washington', - VETERAN_STATUS_MILITARY_BRANCH_TEXT: 'United States Coast Guard', VETERAN_STATUS_DISABILITY_RATING_TEXT: '100% service connected', VETERAN_STATUS_PERIOD_OF_SERVICE_BRANCH_1_TEXT: 'United States Army', - VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_1_TEXT: 'July 13, 1970 – August 31, 1998', VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_2_TEXT: 'September 01, 1998 – January 01, 2000', VETERAN_STATUS_DISCLAIMER_TEXT: "You can use this Veteran status to prove you served in the United States Uniformed Services. This status doesn't entitle you to any VA benefits.", @@ -51,6 +48,7 @@ export async function validateVeteranStatusDesign() { await expect(element(by.id('veteranStatusBranchTestID'))).toExist() await expect(element(by.id('veteranStatusDisabilityRatingTestID'))).toExist() await expect(element(by.id('veteranStatusMilitaryServiceTestID')).atIndex(0)).toExist() + await expect(element(by.id('veteranStatusDODTestID'))).toExist() await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_DISCLAIMER_TEXT))).toExist() await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_DOB_DISABILITY_ERROR_PHONE_TEXT))).toExist() await expect(element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0)).toExist() @@ -77,7 +75,7 @@ export async function tapPhoneAndTTYLinks() { await element(by.id('veteranStatusTestID')).scrollTo('bottom') await element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0).tap() try { - await element(by.text('Dismiss')).tap() + await element(by.text(CommonE2eIdConstants.DISMISS_TEXT)).tap() await element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0).tap() } catch (e) {} await setTimeout(2000) @@ -110,7 +108,7 @@ export async function verifyMilitaryInfo(militaryBranch) { await element(by.text('Home')).tap() await waitFor(element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_ID))) .toBeVisible() - .whileElement(by.id('homeScreenID')) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_ID)).tap() await expect(element(by.text(militaryBranch)).atIndex(1)).toExist() @@ -129,7 +127,7 @@ describe('Veteran Status Card', () => { it('should match design in the home screen', async () => { await waitFor(element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_ID))) .toBeVisible() - .whileElement(by.id('homeScreenID')) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_ID)).tap() await validateVeteranStatusDesign() @@ -149,15 +147,15 @@ describe('Veteran Status Card', () => { it('verify the period of service matches app', async () => { await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_BRANCH_1_TEXT))).toExist() - await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_1_TEXT))).toExist() - await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_MILITARY_BRANCH_TEXT)).atIndex(1)).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_PERIOD_OF_SERVICE))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_BRANCH_COAST_GUARD)).atIndex(1)).toExist() await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_2_TEXT))).toExist() await element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_CLOSE_ID)).tap() await setTimeout(2000) await openMilitaryInformation() await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_BRANCH_1_TEXT))).toExist() - await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_1_TEXT))).toExist() - await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_MILITARY_BRANCH_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_PERIOD_OF_SERVICE))).toExist() + await expect(element(by.text(CommonE2eIdConstants.MILITARY_BRANCH_COAST_GUARD))).toExist() await expect(element(by.text(VeteranStatusCardConstants.VETERAN_STATUS_PERIOD_OF_SERVICE_PERIOD_2_TEXT))).toExist() await element(by.id(VeteranStatusCardConstants.BACK_TO_PROFILE_ID)).tap() }) @@ -168,7 +166,7 @@ describe('Veteran Status Card', () => { await element(by.id(VeteranStatusCardConstants.VETERAN_STATUS_CLOSE_ID)).tap() await openBenefits() await openDisabilityRating() - await expect(element(by.text('100%')).atIndex(1)).toExist() + await expect(element(by.text(CommonE2eIdConstants.DISABILITY_RATING_PERCENT_TEXT)).atIndex(1)).toExist() }) verifyMilitaryInfo('United States Coast Guard') diff --git a/VAMobile/e2e/tests/VeteransCrisisLine.e2e.ts b/VAMobile/e2e/tests/VeteransCrisisLine.e2e.ts index 6edbc1c830a..85d33f4ebc0 100644 --- a/VAMobile/e2e/tests/VeteransCrisisLine.e2e.ts +++ b/VAMobile/e2e/tests/VeteransCrisisLine.e2e.ts @@ -10,17 +10,11 @@ import { setTimeout } from 'timers/promises' import { CommonE2eIdConstants, loginToDemoMode, openVeteransCrisisLine } from './utils' export const VCLConstants = { - HEADING_TEXT: 'Veterans Crisis Line', SUBHEADING_TEXT: 'We’re here anytime, day or night – 24/7', MESSAGE_TEXT: "If you're a Veteran in crisis or concerned about one, connect with our caring, qualified responders for confidential help. Many of them are Veterans themselves.", - PHONE_LINK_ID: 'veteransCrisisLineCallID', - TEXT_MESSAGE_LINK_ID: 'veteransCrisisLineTextNumberTestID', - CHAT_LINK_ID: 'veteransCrisisLineConfidentialChatTestID', - TTY_LINK_ID: 'veteransCrisisLineHearingLossNumberTestID', MORE_RESOURCES_TEXT: 'Get more resources', VCL_SITE_LINK_ID: 'veteransCrisisLineGetMoreResourcesTestID', - BACK_ID: 'veteranCrisisLineBackID', } const tapAndTakeScreenshot = async (text: string, screenshotName: string) => { @@ -39,7 +33,7 @@ beforeAll(async () => { describe('Veterans Crisis Line', () => { it('should match design', async () => { - await expect(element(by.text(VCLConstants.HEADING_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.VETERAN_CRISIS_LINE_HEADING_TEXT))).toExist() await expect(element(by.text(VCLConstants.SUBHEADING_TEXT))).toExist() await expect(element(by.text(VCLConstants.MESSAGE_TEXT))).toExist() await expect(element(by.text(VCLConstants.MORE_RESOURCES_TEXT))).toExist() @@ -47,19 +41,19 @@ describe('Veterans Crisis Line', () => { if (device.getPlatform() === 'android') { it('should open phone link', async () => { - await tapAndTakeScreenshot(VCLConstants.PHONE_LINK_ID, 'CrisisLinePhone') + await tapAndTakeScreenshot(CommonE2eIdConstants.VETERANS_CRISIS_LINE_CALL_ID, 'CrisisLinePhone') }) it('should open TTY link', async () => { - await tapAndTakeScreenshot(VCLConstants.TTY_LINK_ID, 'CrisisLineTTY') + await tapAndTakeScreenshot(CommonE2eIdConstants.VETERANS_CRISIS_LINE_TTY_ID, 'CrisisLineTTY') }) } it('should open text message link', async () => { - await tapAndTakeScreenshot(VCLConstants.TEXT_MESSAGE_LINK_ID, 'CrisisLineTextMessage') + await tapAndTakeScreenshot(CommonE2eIdConstants.VETERANS_CRISIS_LINE_TEXT_ID, 'CrisisLineTextMessage') }) it('should open chat link', async () => { - await element(by.id(VCLConstants.CHAT_LINK_ID)).tap() + await element(by.id(CommonE2eIdConstants.VETERANS_CRISIS_LINE_CHAT_ID)).tap() await element(by.text(CommonE2eIdConstants.LEAVING_APP_LEAVE_TEXT)).tap() await setTimeout(5000) await device.takeScreenshot('CrisisLineChat') @@ -75,7 +69,7 @@ describe('Veterans Crisis Line', () => { }) it('should close panel', async () => { - await element(by.id(VCLConstants.BACK_ID)).tap() + await element(by.id(CommonE2eIdConstants.VETERAN_CRISIS_LINE_BACK_ID)).tap() await expect(element(by.text(CommonE2eIdConstants.HOME_ACTIVITY_HEADER_TEXT))).toExist() }) }) diff --git a/VAMobile/e2e/tests/utils.ts b/VAMobile/e2e/tests/utils.ts index 294f9169987..564ed270373 100644 --- a/VAMobile/e2e/tests/utils.ts +++ b/VAMobile/e2e/tests/utils.ts @@ -1,3 +1,9 @@ +/* +Description: +Detox script for functions/constants that effect multiple other scripts. +When to update: +New functions/constants should be added when anything is created that might effect multiple scripts. +*/ import { expect as jestExpect } from '@jest/globals' import { by, device, element, expect, waitFor } from 'detox' import { setTimeout } from 'timers/promises' @@ -23,86 +29,127 @@ const mockNotification = { } export const CommonE2eIdConstants = { - VA_LOGO_ICON_ID: 'va-icon', - DEMO_MODE_INPUT_ID: 'demo-mode-password', - DEMO_BTN_ID: 'demo-btn', - SIGN_IN_BTN_ID: 'Sign in', - TURN_ON_NOTIFICATIONS_TEXT: 'Turn on notifications', - VETERAN_CRISIS_LINE_BTN_TEXT: 'Talk to the Veterans Crisis Line now', - VETERAN_CRISIS_LINE_BTN_ID: 'veteransCrisisLineID', - VETERAN_CRISIS_LINE_BACK_ID: 'veteranCrisisLineBackID', - HEALTH_TAB_BUTTON_TEXT: 'Health', - PAYMENTS_TAB_BUTTON_TEXT: 'Payments', - BENEFITS_TAB_BUTTON_TEXT: 'Benefits', - HOME_TAB_BUTTON_TEXT: 'Home', - SETTINGS_ROW_TEXT: 'Settings', + //device-specific + OK_PLATFORM_SPECIFIC_TEXT: device.getPlatform() === 'ios' ? 'Ok' : 'OK', + CANCEL_PLATFORM_SPECIFIC_TEXT: device.getPlatform() === 'ios' ? 'Cancel' : 'Cancel ', + CAMERA_TEXT: device.getPlatform() === 'ios' ? 'Camera' : 'Camera ', + PHOTO_GALLERY_TEXT: device.getPlatform() === 'ios' ? 'Photo Gallery' : 'Photo gallery ', + FILE_FOLDER_TEXT: device.getPlatform() === 'ios' ? 'File Folder' : 'File folder ', + CANCEL_DELETE_CHANGES_BUTTON_TEXT: device.getPlatform() === 'ios' ? 'Delete Changes' : 'Delete Changes ', + CANCEL_KEEP_EDITING_TEXT: device.getPlatform() === 'ios' ? 'Keep Editing' : 'Keep Editing ', + //universal + SAVE_TEXT: 'Save', + ENABLED_TEXT: 'Enabled', + PREVIOUS_PAGE_ID: 'previous-page', + NEXT_PAGE_ID: 'next-page', BACK_BTN_LABEL: 'Back', LEAVING_APP_POPUP_TEXT: 'Leave the mobile app?', LEAVING_APP_CANCEL_TEXT: 'Go back', LEAVING_APP_LEAVE_TEXT: 'Leave', CANCEL_UNIVERSAL_TEXT: 'Cancel', OK_UNIVERSAL_TEXT: 'OK', - CLAIMS_HISTORY_BUTTON_ID: 'toClaimsHistoryID', - CANCEL_PLATFORM_SPECIFIC_TEXT: device.getPlatform() === 'ios' ? 'Cancel' : 'Cancel ', - RESET_INAPP_REVIEW_BUTTON_TEXT: 'Reset in-app review actions', - REMOTE_CONFIG_TEST_ID: 'remoteConfigTestID', - REMOTE_CONFIG_BUTTON_TEXT: 'Remote Config', - APPLY_OVERRIDES_BUTTON_TEXT: 'Apply Overrides', - OK_PLATFORM_SPECIFIC_TEXT: device.getPlatform() === 'ios' ? 'Ok' : 'OK', - UPCOMING_APPT_BUTTON_TEXT: 'Upcoming', - START_NEW_MESSAGE_BUTTON_ID: 'startNewMessageButtonTestID', - PRESCRIPTION_REFILL_BUTTON_TEXT: 'Start refill request', - PRESCRIPTION_REFILL_BUTTON_ID: 'refillRequestTestID', - HOME_ACTIVITY_HEADER_TEXT: 'Activity', - IN_APP_REVIEW_TOGGLE_TEXT: 'inAppReview', - CONTACT_INFO_SAVE_ID: 'contactInfoSaveTestID', - CONTACT_INFO_SUGGESTED_ADDRESS_ID: 'suggestedAddressTestID', - CONTACT_INFO_USE_THIS_ADDRESS_ID: 'Use this address', - CONTACT_INFO_STREET_ADDRESS_LINE_2_ID: 'streetAddressLine2TestID', + DISMISS_TEXT: 'Dismiss', CALL_VA_PHONE_NUMBER_ID: 'CallVATestID', CALL_VA_TTY_PHONE_NUMBER_ID: 'CallTTYTestID', - APPOINTMENTS_SCROLL_ID: 'appointmentsTestID', GO_TO_VA_GOV_LINK_ID: 'goToVAGovID', - CLAIMS_HISTORY_SCROLL_ID: 'claimsHistoryID', - NEXT_PAGE_ID: 'next-page', + VETERAN_CRISIS_LINE_HEADING_TEXT: 'Veterans Crisis Line', + VETERAN_CRISIS_LINE_BTN_TEXT: 'Talk to the Veterans Crisis Line now', + VETERAN_CRISIS_LINE_BTN_ID: 'veteransCrisisLineID', + VETERAN_CRISIS_LINE_BACK_ID: 'veteranCrisisLineBackID', VETERANS_CRISIS_LINE_CALL_ID: 'veteransCrisisLineCallID', VETERANS_CRISIS_LINE_TTY_ID: 'veteransCrisisLineHearingLossNumberTestID', VETERANS_CRISIS_LINE_TEXT_ID: 'veteransCrisisLineTextNumberTestID', VETERANS_CRISIS_LINE_CHAT_ID: 'veteransCrisisLineConfidentialChatTestID', - PREVIOUS_PAGE_ID: 'previous-page', - CLAIMS_DETAILS_BACK_ID: 'claimsDetailsBackTestID', - CLAIMS_HISTORY_BACK_ID: 'claimsHistoryBackTestID', - CLAIMS_HISTORY_CLOSED_TAB_ID: 'claimsHistoryClosedID', + MILITARY_BRANCH_COAST_GUARD: 'United States Coast Guard', + MILITARY_PERIOD_OF_SERVICE: 'July 13, 1970 – August 31, 1998', + //login, home, nav bar + VA_LOGO_ICON_ID: 'va-icon', + DEMO_MODE_INPUT_ID: 'demo-mode-password', + DEMO_BTN_ID: 'demo-btn', + SIGN_IN_BTN_ID: 'Sign in', SKIP_BACK_BUTTON_ID: 'onboardingSkipBackButtonID', + TURN_ON_NOTIFICATIONS_TEXT: 'Turn on notifications', + HOME_ACTIVITY_HEADER_TEXT: 'Activity', + HEALTH_TAB_BUTTON_TEXT: 'Health', + PAYMENTS_TAB_BUTTON_TEXT: 'Payments', + BENEFITS_TAB_BUTTON_TEXT: 'Benefits', + HOME_TAB_BUTTON_TEXT: 'Home', HEALTH_TAB_BUTTON_ID: 'Health', PAYMENTS_TAB_BUTTON_ID: 'Payments', BENEFITS_TAB_BUTTON_ID: 'Benefits', HOME_TAB_BUTTON_ID: 'Home', - AF_APP_UPDATE_BUTTON_TOGGLE_ID: 'remoteConfigAppUpdateTestID', - AF_ENABLE_TOGGLE_ID: 'remoteConfigEnableTestID', + PROFILE_HEADER_BUTTON_ID: 'toProfileScreenID', + HOME_SCREEN_SCROLL_ID: 'homeScreenID', + DISABILITY_RATING_PERCENT_TEXT: '100%', + //health + UPCOMING_APPT_BUTTON_TEXT: 'Upcoming', + APPOINTMENTS_SCROLL_ID: 'appointmentsTestID', + APPOINTMENTS_BUTTON_ID: 'toAppointmentsID', + ADD_TO_CALENDAR_ID: 'addToCalendarTestID', + GET_DIRECTIONS_ID: 'directionsTestID', + DATE_RANGE_INITIAL_TEXT: 'Past 3 months', + START_NEW_MESSAGE_BUTTON_ID: 'startNewMessageButtonTestID', + MESSAGES_INBOX_BUTTON_ID: 'toMessageInboxID', + VIEW_MESSAGE_ID: 'viewMessageTestID', + PRESCRIPTION_REFILL_BUTTON_TEXT: 'Start refill request', + PRESCRIPTION_REFILL_BUTTON_ID: 'refillRequestTestID', + PRESCRIPTION_HISTORY_SCROLL_ID: 'PrescriptionHistory', + PRESCRIPTIONS_BUTTON_ID: 'toPrescriptionsID', + PRESCRIPTION_REFILL_DIALOG_YES_TEXT: device.getPlatform() === 'ios' ? 'Request Refill' : 'Request Refill ', + VACCINES_BUTTON_ID: 'toVaccineListID', + CHEYENNE_FACILITY_TEXT: 'Cheyenne VA Medical Center', + //benefits + CLAIMS_HISTORY_BUTTON_ID: 'toClaimsHistoryID', + CLAIMS_HISTORY_SCROLL_ID: 'claimsHistoryID', + CLAIMS_DETAILS_BACK_ID: 'claimsDetailsBackTestID', + CLAIMS_HISTORY_BACK_ID: 'claimsHistoryBackTestID', + CLAIMS_HISTORY_CLOSED_TAB_ID: 'claimsHistoryClosedID', CLAIMS_DETAILS_SCREEN_ID: 'ClaimDetailsScreen', ALERT_FILE_REQUEST_BUTTON_ID: 'Review file requests', - PRESCRIPTION_HISTORY_SCROLL_ID: 'PrescriptionHistory', - PERSONAL_INFO_BUTTON_ID: 'toPersonalInfoID', - CONTACT_INFO_BUTTON_ID: 'toContactInfoID', - MILITARY_HISTORY_BUTTON_ID: 'toMilitaryHistoryID', - SETTINGS_BUTTON_ID: 'toSettingsID', - PROFILE_SCROLL_ID: 'profileID', CLAIMS_LANDING_BUTTON_ID: 'toClaimsLandingID', + APPEALS_DETAILS_ID: 'appealsDetailsTestID', + CLOSED_CLAIM_DECISION_LETTER_ID: + 'Compensation Decision letter ready Received January 01, 2021 Step 5 of 5: Complete Moved to this step on April 09, 2021', LETTERS_LANDING_BUTTON_ID: 'toLettersLandingID', DISABILITY_RATING_BUTTON_ID: 'toDisabilityRatingID', + //payments PAYMENT_HISTORY_BUTTON_ID: 'toPaymentHistoryID', DIRECT_DEPOSIT_BUTTON_ID: 'toDirectDepositID', - APPOINTMENTS_BUTTON_ID: 'toAppointmentsID', - MESSAGES_INBOX_BUTTON_ID: 'toMessageInboxID', - PRESCRIPTIONS_BUTTON_ID: 'toPrescriptionsID', - VACCINES_BUTTON_ID: 'toVaccineListID', + //profile, settings + PROFILE_SCROLL_ID: 'profileID', + PERSONAL_INFO_BUTTON_ID: 'toPersonalInfoID', + CONTACT_INFO_BUTTON_ID: 'toContactInfoID', + MILITARY_HISTORY_BUTTON_ID: 'toMilitaryHistoryID', + SETTINGS_BUTTON_ID: 'toSettingsID', + SETTINGS_ROW_TEXT: 'Settings', + CONTACT_INFO_SCREEN_ID: 'ContactInfoTestID', + CONTACT_INFO_SAVE_ID: 'contactInfoSaveTestID', + CONTACT_INFO_SUGGESTED_ADDRESS_ID: 'suggestedAddressTestID', + CONTACT_INFO_USE_THIS_ADDRESS_ID: 'Use this address', + CONTACT_INFO_STREET_ADDRESS_LINE_2_ID: 'streetAddressLine2TestID', DEVELOPER_SCREEN_BUTTON_ID: 'toDeveloperScreenID', - PROFILE_HEADER_BUTTON_ID: 'toProfileScreenID', -} - -/** Log the automation into demo mode - * */ + DEVELOPER_SCREEN_SCROLL_ID: 'developerScreenTestID', + RESET_INAPP_REVIEW_BUTTON_TEXT: 'Reset in-app review actions', + REMOTE_CONFIG_TEST_ID: 'remoteConfigTestID', + REMOTE_CONFIG_BUTTON_TEXT: 'Remote Config', + APPLY_OVERRIDES_BUTTON_TEXT: 'Apply Overrides', + IN_APP_REVIEW_TOGGLE_TEXT: 'inAppReview', + AF_APP_UPDATE_BUTTON_TOGGLE_ID: 'remoteConfigAppUpdateTestID', + AF_ENABLE_TOGGLE_ID: 'remoteConfigEnableTestID', + AF_UPDATE_NOW_BUTTON_TEXT: 'Update now', + AF_ERROR_MSG_TITLE_INPUT_ID: 'AFErrorMsgTitleTestID', + AF_ERROR_MSG_TITLE_ENTERED_TEXT: 'AF Heading Test', + AF_ERROR_MSG_BODY_INPUT_ID: 'AFErrorMsgBodyTestID', + AF_BODY_ENTERED_TEXT: 'AF Body Test', + AF_ERROR_MSG_PHONE_ID: 'AFErrorPhoneNumberTestID', + AF_TYPE_INPUT_ID: 'AFTypeTestID', + AF_USE_CASE_TWO_ID: 'AFUseCase2TestID', +} + +/** Logs into demo mode. +* @param skipOnboarding: Boolean value that defaults to true. Set this to false if you want the detox test to view the onboarding carasoul on login +* @param pushNotifications: Boolean value that tells the detox tests whether to turn on/off push notifications +* */ export async function loginToDemoMode(skipOnboarding = true, pushNotifications?: boolean) { try { await waitFor(element(by.id(CommonE2eIdConstants.VA_LOGO_ICON_ID))) @@ -125,6 +172,10 @@ export async function loginToDemoMode(skipOnboarding = true, pushNotifications?: .toExist() .withTimeout(60000) } + await waitFor(element(by.id(CommonE2eIdConstants.VA_LOGO_ICON_ID))) + .toBeVisible() + .whileElement(by.id('Login-page')) + .scroll(100, 'down') await element(by.id(CommonE2eIdConstants.VA_LOGO_ICON_ID)).multiTap(7) if (DEMO_PASSWORD !== undefined) { @@ -134,6 +185,10 @@ export async function loginToDemoMode(skipOnboarding = true, pushNotifications?: await element(by.id(CommonE2eIdConstants.DEMO_MODE_INPUT_ID)).tapReturnKey() await element(by.id(CommonE2eIdConstants.DEMO_BTN_ID)).multiTap(2) + await waitFor(element(by.id(CommonE2eIdConstants.SIGN_IN_BTN_ID))) + .toBeVisible() + .whileElement(by.id('Login-page')) + .scroll(100, 'down') await element(by.id(CommonE2eIdConstants.SIGN_IN_BTN_ID)).tap() if (skipOnboarding === true) { @@ -160,7 +215,6 @@ export async function loginToDemoMode(skipOnboarding = true, pushNotifications?: * @param waitForElement - boolean to wait for an element * @param timeOut - time to wait for the element * */ - export async function checkIfElementIsPresent( matchString: string, findbyText = false, @@ -191,7 +245,7 @@ export async function checkIfElementIsPresent( } } -/* Scroll down inside container until specified text is found, then tap the text +/** Scroll down inside container until specified text is found, then tap the text * * @param text - string of the text to match * @param containerID - testID of the container @@ -204,7 +258,7 @@ export async function scrollToThenTap(text: string, containerID: string) { await element(by.text(text)).tap() } -/* Scroll down inside container until specified testID is found, then tap the testID +/** Scroll down inside container until specified testID is found, then tap the testID * * @param scrollToID - testID of the item to scroll to * @param containerID - testID of the container @@ -217,7 +271,7 @@ export async function scrollToIDThenTap(scrollToID: string, containerID: string) await element(by.id(scrollToID)).tap() } -/*This function will open, check for, and dismiss the leaving app popup from a specified launching point +/** This function will open, check for, and dismiss the leaving app popup from a specified launching point * * @param matchString - string of the text or id to match * @param findbyText - boolean to search by testID or Text @@ -405,6 +459,11 @@ export async function backButton(backButtonName: string) { } } +/** Enables the availibility banner. +* @param AFFeature: Name of the AF waygate. +* @param AFUseCase: Name of the AF type. +* @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not +* */ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { await device.launchApp({ newInstance: true, permissions: { notifications: 'YES' } }) await loginToDemoMode() @@ -413,19 +472,19 @@ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { await openDeveloperScreen() await waitFor(element(by.text(CommonE2eIdConstants.REMOTE_CONFIG_BUTTON_TEXT))) .toBeVisible() - .whileElement(by.id('developerScreenTestID')) + .whileElement(by.id(CommonE2eIdConstants.DEVELOPER_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(CommonE2eIdConstants.REMOTE_CONFIG_BUTTON_TEXT)).tap() if (AFUseCase === 'DenyAccess') { await waitFor(element(by.text(CommonE2eIdConstants.IN_APP_REVIEW_TOGGLE_TEXT))) .toBeVisible() - .whileElement(by.id('remoteConfigTestID')) + .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(600, 'down') await element(by.text(CommonE2eIdConstants.IN_APP_REVIEW_TOGGLE_TEXT)).tap() } await waitFor(element(by.text(AFFeature))) .toBeVisible() - .whileElement(by.id('remoteConfigTestID')) + .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(600, 'down') await element(by.text(AFFeature)).tap() @@ -458,21 +517,21 @@ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { } } } - await element(by.id('AFTypeTestID')).replaceText(AFUseCase) - await element(by.id('AFTypeTestID')).tapReturnKey() - await element(by.id('AFErrorMsgTitleTestID')).replaceText('AF Heading Test') - await element(by.id('AFErrorMsgTitleTestID')).tapReturnKey() - await element(by.id('AFErrorMsgBodyTestID')).replaceText('AF Body Test') - await element(by.id('AFErrorMsgBodyTestID')).tapReturnKey() + await element(by.id(CommonE2eIdConstants.AF_TYPE_INPUT_ID)).replaceText(AFUseCase) + await element(by.id(CommonE2eIdConstants.AF_TYPE_INPUT_ID)).tapReturnKey() + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_TITLE_INPUT_ID)).replaceText('AF Heading Test') + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_TITLE_INPUT_ID)).tapReturnKey() + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_BODY_INPUT_ID)).replaceText('AF Body Test') + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_BODY_INPUT_ID)).tapReturnKey() await setTimeout(3000) - await element(by.id('AFErrorPhoneNumberTestID')).replaceText('8006982411') - await element(by.id('AFErrorPhoneNumberTestID')).tapReturnKey() + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_PHONE_ID)).replaceText('8006982411') + await element(by.id(CommonE2eIdConstants.AF_ERROR_MSG_PHONE_ID)).tapReturnKey() - await element(by.text('Save')).tap() + await element(by.text(CommonE2eIdConstants.SAVE_TEXT)).tap() if (AFUseCase === 'DenyAccess') { await waitFor(element(by.text(CommonE2eIdConstants.APPLY_OVERRIDES_BUTTON_TEXT))) .toBeVisible() - .whileElement(by.id('remoteConfigTestID')) + .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(600, 'up') await element(by.text(CommonE2eIdConstants.APPLY_OVERRIDES_BUTTON_TEXT)).tap() if (AFFeature !== 'WG_Login' && AFFeature !== 'WG_VeteransCrisisLine') { @@ -483,9 +542,15 @@ export async function enableAF(AFFeature, AFUseCase, AFAppUpdate = false) { } } +/** Disables the availibility banner. +* @param featureNavigationArray: Array that tells the AF script how to navigate to the feature +* @param AFFeature: Name of the AF waygate. +* @param AFUseCaseName: Name of the AF type. +* @param AFAppUpdate: Boolean value that tells the script whether to enable the update now button or not +* */ export async function disableAF(featureNavigationArray, AFFeature, AFFeatureName, AFUseCaseName) { if (AFUseCaseName === 'AllowFunction') { - await element(by.id('Home')).tap() + await element(by.id(CommonE2eIdConstants.HOME_TAB_BUTTON_ID)).tap() } else { await device.launchApp({ newInstance: true, permissions: { notifications: 'YES' } }) await loginToDemoMode() @@ -495,7 +560,7 @@ export async function disableAF(featureNavigationArray, AFFeature, AFFeatureName await openDeveloperScreen() await waitFor(element(by.text(CommonE2eIdConstants.REMOTE_CONFIG_BUTTON_TEXT))) .toBeVisible() - .whileElement(by.id('developerScreenTestID')) + .whileElement(by.id(CommonE2eIdConstants.DEVELOPER_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(CommonE2eIdConstants.REMOTE_CONFIG_BUTTON_TEXT)).tap() await waitFor(element(by.text(AFFeature))) @@ -503,20 +568,22 @@ export async function disableAF(featureNavigationArray, AFFeature, AFFeatureName .whileElement(by.id(CommonE2eIdConstants.REMOTE_CONFIG_TEST_ID)) .scroll(600, 'down') await element(by.text(AFFeature)).tap() - await element(by.text('Enabled')).tap() - await element(by.text('Save')).tap() + await element(by.text(CommonE2eIdConstants.ENABLED_TEXT)).tap() + await element(by.text(CommonE2eIdConstants.SAVE_TEXT)).tap() await element(by.id(CommonE2eIdConstants.HOME_TAB_BUTTON_ID)).tap() if (featureNavigationArray !== undefined) { await navigateToFeature(featureNavigationArray) - await expect(element(by.text('AF Heading Test'))).not.toExist() - await expect(element(by.text('AF Body Test'))).not.toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_ERROR_MSG_TITLE_ENTERED_TEXT))).not.toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_BODY_ENTERED_TEXT))).not.toExist() } await device.uninstallApp() await device.installApp() } +/** Function that allows the AF script to navigate to a certain feature +* */ const navigateToFeature = async (featureNavigationArray) => { for (let j = 2; j < featureNavigationArray.length; j++) { if (featureNavigationArray[j] === 'Talk to the Veterans Crisis Line now') { @@ -537,12 +604,12 @@ const navigateToFeature = async (featureNavigationArray) => { featureNavigationArray[j] === 'Reply' || featureNavigationArray[j] === 'Only use messages for non-urgent needs' ) { - await element(by.id('viewMessageTestID')).scrollTo('bottom') + await element(by.id(CommonE2eIdConstants.VIEW_MESSAGE_ID)).scrollTo('bottom') await element(by.text(featureNavigationArray[j])).atIndex(0).tap() } else if (featureNavigationArray[j] === 'Email address') { await waitFor(element(by.text(featureNavigationArray[j]))) .toBeVisible() - .whileElement(by.id('ContactInfoTestID')) + .whileElement(by.id(CommonE2eIdConstants.CONTACT_INFO_SCREEN_ID)) .scroll(50, 'down') await element(by.text(featureNavigationArray[j])).tap() } else if (featureNavigationArray[j] === 'Received July 17, 2008') { @@ -561,21 +628,17 @@ const navigateToFeature = async (featureNavigationArray) => { .scroll(50, 'down') await element(by.text(featureNavigationArray[j])).tap() } else if (featureNavigationArray[j] === 'Request Refill') { - if (device.getPlatform() === 'ios') { - await element(by.text(featureNavigationArray[j])).tap() - } else { - await element(by.text('Request Refill ')).tap() - } + await element(by.text(CommonE2eIdConstants.PRESCRIPTION_REFILL_DIALOG_YES_TEXT)).tap() } else if (featureNavigationArray[j] === 'Contact us' || featureNavigationArray[j] === 'Proof of Veteran status') { await waitFor(element(by.text(featureNavigationArray[j]))) .toBeVisible() - .whileElement(by.id('homeScreenID')) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(featureNavigationArray[j])).tap() } else if (featureNavigationArray[0] === 'HomeScreen.e2e' && featureNavigationArray[j] !== 'Appointments') { await waitFor(element(by.text(featureNavigationArray[j]))) .toBeVisible() - .whileElement(by.id('homeScreenID')) + .whileElement(by.id(CommonE2eIdConstants.HOME_SCREEN_SCROLL_ID)) .scroll(200, 'down') await element(by.text(featureNavigationArray[j])).tap() } else { @@ -588,19 +651,24 @@ const navigateToFeature = async (featureNavigationArray) => { } } +/** Verifies that the availibility banner is the correct type and is populated with the correct information. +* @param featureNavigationArray: Array that tells the AF script how to navigate to the feature +* @param AFUseCaseName: Name of the AF type. +* @param AFUseCaseUpgrade: Boolean value that tells the script whether to enable the update now button or not +* */ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgrade = false) { let featureName if (AFUseCase !== 'AllowFunction') { featureName = featureNavigationArray[featureNavigationArray.length - 1] await navigateToFeature(featureNavigationArray) } - await expect(element(by.text('AF Heading Test'))).toExist() - await expect(element(by.text('AF Body Test'))).toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_ERROR_MSG_TITLE_ENTERED_TEXT))).toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_BODY_ENTERED_TEXT))).toExist() if (AFUseCase === 'DenyAccess') { try { - await element(by.text('OK')).tap() + await element(by.text(CommonE2eIdConstants.OK_UNIVERSAL_TEXT)).tap() } catch (ex) { - await element(by.text('OK')).atIndex(0).tap() + await element(by.text(CommonE2eIdConstants.OK_UNIVERSAL_TEXT)).atIndex(0).tap() } } else if (AFUseCase === 'DenyContent' || AFUseCase === 'AllowFunction') { if (device.getPlatform() === 'android') { @@ -608,7 +676,11 @@ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgra try { await element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID)).atIndex(0).tap() } catch (ex) { - await element(by.id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID).withAncestor(by.id('AFUseCase2TestID'))).tap() + await element( + by + .id(CommonE2eIdConstants.CALL_VA_PHONE_NUMBER_ID) + .withAncestor(by.id(CommonE2eIdConstants.AF_USE_CASE_TWO_ID)), + ).tap() } await setTimeout(5000) await device.takeScreenshot(featureName + 'AFUseCase2PhoneNumber') @@ -617,7 +689,9 @@ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgra await element(by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID)).atIndex(0).tap() } catch (ex) { await element( - by.id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID).withAncestor(by.id('AFUseCase2TestID')), + by + .id(CommonE2eIdConstants.CALL_VA_TTY_PHONE_NUMBER_ID) + .withAncestor(by.id(CommonE2eIdConstants.AF_USE_CASE_TWO_ID)), ).tap() } await setTimeout(5000) @@ -628,9 +702,9 @@ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgra if (AFUseCaseUpgrade) { try { - await expect(element(by.text('Update now'))).toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_UPDATE_NOW_BUTTON_TEXT))).toExist() } catch (ex) { - await expect(element(by.text('Update now')).atIndex(1)).toExist() + await expect(element(by.text(CommonE2eIdConstants.AF_UPDATE_NOW_BUTTON_TEXT)).atIndex(1)).toExist() } } } @@ -642,10 +716,9 @@ export async function verifyAF(featureNavigationArray, AFUseCase, AFUseCaseUpgra } } -/* Toggle the specified remote config feature flag - * +/** Toggle the specified remote config feature flag * @param flagName - name of flag to toggle - */ +* */ export async function toggleRemoteConfigFlag(flagName: string) { await loginToDemoMode() await openProfile() diff --git a/VAMobile/ios/Gemfile.lock b/VAMobile/ios/Gemfile.lock index 5c6b9eda936..ed7740d18e4 100644 --- a/VAMobile/ios/Gemfile.lock +++ b/VAMobile/ios/Gemfile.lock @@ -5,7 +5,7 @@ GEM base64 nkf rexml - activesupport (7.2.2) + activesupport (7.2.2.1) base64 benchmark (>= 0.3) bigdecimal @@ -25,8 +25,8 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.1010.0) - aws-sdk-core (3.213.0) + aws-partitions (1.1020.0) + aws-sdk-core (3.214.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -34,7 +34,7 @@ GEM aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.172.0) + aws-sdk-s3 (1.176.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -128,7 +128,7 @@ GEM faraday_middleware (1.2.1) faraday (~> 1.0) fastimage (2.3.1) - fastlane (2.225.0) + fastlane (2.226.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -168,7 +168,7 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) + xcpretty (~> 0.4.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-slack_bot (1.4.0) fastlane-sirp (1.0.0) @@ -215,19 +215,19 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.7) + http-cookie (1.0.8) domain_name (~> 0.5) httpclient (2.8.3) i18n (1.14.6) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.8.2) + json (2.9.0) jwt (2.9.3) base64 - logger (1.6.1) + logger (1.6.2) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.1) + minitest (5.25.4) molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.4.1) @@ -247,11 +247,11 @@ GEM uber (< 0.2.0) retriable (3.1.2) rexml (3.3.9) - rouge (2.0.7) + rouge (3.28.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) - securerandom (0.3.2) + securerandom (0.4.0) security (0.1.5) signet (0.19.0) addressable (~> 2.8) @@ -287,8 +287,8 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) + xcpretty (0.4.0) + rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) diff --git a/VAMobile/package.json b/VAMobile/package.json index 77bcecb5bc9..83daafe4a2d 100644 --- a/VAMobile/package.json +++ b/VAMobile/package.json @@ -37,9 +37,9 @@ "pods": "cd ios && pod install && cd .." }, "dependencies": { - "@department-of-veterans-affairs/mobile-assets": "0.13.0", - "@department-of-veterans-affairs/mobile-component-library": "0.21.0", - "@department-of-veterans-affairs/mobile-tokens": "0.17.1", + "@department-of-veterans-affairs/mobile-assets": "0.14.0", + "@department-of-veterans-affairs/mobile-component-library": "0.27.1", + "@department-of-veterans-affairs/mobile-tokens": "0.20.0", "@expo/react-native-action-sheet": "^4.1.0", "@react-native-async-storage/async-storage": "^1.24.0", "@react-native-cookies/cookies": "^6.2.1", @@ -52,9 +52,9 @@ "@react-navigation/bottom-tabs": "^6.6.1", "@react-navigation/native": "^6.1.18", "@react-navigation/stack": "^6.4.1", - "@reduxjs/toolkit": "^2.3.0", + "@reduxjs/toolkit": "^2.4.0", "@tanstack/react-query": "^5.59.15", - "eslint-plugin-tsdoc": "^0.3.0", + "eslint-plugin-tsdoc": "^0.4.0", "i18next": "^23.7.18", "jsc-android": "^250231.0.0", "lottie-react-native": "^5.1.6", @@ -83,7 +83,7 @@ "react-native-svg-transformer": "^1.5.0", "react-native-toast-notifications": "^3.4.0", "react-native-webp-format": "^1.2.0", - "react-native-webview": "^13.12.3", + "react-native-webview": "^13.12.4", "react-redux": "^9.1.2", "styled-components": "^5.3.10", "underscore": "^1.13.7" @@ -101,12 +101,12 @@ "@react-native/metro-config": "^0.75.3", "@react-native/typescript-config": "0.76.2", "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react-native": "^12.8.1", + "@testing-library/react-native": "^12.9.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@tsconfig/react-native": "^3.0.5", "@types/detox": "^18.1.0", "@types/jest-when": "^3.5.5", - "@types/lodash": "^4.17.7", + "@types/lodash": "^4.17.13", "@types/luxon": "^3.4.2", "@types/node": "^20.14.10", "@types/react-native": "0.73.0", @@ -119,7 +119,7 @@ "babel-jest": "^29.7.0", "babel-plugin-module-resolver": "^5.0.2", "concurrently": "^8.2.2", - "detox": "^20.25.5", + "detox": "^20.28.0", "eslint": "^8.57.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^27.9.0", @@ -132,7 +132,7 @@ "jest-environment-jsdom": "29.7.0", "jest-image-snapshot": "^6.4.0", "jest-junit": "^16.0.0", - "jest-when": "^3.6.0", + "jest-when": "^3.7.0", "lint-staged": "^15.2.9", "metro-react-native-babel-preset": "^0.77.0", "prettier": "^3.3.3", diff --git a/VAMobile/src/App.tsx b/VAMobile/src/App.tsx index 5a3dff97c2a..f279296cee3 100644 --- a/VAMobile/src/App.tsx +++ b/VAMobile/src/App.tsx @@ -19,6 +19,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native' import { createStackNavigator } from '@react-navigation/stack' +import { useIsScreenReaderEnabled } from '@department-of-veterans-affairs/mobile-component-library' import { ActionSheetProvider, connectActionSheet } from '@expo/react-native-action-sheet' import { QueryClientProvider } from '@tanstack/react-query' import { ThemeProvider } from 'styled-components' diff --git a/VAMobile/src/api/types/PersonalInformationData.ts b/VAMobile/src/api/types/PersonalInformationData.ts index 7b849b39263..45f276a2563 100644 --- a/VAMobile/src/api/types/PersonalInformationData.ts +++ b/VAMobile/src/api/types/PersonalInformationData.ts @@ -10,6 +10,7 @@ export type PersonalInformationPayload = { signinService: string birthDate: string | null hasFacilityTransitioningToCerner: boolean + edipi: string | null } } } diff --git a/VAMobile/src/components/AttachmentLink.tsx b/VAMobile/src/components/AttachmentLink.tsx index 3f0d2e403e1..03e07964164 100644 --- a/VAMobile/src/components/AttachmentLink.tsx +++ b/VAMobile/src/components/AttachmentLink.tsx @@ -1,6 +1,8 @@ import React, { FC } from 'react' import { AccessibilityProps, Pressable, PressableProps } from 'react-native' +import { Icon } from '@department-of-veterans-affairs/mobile-component-library' + import { a11yHintProp } from 'utils/accessibility' import { useTheme } from 'utils/hooks' import { featureEnabled } from 'utils/remoteConfig' @@ -8,7 +10,6 @@ import { featureEnabled } from 'utils/remoteConfig' import Box from './Box' import LinkWithAnalytics from './LinkWithAnalytics' import TextView from './TextView' -import VAIcon from './VAIcon' export type AttachmentLinkProps = { /** Name of link/attachment */ @@ -57,7 +58,7 @@ const AttachmentLink: FC = ({ - + {text} diff --git a/VAMobile/src/components/FormWrapper/FormFields/FormAttachments.tsx b/VAMobile/src/components/FormWrapper/FormFields/FormAttachments.tsx index 8c5b11652d4..97c14f3a623 100644 --- a/VAMobile/src/components/FormWrapper/FormFields/FormAttachments.tsx +++ b/VAMobile/src/components/FormWrapper/FormFields/FormAttachments.tsx @@ -2,10 +2,10 @@ import React, { FC, ReactNode } from 'react' import { useTranslation } from 'react-i18next' import { ImagePickerResponse } from 'react-native-image-picker/src/types' -import { Button, ButtonVariants } from '@department-of-veterans-affairs/mobile-component-library' +import { Button, ButtonVariants, Icon } from '@department-of-veterans-affairs/mobile-component-library' import _ from 'underscore' -import { Box, TextView, VAIcon } from 'components/index' +import { Box, TextView } from 'components/index' import { NAMESPACE } from 'constants/namespaces' import { DocumentPickerResponse } from 'screens/BenefitsScreen/BenefitsStackScreens' import { getFileDisplay } from 'utils/common' @@ -45,21 +45,19 @@ const FormAttachments: FC = ({ return ( - - - - {text} - + flexDirection={'row'} + mr={theme.dimensions.gutter} + mt={index !== 0 ? theme.dimensions.condensedMarginBetween : 0} + mb={theme.dimensions.condensedMarginBetween}> + + + + {text} +