diff --git a/.eslintrc.json b/.eslintrc.json index 15b1ed91a..2eb546d82 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next" + "extends": ["next", "plugin:prettier/recommended"] } diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e8e115e95..a5cd186ed 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,13 @@ name: 'CodeQL' on: push: - branches: [main] + branches: + - main + - develop pull_request: - # The branches below must be a subset of the branches above - branches: [main] + branches: + - main + - develop schedule: - cron: '35 3 * * 6' @@ -38,11 +41,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # โ„น๏ธ Command-line programs to run using the OS shell. # ๐Ÿ“š https://git.io/JvXDl @@ -67,4 +70,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/run-scrapers.yml b/.github/workflows/run-scrapers.yml index 297737e60..39cc44f34 100644 --- a/.github/workflows/run-scrapers.yml +++ b/.github/workflows/run-scrapers.yml @@ -1,46 +1,63 @@ -name: Run scrapers +name: Legal values auto-update on: - workflow_dispatch: + workflow_dispatch: # so we can run manually schedule: - cron: '0 0 * * *' jobs: - build: + legal-values-auto-update: runs-on: ubuntu-latest steps: - - id: import_gpg - uses: crazy-max/ghaction-import-gpg@v5 - with: - gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_KEY_PASSPHRASE }} - git_user_signingkey: true - git_commit_gpgsign: true - git_committer_name: DTS-STN - git_committer_email: dts-stn+actions@github.com - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - name: Checkout + uses: actions/checkout@v3 + + ## Signing with GPG won't work unless we create a "DTS Bot" GitHub account. + #- name: Setup GPG key + # id: import_gpg + # uses: crazy-max/ghaction-import-gpg@v5 + # with: + # gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + # passphrase: ${{ secrets.GPG_KEY_PASSPHRASE }} + # git_user_signingkey: true + # git_commit_gpgsign: true + # git_committer_name: GitHub Actions + # git_committer_email: actions@github.com + + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: '16' - cache: 'yarn' - - run: corepack enable - - run: yarn install - # - run: git checkout -b legal-values-autoupdate - - run: yarn run run-scraper - # - run: echo test > utils/api/scrapers/output/test.json - # - uses: EndBug/add-and-commit@v9 - # with: - # add: 'utils/api/scrapers/output/*.json' - # new_branch: legal-values-autoupdate - # committer_name: DTS-STN - # committer_email: dts-stn+actions@github.com - # - run: | - # git add 'utils/api/scrapers/output/*.json' - # git commit -S -m "update legal values" - # - run: git push -v --set-upstream origin legal-values-autoupdate - - uses: peter-evans/create-pull-request@v4 + cache: 'yarn' # cache seems to not work until yarn is installed, so this might be futile + + - name: Install Yarn + run: corepack enable + + - name: Install dependencies + run: yarn install + + - name: Run scraper + run: yarn run run-scraper + + - name: Create pull request + uses: peter-evans/create-pull-request@v4 with: commit-message: auto-update legal values title: Auto-update legal values - body: This is created by a bot, please review. - branch: legal-values-autoupdate + body: | + This is created by a bot, please review and make any appropriate changes. + + You will have to sign the bot's commit before merging, because it doesn't have permission to do so itself. + + To do this, run the following commands: + ``` + git fetch + git switch legal-values-auto-update + git pull + git rebase --exec 'git commit -S --amend --no-edit' develop + git push --force + ``` + branch: legal-values-auto-update + base: develop add-paths: | utils/api/scrapers/output/*.json + committer: GitHub Actions + author: GitHub Actions diff --git a/.github/workflows/test-and-lint.yml b/.github/workflows/test-and-lint.yml index 88768d3fe..21220bbc3 100644 --- a/.github/workflows/test-and-lint.yml +++ b/.github/workflows/test-and-lint.yml @@ -4,9 +4,6 @@ name: Lint and Test on: - push: - branches: - - main pull_request: branches: - main @@ -16,25 +13,25 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Checkout ๐Ÿ”” - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v3 - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x cache: yarn - name: Install - run: yarn install --frozen-lockfile + run: yarn install --immutable - name: Build run: yarn run build - - name: Linting + - name: Lint run: yarn run lint - - name: Run Unit Tests and Coverage ๐Ÿงช + - name: Run Unit Tests and Coverage run: yarn run test:ci # - name: Extract branch name diff --git a/.pnp.cjs b/.pnp.cjs index 405a69c79..cc9a5cf95 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -33,7 +33,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { [null, {\ "packageLocation": "./",\ "packageDependencies": [\ - ["@dts-stn/decd-design-system", "https://github.com/DTS-STN/DECD-Design-System.git#commit=0e2d2e4bbd65eaebb6015c80de4094a928d51e32"],\ + ["@dts-stn/decd-design-system", "npm:1.40.0"],\ ["@tailwindcss/forms", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:0.5.0"],\ ["@testing-library/jest-dom", "npm:5.16.4"],\ ["@testing-library/react", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:12.1.4"],\ @@ -46,6 +46,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["csv-writer", "npm:1.6.0"],\ ["eslint", "npm:8.17.0"],\ ["eslint-config-next", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:12.1.4"],\ + ["eslint-config-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:8.5.0"],\ + ["eslint-plugin-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:4.0.0"],\ ["husky", "npm:7.0.4"],\ ["jest", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:27.5.1"],\ ["joi", "npm:17.6.0"],\ @@ -863,14 +865,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["@dts-stn/decd-design-system", [\ - ["https://github.com/DTS-STN/DECD-Design-System.git#commit=0e2d2e4bbd65eaebb6015c80de4094a928d51e32", {\ - "packageLocation": "./.yarn/cache/@dts-stn-decd-design-system-https-cb4ea9b315-bd4a148c2d.zip/node_modules/@dts-stn/decd-design-system/",\ + ["npm:1.40.0", {\ + "packageLocation": "./.yarn/cache/@dts-stn-decd-design-system-npm-1.40.0-7abdd78163-b1a9345604.zip/node_modules/@dts-stn/decd-design-system/",\ "packageDependencies": [\ - ["@dts-stn/decd-design-system", "https://github.com/DTS-STN/DECD-Design-System.git#commit=0e2d2e4bbd65eaebb6015c80de4094a928d51e32"],\ + ["@dts-stn/decd-design-system", "npm:1.40.0"],\ ["prop-types", "npm:15.8.1"],\ ["react", "npm:17.0.2"],\ ["react-app-polyfill", "npm:3.0.0"],\ - ["react-dom", "virtual:cb4ea9b3154ff76ccc6d003f5f989aa3d8b76d160a81578413341f53bda0e9447e4ad31180defba22b6551c323f01f0ef43ee93c451de5a4ff0767340df8f2bc#npm:17.0.2"],\ + ["react-dom", "virtual:7abdd781636ab7de03898b26cfa35a52df78632e884cfffeffcd36480b4882d90a9afc55cd68ea86ed10d68e5d602762a3cf2153ea08e348156b3436d9f3b57a#npm:17.0.2"],\ ["user", "npm:0.0.0"]\ ],\ "linkType": "HARD"\ @@ -3511,7 +3513,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./",\ "packageDependencies": [\ ["eligibility-estimator-client", "workspace:."],\ - ["@dts-stn/decd-design-system", "https://github.com/DTS-STN/DECD-Design-System.git#commit=0e2d2e4bbd65eaebb6015c80de4094a928d51e32"],\ + ["@dts-stn/decd-design-system", "npm:1.40.0"],\ ["@tailwindcss/forms", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:0.5.0"],\ ["@testing-library/jest-dom", "npm:5.16.4"],\ ["@testing-library/react", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:12.1.4"],\ @@ -3524,6 +3526,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["csv-writer", "npm:1.6.0"],\ ["eslint", "npm:8.17.0"],\ ["eslint-config-next", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:12.1.4"],\ + ["eslint-config-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:8.5.0"],\ + ["eslint-plugin-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:4.0.0"],\ ["husky", "npm:7.0.4"],\ ["jest", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:27.5.1"],\ ["joi", "npm:17.6.0"],\ @@ -3785,6 +3789,28 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["eslint-config-prettier", [\ + ["npm:8.5.0", {\ + "packageLocation": "./.yarn/cache/eslint-config-prettier-npm-8.5.0-a1dd58b6d8-0d0f5c32e7.zip/node_modules/eslint-config-prettier/",\ + "packageDependencies": [\ + ["eslint-config-prettier", "npm:8.5.0"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:8.5.0", {\ + "packageLocation": "./.yarn/__virtual__/eslint-config-prettier-virtual-4b4b2afa36/0/cache/eslint-config-prettier-npm-8.5.0-a1dd58b6d8-0d0f5c32e7.zip/node_modules/eslint-config-prettier/",\ + "packageDependencies": [\ + ["eslint-config-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:8.5.0"],\ + ["@types/eslint", null],\ + ["eslint", "npm:8.17.0"]\ + ],\ + "packagePeers": [\ + "@types/eslint",\ + "eslint"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["eslint-import-resolver-node", [\ ["npm:0.3.4", {\ "packageLocation": "./.yarn/cache/eslint-import-resolver-node-npm-0.3.4-fa0173d267-a0db55ec26.zip/node_modules/eslint-import-resolver-node/",\ @@ -3945,6 +3971,37 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["eslint-plugin-prettier", [\ + ["npm:4.0.0", {\ + "packageLocation": "./.yarn/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\ + "packageDependencies": [\ + ["eslint-plugin-prettier", "npm:4.0.0"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:4.0.0", {\ + "packageLocation": "./.yarn/__virtual__/eslint-plugin-prettier-virtual-6661a582a0/0/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\ + "packageDependencies": [\ + ["eslint-plugin-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:4.0.0"],\ + ["@types/eslint", null],\ + ["@types/eslint-config-prettier", null],\ + ["@types/prettier", null],\ + ["eslint", "npm:8.17.0"],\ + ["eslint-config-prettier", "virtual:681281c59dad27b631c32269a449c43baa0ba3057a9783ffbbd0369615843c80b4fc8dc74800023e967d416c55215c22d29cf1363936f070b3a95c86dd1f9515#npm:8.5.0"],\ + ["prettier", "npm:2.6.2"],\ + ["prettier-linter-helpers", "npm:1.0.0"]\ + ],\ + "packagePeers": [\ + "@types/eslint-config-prettier",\ + "@types/eslint",\ + "@types/prettier",\ + "eslint-config-prettier",\ + "eslint",\ + "prettier"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["eslint-plugin-react", [\ ["npm:7.29.1", {\ "packageLocation": "./.yarn/cache/eslint-plugin-react-npm-7.29.1-1faecd24d9-d1d0d267d2.zip/node_modules/eslint-plugin-react/",\ @@ -4161,6 +4218,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["fast-diff", [\ + ["npm:1.2.0", {\ + "packageLocation": "./.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-1b5306eaa9.zip/node_modules/fast-diff/",\ + "packageDependencies": [\ + ["fast-diff", "npm:1.2.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["fast-glob", [\ ["npm:3.2.11", {\ "packageLocation": "./.yarn/cache/fast-glob-npm-3.2.11-bc01135fef-f473105324.zip/node_modules/fast-glob/",\ @@ -7212,6 +7278,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["prettier-linter-helpers", [\ + ["npm:1.0.0", {\ + "packageLocation": "./.yarn/cache/prettier-linter-helpers-npm-1.0.0-6925131a7e-00ce8011cf.zip/node_modules/prettier-linter-helpers/",\ + "packageDependencies": [\ + ["prettier-linter-helpers", "npm:1.0.0"],\ + ["fast-diff", "npm:1.2.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["pretty-format", [\ ["npm:27.5.1", {\ "packageLocation": "./.yarn/cache/pretty-format-npm-27.5.1-cd7d49696f-cf610cffcb.zip/node_modules/pretty-format/",\ @@ -7447,10 +7523,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "HARD"\ }],\ - ["virtual:cb4ea9b3154ff76ccc6d003f5f989aa3d8b76d160a81578413341f53bda0e9447e4ad31180defba22b6551c323f01f0ef43ee93c451de5a4ff0767340df8f2bc#npm:17.0.2", {\ - "packageLocation": "./.yarn/__virtual__/react-dom-virtual-64389c4fde/0/cache/react-dom-npm-17.0.2-f551215af1-1c1eaa3bca.zip/node_modules/react-dom/",\ + ["virtual:7abdd781636ab7de03898b26cfa35a52df78632e884cfffeffcd36480b4882d90a9afc55cd68ea86ed10d68e5d602762a3cf2153ea08e348156b3436d9f3b57a#npm:17.0.2", {\ + "packageLocation": "./.yarn/__virtual__/react-dom-virtual-7f62764dcd/0/cache/react-dom-npm-17.0.2-f551215af1-1c1eaa3bca.zip/node_modules/react-dom/",\ "packageDependencies": [\ - ["react-dom", "virtual:cb4ea9b3154ff76ccc6d003f5f989aa3d8b76d160a81578413341f53bda0e9447e4ad31180defba22b6551c323f01f0ef43ee93c451de5a4ff0767340df8f2bc#npm:17.0.2"],\ + ["react-dom", "virtual:7abdd781636ab7de03898b26cfa35a52df78632e884cfffeffcd36480b4882d90a9afc55cd68ea86ed10d68e5d602762a3cf2153ea08e348156b3436d9f3b57a#npm:17.0.2"],\ ["@types/react", null],\ ["loose-envify", "npm:1.4.0"],\ ["object-assign", "npm:4.1.1"],\ diff --git a/.prettierignore b/.prettierignore index 806e9f0f7..b8d7dc826 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,4 +4,7 @@ node_modules/ coverage/ helmfile/ helm/ +out/ yarn.lock +.pnp.cjs +.pnp.loader.mjs diff --git a/.vscode/extensions.json b/.vscode/extensions.json index bd47279fb..0f9c2d80b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,8 @@ { - "recommendations": ["orta.vscode-jest"] + "recommendations": [ + "orta.vscode-jest", + "arcanis.vscode-zipfs", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index c45adaed3..0752bcd86 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,11 @@ { - "jest.jestCommandLine": "yarn test:coverage" + "jest.jestCommandLine": "yarn test:coverage", + "search.exclude": { + "**/.yarn": true, + "**/.pnp.*": true + }, + "eslint.nodePath": ".yarn/sdks", + "prettier.prettierPath": ".yarn/sdks/prettier/index.js", + "typescript.tsdk": ".yarn/sdks/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true } diff --git a/.yarn/cache/@dts-stn-decd-design-system-https-cb4ea9b315-bd4a148c2d.zip b/.yarn/cache/@dts-stn-decd-design-system-https-cb4ea9b315-bd4a148c2d.zip deleted file mode 100644 index 1ebe77764..000000000 Binary files a/.yarn/cache/@dts-stn-decd-design-system-https-cb4ea9b315-bd4a148c2d.zip and /dev/null differ diff --git a/.yarn/cache/@dts-stn-decd-design-system-npm-1.40.0-7abdd78163-b1a9345604.zip b/.yarn/cache/@dts-stn-decd-design-system-npm-1.40.0-7abdd78163-b1a9345604.zip new file mode 100644 index 000000000..bfc408853 Binary files /dev/null and b/.yarn/cache/@dts-stn-decd-design-system-npm-1.40.0-7abdd78163-b1a9345604.zip differ diff --git a/.yarn/cache/@next-swc-darwin-arm64-npm-12.1.4-8bc9a59090-8.zip b/.yarn/cache/@next-swc-darwin-arm64-npm-12.1.4-8bc9a59090-8.zip new file mode 100644 index 000000000..87eb23228 Binary files /dev/null and b/.yarn/cache/@next-swc-darwin-arm64-npm-12.1.4-8bc9a59090-8.zip differ diff --git a/.yarn/cache/eslint-config-prettier-npm-8.5.0-a1dd58b6d8-0d0f5c32e7.zip b/.yarn/cache/eslint-config-prettier-npm-8.5.0-a1dd58b6d8-0d0f5c32e7.zip new file mode 100644 index 000000000..3e369149f Binary files /dev/null and b/.yarn/cache/eslint-config-prettier-npm-8.5.0-a1dd58b6d8-0d0f5c32e7.zip differ diff --git a/.yarn/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip b/.yarn/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip new file mode 100644 index 000000000..6babba4e3 Binary files /dev/null and b/.yarn/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip differ diff --git a/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-1b5306eaa9.zip b/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-1b5306eaa9.zip new file mode 100644 index 000000000..3f06ff5bf Binary files /dev/null and b/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-1b5306eaa9.zip differ diff --git a/.yarn/cache/fsevents-patch-3340e2eb10-8.zip b/.yarn/cache/fsevents-patch-3340e2eb10-8.zip new file mode 100644 index 000000000..c4511f19b Binary files /dev/null and b/.yarn/cache/fsevents-patch-3340e2eb10-8.zip differ diff --git a/.yarn/cache/prettier-linter-helpers-npm-1.0.0-6925131a7e-00ce8011cf.zip b/.yarn/cache/prettier-linter-helpers-npm-1.0.0-6925131a7e-00ce8011cf.zip new file mode 100644 index 000000000..ec7b0a0b8 Binary files /dev/null and b/.yarn/cache/prettier-linter-helpers-npm-1.0.0-6925131a7e-00ce8011cf.zip differ diff --git a/.yarn/sdks/eslint/bin/eslint.js b/.yarn/sdks/eslint/bin/eslint.js new file mode 100644 index 000000000..4d327a49a --- /dev/null +++ b/.yarn/sdks/eslint/bin/eslint.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require eslint/bin/eslint.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real eslint/bin/eslint.js your application uses +module.exports = absRequire(`eslint/bin/eslint.js`); diff --git a/.yarn/sdks/eslint/lib/api.js b/.yarn/sdks/eslint/lib/api.js new file mode 100644 index 000000000..fc728d952 --- /dev/null +++ b/.yarn/sdks/eslint/lib/api.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require eslint + require(absPnpApiPath).setup(); + } +} + +// Defer to the real eslint your application uses +module.exports = absRequire(`eslint`); diff --git a/.yarn/sdks/eslint/package.json b/.yarn/sdks/eslint/package.json new file mode 100644 index 000000000..1e1bcd8a4 --- /dev/null +++ b/.yarn/sdks/eslint/package.json @@ -0,0 +1,6 @@ +{ + "name": "eslint", + "version": "8.17.0-sdk", + "main": "./lib/api.js", + "type": "commonjs" +} diff --git a/.yarn/sdks/integrations.yml b/.yarn/sdks/integrations.yml new file mode 100644 index 000000000..aa9d0d0ad --- /dev/null +++ b/.yarn/sdks/integrations.yml @@ -0,0 +1,5 @@ +# This file is automatically generated by @yarnpkg/sdks. +# Manual changes might be lost! + +integrations: + - vscode diff --git a/.yarn/sdks/prettier/index.js b/.yarn/sdks/prettier/index.js new file mode 100644 index 000000000..f6882d809 --- /dev/null +++ b/.yarn/sdks/prettier/index.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require prettier/index.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real prettier/index.js your application uses +module.exports = absRequire(`prettier/index.js`); diff --git a/.yarn/sdks/prettier/package.json b/.yarn/sdks/prettier/package.json new file mode 100644 index 000000000..bce279fdd --- /dev/null +++ b/.yarn/sdks/prettier/package.json @@ -0,0 +1,6 @@ +{ + "name": "prettier", + "version": "2.6.2-sdk", + "main": "./index.js", + "type": "commonjs" +} diff --git a/.yarn/sdks/typescript/bin/tsc b/.yarn/sdks/typescript/bin/tsc new file mode 100644 index 000000000..5608e5743 --- /dev/null +++ b/.yarn/sdks/typescript/bin/tsc @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/bin/tsc + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/bin/tsc your application uses +module.exports = absRequire(`typescript/bin/tsc`); diff --git a/.yarn/sdks/typescript/bin/tsserver b/.yarn/sdks/typescript/bin/tsserver new file mode 100644 index 000000000..cd7d557d5 --- /dev/null +++ b/.yarn/sdks/typescript/bin/tsserver @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/bin/tsserver + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/bin/tsserver your application uses +module.exports = absRequire(`typescript/bin/tsserver`); diff --git a/.yarn/sdks/typescript/lib/tsc.js b/.yarn/sdks/typescript/lib/tsc.js new file mode 100644 index 000000000..16042d01d --- /dev/null +++ b/.yarn/sdks/typescript/lib/tsc.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsc.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsc.js your application uses +module.exports = absRequire(`typescript/lib/tsc.js`); diff --git a/.yarn/sdks/typescript/lib/tsserver.js b/.yarn/sdks/typescript/lib/tsserver.js new file mode 100644 index 000000000..9f9f4d6f4 --- /dev/null +++ b/.yarn/sdks/typescript/lib/tsserver.js @@ -0,0 +1,223 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +const moduleWrapper = tsserver => { + if (!process.versions.pnp) { + return tsserver; + } + + const {isAbsolute} = require(`path`); + const pnpApi = require(`pnpapi`); + + const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); + const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); + + const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { + return `${locator.name}@${locator.reference}`; + })); + + // VSCode sends the zip paths to TS using the "zip://" prefix, that TS + // doesn't understand. This layer makes sure to remove the protocol + // before forwarding it to TS, and to add it back on all returned paths. + + function toEditorPath(str) { + // We add the `zip:` prefix to both `.zip/` paths and virtual paths + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { + // We also take the opportunity to turn virtual paths into physical ones; + // this makes it much easier to work with workspaces that list peer + // dependencies, since otherwise Ctrl+Click would bring us to the virtual + // file instances instead of the real ones. + // + // We only do this to modules owned by the the dependency tree roots. + // This avoids breaking the resolution when jumping inside a vendor + // with peer dep (otherwise jumping into react-dom would show resolution + // errors on react). + // + const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; + if (resolved) { + const locator = pnpApi.findPackageLocator(resolved); + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { + str = resolved; + } + } + + str = normalize(str); + + if (str.match(/\.zip\//)) { + switch (hostInfo) { + // Absolute VSCode `Uri.fsPath`s need to start with a slash. + // VSCode only adds it automatically for supported schemes, + // so we have to do it manually for the `zip` scheme. + // The path needs to start with a caret otherwise VSCode doesn't handle the protocol + // + // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 + // + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { + str = `^zip:${str}`; + } break; + + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + + // To make "go to definition" work, + // We have to resolve the actual file system path from virtual path + // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) + case `coc-nvim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = resolve(`zipfile:${str}`); + } break; + + // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) + // We have to resolve the actual file system path from virtual path, + // everything else is up to neovim + case `neovim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = `zipfile://${str}`; + } break; + + default: { + str = `zip:${str}`; + } break; + } + } + } + + return str; + } + + function fromEditorPath(str) { + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } + } + + // Force enable 'allowLocalPluginLoads' + // TypeScript tries to resolve plugins using a path relative to itself + // which doesn't work when using the global cache + // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 + // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but + // TypeScript already does local loads and if this code is running the user trusts the workspace + // https://github.com/microsoft/vscode/issues/45856 + const ConfiguredProject = tsserver.server.ConfiguredProject; + const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; + ConfiguredProject.prototype.enablePluginsWithOptions = function() { + this.projectService.allowLocalPluginLoads = true; + return originalEnablePluginsWithOptions.apply(this, arguments); + }; + + // And here is the point where we hijack the VSCode <-> TS communications + // by adding ourselves in the middle. We locate everything that looks + // like an absolute path of ours and normalize it. + + const Session = tsserver.server.Session; + const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; + let hostInfo = `unknown`; + + Object.assign(Session.prototype, { + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; + + if ( + parsedMessage != null && + typeof parsedMessage === `object` && + parsedMessage.arguments && + typeof parsedMessage.arguments.hostInfo === `string` + ) { + hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } + } + + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); + }, + + send(/** @type {any} */ msg) { + return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { + return typeof value === `string` ? toEditorPath(value) : value; + }))); + } + }); + + return tsserver; +}; + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserver.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsserver.js your application uses +module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); diff --git a/.yarn/sdks/typescript/lib/tsserverlibrary.js b/.yarn/sdks/typescript/lib/tsserverlibrary.js new file mode 100644 index 000000000..878b11946 --- /dev/null +++ b/.yarn/sdks/typescript/lib/tsserverlibrary.js @@ -0,0 +1,223 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +const moduleWrapper = tsserver => { + if (!process.versions.pnp) { + return tsserver; + } + + const {isAbsolute} = require(`path`); + const pnpApi = require(`pnpapi`); + + const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); + const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); + + const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { + return `${locator.name}@${locator.reference}`; + })); + + // VSCode sends the zip paths to TS using the "zip://" prefix, that TS + // doesn't understand. This layer makes sure to remove the protocol + // before forwarding it to TS, and to add it back on all returned paths. + + function toEditorPath(str) { + // We add the `zip:` prefix to both `.zip/` paths and virtual paths + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { + // We also take the opportunity to turn virtual paths into physical ones; + // this makes it much easier to work with workspaces that list peer + // dependencies, since otherwise Ctrl+Click would bring us to the virtual + // file instances instead of the real ones. + // + // We only do this to modules owned by the the dependency tree roots. + // This avoids breaking the resolution when jumping inside a vendor + // with peer dep (otherwise jumping into react-dom would show resolution + // errors on react). + // + const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; + if (resolved) { + const locator = pnpApi.findPackageLocator(resolved); + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { + str = resolved; + } + } + + str = normalize(str); + + if (str.match(/\.zip\//)) { + switch (hostInfo) { + // Absolute VSCode `Uri.fsPath`s need to start with a slash. + // VSCode only adds it automatically for supported schemes, + // so we have to do it manually for the `zip` scheme. + // The path needs to start with a caret otherwise VSCode doesn't handle the protocol + // + // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 + // + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { + str = `^zip:${str}`; + } break; + + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + + // To make "go to definition" work, + // We have to resolve the actual file system path from virtual path + // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) + case `coc-nvim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = resolve(`zipfile:${str}`); + } break; + + // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) + // We have to resolve the actual file system path from virtual path, + // everything else is up to neovim + case `neovim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = `zipfile://${str}`; + } break; + + default: { + str = `zip:${str}`; + } break; + } + } + } + + return str; + } + + function fromEditorPath(str) { + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } + } + + // Force enable 'allowLocalPluginLoads' + // TypeScript tries to resolve plugins using a path relative to itself + // which doesn't work when using the global cache + // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 + // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but + // TypeScript already does local loads and if this code is running the user trusts the workspace + // https://github.com/microsoft/vscode/issues/45856 + const ConfiguredProject = tsserver.server.ConfiguredProject; + const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; + ConfiguredProject.prototype.enablePluginsWithOptions = function() { + this.projectService.allowLocalPluginLoads = true; + return originalEnablePluginsWithOptions.apply(this, arguments); + }; + + // And here is the point where we hijack the VSCode <-> TS communications + // by adding ourselves in the middle. We locate everything that looks + // like an absolute path of ours and normalize it. + + const Session = tsserver.server.Session; + const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; + let hostInfo = `unknown`; + + Object.assign(Session.prototype, { + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; + + if ( + parsedMessage != null && + typeof parsedMessage === `object` && + parsedMessage.arguments && + typeof parsedMessage.arguments.hostInfo === `string` + ) { + hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } + } + + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); + }, + + send(/** @type {any} */ msg) { + return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { + return typeof value === `string` ? toEditorPath(value) : value; + }))); + } + }); + + return tsserver; +}; + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserverlibrary.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsserverlibrary.js your application uses +module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); diff --git a/.yarn/sdks/typescript/lib/typescript.js b/.yarn/sdks/typescript/lib/typescript.js new file mode 100644 index 000000000..cbdbf1500 --- /dev/null +++ b/.yarn/sdks/typescript/lib/typescript.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire, createRequireFromPath} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/typescript.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/typescript.js your application uses +module.exports = absRequire(`typescript/lib/typescript.js`); diff --git a/.yarn/sdks/typescript/package.json b/.yarn/sdks/typescript/package.json new file mode 100644 index 000000000..97b00525a --- /dev/null +++ b/.yarn/sdks/typescript/package.json @@ -0,0 +1,6 @@ +{ + "name": "typescript", + "version": "4.6.3-sdk", + "main": "./lib/typescript.js", + "type": "commonjs" +} diff --git a/__tests__/client-state/mst.test.ts b/__tests__/client-state/mst.test.ts index 878ebda8d..631e970e8 100644 --- a/__tests__/client-state/mst.test.ts +++ b/__tests__/client-state/mst.test.ts @@ -44,12 +44,12 @@ describe('test the mobx state tree nodes', () => { function fillOutForm(form: Instance) { // TODO: this should NOT use numbered indexes to fill the form, as that makes ordering changes cause tests to fail. form.fields[0].setValue('65') // age - // form.fields[1].setValue('65') // oasAge - form.fields[1].setValue('20000') // income - form.fields[2].setValue(LegalStatus.CANADIAN_CITIZEN) - form.fields[3].setValue(LivingCountry.CANADA) - form.fields[4].setValue('false') // never lived outside Canada - form.fields[5].setValue(MaritalStatus.SINGLE) + form.fields[1].setValue('false') // oasDefer + form.fields[2].setValue('true') // incomeAvailable + form.fields[3].setValue(LegalStatus.CANADIAN_CITIZEN) + form.fields[4].setValue(LivingCountry.CANADA) + form.fields[5].setValue('false') // never lived outside Canada + form.fields[6].setValue(MaritalStatus.SINGLE) } async function instantiateFormFields() { @@ -87,14 +87,14 @@ describe('test the mobx state tree nodes', () => { const res = await instantiateFormFields() const form: Instance = root.form form.setupForm(res.body.fieldData) - expect(form.fields).toHaveLength(6) + expect(form.fields).toHaveLength(7) }) it("can clear an entire form's fields", async () => { const res = await instantiateFormFields() const form: Instance = root.form form.setupForm(res.body.fieldData) - expect(form.fields).toHaveLength(6) + expect(form.fields).toHaveLength(7) form.removeAllFields() expect(form.fields).toHaveLength(0) }) @@ -107,7 +107,7 @@ describe('test the mobx state tree nodes', () => { sendReq.mockImplementationOnce(async () => res) form.setupForm(res.body.fieldData) - expect(form.fields).toHaveLength(6) + expect(form.fields).toHaveLength(7) form.clearForm() for (const field of form.fields) { @@ -164,8 +164,9 @@ describe('test the mobx state tree nodes', () => { expect(input).toEqual({ _language: 'en', livingCountry: 'CAN' }) // blank form includes default livingCountry fillOutForm(form) input = form.buildObjectWithFormData() - expect(input.income).toEqual('20000') + expect(input.incomeAvailable).toEqual('true') expect(input.age).toEqual('65') + expect(input.oasDefer).toEqual('false') expect(input.maritalStatus).toEqual('single') expect(input.livingCountry).toEqual('CAN') expect(input.legalStatus).toEqual('canadianCitizen') diff --git a/__tests__/pages/api/benefits.test.ts b/__tests__/pages/api/benefits.test.ts index df8630f38..9f4e898bd 100644 --- a/__tests__/pages/api/benefits.test.ts +++ b/__tests__/pages/api/benefits.test.ts @@ -10,8 +10,10 @@ import { } from '../../../utils/api/definitions/enums' import { FieldKey } from '../../../utils/api/definitions/fields' import roundToTwo from '../../../utils/api/helpers/roundToTwo' -import { legalValues } from '../../../utils/api/scrapers/output' +import legalValues from '../../../utils/api/scrapers/output' import { + age60NoDefer, + age65NoDefer, canadaWholeLife, canadian, expectAfsEligible, @@ -23,6 +25,8 @@ import { expectOasGisEligible, expectOasGisTooYoung, expectOasGisUnavailable, + income10k, + partnerIncomeZero, partnerNoHelpNeeded, partnerUndefined, } from './expectUtils' @@ -31,9 +35,8 @@ import { mockGetRequest, mockGetRequestError } from './factory' describe('consolidated benefit tests: unavailable', () => { it('returns "unavailable" - living in Canada, under 10 years in Canada, lived in social country', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -51,9 +54,8 @@ describe('consolidated benefit tests: unavailable', () => { it('returns "unavailable" - living in No Agreement, under 20 years in Canada, lived in social country', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -80,9 +82,8 @@ describe('consolidated benefit tests: unavailable', () => { it('returns "unavailable" - living in Agreement, under 20 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -108,9 +109,8 @@ describe('consolidated benefit tests: unavailable', () => { }) it('returns "unavailable" - age 60, living in Agreement, under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -118,7 +118,7 @@ describe('consolidated benefit tests: unavailable', () => { yearsInCanadaSince18: 9, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expect(res.body.summary.state).toEqual(EstimationSummaryState.UNAVAILABLE) @@ -146,13 +146,16 @@ describe('consolidated benefit tests: unavailable', () => { describe('consolidated benefit tests: ineligible', () => { it('returns "ineligible" - age 50', async () => { const res = await mockGetRequest({ + incomeAvailable: true, income: 20000, age: 50, - oasAge: 65, + oasDefer: false, + oasAge: undefined, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 10000, ...partnerNoHelpNeeded, }) @@ -168,15 +171,15 @@ describe('consolidated benefit tests: ineligible', () => { it('returns "ineligible" - age 60, married, living in Canada, under 10 years in Canada, not lived in social country', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 9, everLivedSocialCountry: false, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 10000, ...partnerNoHelpNeeded, }) @@ -195,9 +198,8 @@ describe('consolidated benefit tests: ineligible', () => { it('returns "ineligible" - age 60, single, living in No Agreement, under 20 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -223,9 +225,8 @@ describe('consolidated benefit tests: ineligible', () => { it('returns "ineligible" - age 60, married, living in No Agreement, under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -233,7 +234,7 @@ describe('consolidated benefit tests: ineligible', () => { yearsInCanadaSince18: 9, everLivedSocialCountry: false, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectAllIneligible(res) @@ -253,11 +254,11 @@ describe('consolidated benefit tests: ineligible', () => { }) describe('consolidated benefit tests: max income checks', () => { - it(`OAS: max income is ${legalValues.MAX_OAS_INCOME}`, async () => { + it(`OAS: max income is ${legalValues.oas.incomeLimit}`, async () => { const input = { - income: legalValues.MAX_OAS_INCOME, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.oas.incomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, ...canadaWholeLife, @@ -270,16 +271,16 @@ describe('consolidated benefit tests: max income checks', () => { expect(resError.body.detail.details[0].path[0]).toEqual(FieldKey.INCOME) let resSuccess = await mockGetRequest({ ...input, - income: legalValues.MAX_OAS_INCOME - 1, + income: legalValues.oas.incomeLimit - 1, }) expectOasEligible(resSuccess) }) - it(`GIS: max income when single is ${legalValues.MAX_GIS_INCOME_SINGLE}`, async () => { + it(`GIS: max income when single is ${legalValues.gis.singleIncomeLimit}`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_SINGLE, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.singleIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, ...canadaWholeLife, @@ -292,20 +293,20 @@ describe('consolidated benefit tests: max income checks', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_SINGLE - 1, + income: legalValues.gis.singleIncomeLimit - 1, }) expectGisEligible(res) }) - it(`GIS: max income when married and no partner OAS is ${legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW}`, async () => { + it(`GIS: max income when married and no partner OAS is ${legalValues.gis.spouseNoOasIncomeLimit}`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseNoOasIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.NONE, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, } let res = await mockGetRequest(input) @@ -315,20 +316,20 @@ describe('consolidated benefit tests: max income checks', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW - 1, + income: legalValues.gis.spouseNoOasIncomeLimit - 1, }) expectGisEligible(res) }) - it(`GIS: max income when married and partner OAS is ${legalValues.MAX_GIS_INCOME_PARTNER_OAS}`, async () => { + it(`GIS: max income when married and partner OAS is ${legalValues.gis.spouseOasIncomeLimit}`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseOasIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, } let res = await mockGetRequest(input) @@ -338,20 +339,43 @@ describe('consolidated benefit tests: max income checks', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS - 1, + income: legalValues.gis.spouseOasIncomeLimit - 1, }) expectGisEligible(res) }) - it(`ALW: max income when married and partner OAS is ${legalValues.MAX_ALW_INCOME}`, async () => { + it(`GIS: max income when married and partner ALW is ${legalValues.gis.spouseAlwIncomeLimit}`, async () => { const input = { - income: legalValues.MAX_ALW_INCOME, - age: 60, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseAlwIncomeLimit, + ...age65NoDefer, + maritalStatus: MaritalStatus.PARTNERED, + ...canadian, + ...canadaWholeLife, + partnerBenefitStatus: PartnerBenefitStatus.ALW, + ...partnerIncomeZero, + ...partnerNoHelpNeeded, + } + let res = await mockGetRequest(input) + expect(res.body.results.gis.eligibility.result).toEqual( + ResultKey.INELIGIBLE + ) + expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) + res = await mockGetRequest({ + ...input, + income: legalValues.gis.spouseAlwIncomeLimit - 1, + }) + expectGisEligible(res) + }) + it(`ALW: max income when married and partner OAS is ${legalValues.alw.alwIncomeLimit}`, async () => { + const input = { + incomeAvailable: true, + income: legalValues.alw.alwIncomeLimit, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, } let res = await mockGetRequest(input) @@ -361,16 +385,16 @@ describe('consolidated benefit tests: max income checks', () => { expect(res.body.results.alw.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_ALW_INCOME - 1, + income: legalValues.alw.alwIncomeLimit - 1, }) expectAlwEligible(res) }) - it(`AFS: max income when widowed is ${legalValues.MAX_AFS_INCOME}`, async () => { + it(`AFS: max income when widowed is ${legalValues.alw.afsIncomeLimit}`, async () => { const input = { - income: legalValues.MAX_AFS_INCOME, - age: 60, - oasAge: 65, + incomeAvailable: true, + income: legalValues.alw.afsIncomeLimit, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, @@ -383,7 +407,7 @@ describe('consolidated benefit tests: max income checks', () => { expect(res.body.results.afs.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_AFS_INCOME - 1, + income: legalValues.alw.afsIncomeLimit - 1, }) expectAfsEligible(res) }) @@ -392,9 +416,8 @@ describe('consolidated benefit tests: max income checks', () => { describe('consolidated benefit tests: eligible: 65+', () => { it('returns "eligible" - separated, partial oas', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -405,16 +428,15 @@ describe('consolidated benefit tests: eligible: 65+', () => { expectOasGisEligible( res, EntitlementResultType.PARTIAL, - roundToTwo(legalValues.MAX_OAS_ENTITLEMENT / 4) + roundToTwo(legalValues.oas.amount / 4) ) expectAlwAfsTooOld(res) }) it('returns "eligible" - single, living in Agreement, 20 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -426,7 +448,7 @@ describe('consolidated benefit tests: eligible: 65+', () => { expectOasEligible( res, EntitlementResultType.PARTIAL, - roundToTwo(legalValues.MAX_OAS_ENTITLEMENT / 2) + roundToTwo(legalValues.oas.amount / 2) ) expect(res.body.results.gis.eligibility.result).toEqual( ResultKey.INELIGIBLE @@ -439,9 +461,8 @@ describe('consolidated benefit tests: eligible: 65+', () => { it('returns "eligible" - single, living in No Agreement, 20 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -453,7 +474,7 @@ describe('consolidated benefit tests: eligible: 65+', () => { expectOasEligible( res, EntitlementResultType.PARTIAL, - roundToTwo(legalValues.MAX_OAS_ENTITLEMENT / 2) + roundToTwo(legalValues.oas.amount / 2) ) expect(res.body.results.gis.eligibility.result).toEqual( ResultKey.INELIGIBLE @@ -466,13 +487,13 @@ describe('consolidated benefit tests: eligible: 65+', () => { it('returns "eligible" - married, full oas (no clawback)', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 10000, ...partnerNoHelpNeeded, }) @@ -488,16 +509,51 @@ describe('consolidated benefit tests: eligible: 65+', () => { ) }) + it('returns "eligible" - deferral', async () => { + const deferralIncreaseByMonth = 0.006 // the increase to the monthly payment per month deferred + const oasBaseAmount = legalValues.oas.amount + const deferYears = 5 + const oasDeferredAmount = roundToTwo( + oasBaseAmount * (1 + deferYears * 12 * deferralIncreaseByMonth) + ) + + let inputBase = { + ...income10k, + maritalStatus: MaritalStatus.PARTNERED, + ...canadian, + ...canadaWholeLife, + partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, + partnerIncome: 10000, + ...partnerNoHelpNeeded, + } + let inputNoDefer65 = { ...inputBase, age: 65, oasDefer: false, oasAge: 65 } + let res = await mockGetRequest(inputNoDefer65) + expect(res.body.results.oas.entitlement.result).toEqual(oasBaseAmount) + + let inputNoDefer70 = { ...inputBase, age: 70, oasDefer: false, oasAge: 65 } + res = await mockGetRequest(inputNoDefer70) + expect(res.body.results.oas.entitlement.result).toEqual(oasBaseAmount) + + let input65Defer70 = { ...inputBase, age: 65, oasDefer: true, oasAge: 70 } + res = await mockGetRequest(input65Defer70) + expect(res.body.results.oas.entitlement.result).toEqual(oasDeferredAmount) + + let input70Defer70 = { ...inputBase, age: 70, oasDefer: true, oasAge: 70 } + res = await mockGetRequest(input70Defer70) + expect(res.body.results.oas.entitlement.result).toEqual(oasDeferredAmount) + }) + it('returns "eligible" - married, income high so OAS only (with clawback)', async () => { const res = await mockGetRequest({ - income: legalValues.MAX_OAS_INCOME - 1, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.oas.incomeLimit - 1, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectOasEligible(res) @@ -518,20 +574,22 @@ describe('consolidated benefit tests: eligible: 65+', () => { it('returns "eligible" - married, full oas, age 75', async () => { const res = await mockGetRequest({ - income: 10000, + ...income10k, age: 75, - oasAge: 65, + oasDefer: false, + oasAge: undefined, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 10000, ...partnerNoHelpNeeded, }) expectOasGisEligible( res, EntitlementResultType.FULL, - roundToTwo(legalValues.MAX_OAS_ENTITLEMENT * 1.1) + roundToTwo(legalValues.oas.amount * 1.1) ) expectAlwAfsTooOld(res) @@ -548,14 +606,13 @@ describe('consolidated benefit tests: eligible: 65+', () => { describe('consolidated benefit tests: eligible: 60-64', () => { it('returns "ALW eligible" - married', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectOasGisTooYoung(res) @@ -570,9 +627,8 @@ describe('consolidated benefit tests: eligible: 60-64', () => { it('returns "AFS eligible" - widowed', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, @@ -590,16 +646,15 @@ describe('consolidated benefit tests: eligible: 60-64', () => { it('returns "ALW eligible" - married, 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 10, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectOasGisTooYoung(res) @@ -607,9 +662,8 @@ describe('consolidated benefit tests: eligible: 60-64', () => { }) it('returns "ALW eligible" - married, living in Agreement, 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -617,7 +671,7 @@ describe('consolidated benefit tests: eligible: 60-64', () => { yearsInCanadaSince18: 10, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expect(res.body.results.oas.eligibility.result).toEqual( @@ -637,9 +691,8 @@ describe('consolidated benefit tests: eligible: 60-64', () => { it('returns "ALW eligible" - married, living in No Agreement, 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -647,7 +700,7 @@ describe('consolidated benefit tests: eligible: 60-64', () => { yearsInCanadaSince18: 10, everLivedSocialCountry: false, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expect(res.body.results.oas.eligibility.result).toEqual( @@ -667,16 +720,17 @@ describe('consolidated benefit tests: eligible: 60-64', () => { it('returns "ALW eligible" - age 64, married, 19 years in Canada, lived in social country', async () => { const res = await mockGetRequest({ - income: 10000, + ...income10k, age: 64, - oasAge: 65, + oasDefer: false, + oasAge: undefined, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 19, everLivedSocialCountry: true, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectOasGisTooYoung(res) diff --git a/__tests__/pages/api/expectUtils.ts b/__tests__/pages/api/expectUtils.ts index 87c2ecd47..ea67f26d1 100644 --- a/__tests__/pages/api/expectUtils.ts +++ b/__tests__/pages/api/expectUtils.ts @@ -7,7 +7,7 @@ import { ResultReason, } from '../../../utils/api/definitions/enums' import { ResponseSuccess } from '../../../utils/api/definitions/types' -import { legalValues } from '../../../utils/api/scrapers/output' +import legalValues from '../../../utils/api/scrapers/output' import { MockResponseObject } from './factory' export function expectAlwAfsTooOld(res: MockResponseObject) { @@ -56,7 +56,7 @@ export function expectOasEligible( expect(res.body.results.oas.eligibility.reason).toEqual(ResultReason.NONE) expect(res.body.results.oas.entitlement.type).toEqual(oasType) if (oasType === EntitlementResultType.FULL && !entitlement) - entitlement = legalValues.MAX_OAS_ENTITLEMENT + entitlement = legalValues.oas.amount if (entitlement) expect(res.body.results.oas.entitlement.result).toEqual(entitlement) } @@ -112,6 +112,7 @@ export function expectOasGisEligible( export const partnerUndefined = { partnerBenefitStatus: undefined, + partnerIncomeAvailable: undefined, partnerIncome: undefined, partnerAge: undefined, partnerLivingCountry: undefined, @@ -130,11 +131,39 @@ export const partnerNoHelpNeeded = { partnerEverLivedSocialCountry: undefined, } +export const partnerIncomeZero = { + partnerIncomeAvailable: true, + partnerIncome: 0, +} + +export const incomeZero = { + incomeAvailable: true, + income: 0, +} + +export const income10k = { + incomeAvailable: true, + income: 10000, +} + +export const age65NoDefer = { + age: 65, + oasDefer: false, + oasAge: undefined, +} + +export const age60NoDefer = { + age: 60, + oasDefer: false, + oasAge: undefined, +} + export const canadaWholeLife = { livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, } + export const canadian = { livingCountry: LivingCountry.CANADA, legalStatus: LegalStatus.CANADIAN_CITIZEN, diff --git a/__tests__/pages/api/field-reqs.test.ts b/__tests__/pages/api/field-reqs.test.ts index bf8f9d0dc..72323cf06 100644 --- a/__tests__/pages/api/field-reqs.test.ts +++ b/__tests__/pages/api/field-reqs.test.ts @@ -7,18 +7,21 @@ import { } from '../../../utils/api/definitions/enums' import { FieldKey } from '../../../utils/api/definitions/fields' import { + age65NoDefer, canadaWholeLife, canadian, - partnerNoHelpNeeded, + income10k, partnerUndefined, } from './expectUtils' import { mockGetRequest } from './factory' describe('field requirement analysis', () => { - it('requires only income when nothing provided', async () => { + it('requires base questions when nothing provided', async () => { const res = await mockGetRequest({ + incomeAvailable: undefined, income: undefined, age: undefined, + oasDefer: undefined, oasAge: undefined, maritalStatus: undefined, livingCountry: undefined, @@ -31,329 +34,52 @@ describe('field requirement analysis', () => { expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) expect(res.body.missingFields).toEqual([ FieldKey.AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - }) - - it('requires fields when only income provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: undefined, - oasAge: undefined, - maritalStatus: undefined, - livingCountry: undefined, - legalStatus: undefined, - livedOutsideCanada: undefined, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.AGE, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - }) - - it('requires fields when only income/age provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: undefined, - livingCountry: undefined, - legalStatus: undefined, - livedOutsideCanada: undefined, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - ]) - }) - - it('requires fields when only income/age/marital provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - livingCountry: undefined, - legalStatus: undefined, - livedOutsideCanada: undefined, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - }) - - it('requires fields when only income/age/marital/country provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - livingCountry: LivingCountry.CANADA, - legalStatus: undefined, - livedOutsideCanada: undefined, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.LEGAL_STATUS, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - }) - - it('requires fields when only income/age/marital/country/legal provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - ...canadian, - livedOutsideCanada: undefined, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - }) - - it('requires fields when only income/age/marital/country/legal/lifeCanada provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - ...canadian, - livedOutsideCanada: true, - yearsInCanadaSince18: undefined, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - }) - - it('requires fields when only income/age/marital/country/legal/lifeCanada/years provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - ...canadian, - livedOutsideCanada: true, - yearsInCanadaSince18: 5, - everLivedSocialCountry: undefined, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - }) - - it('requires fields when only income/age/marital/country/legal/lifeCanada/years/socialCountry provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - ...canadian, - livedOutsideCanada: true, - yearsInCanadaSince18: 5, - everLivedSocialCountry: true, - ...partnerUndefined, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([ - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, + FieldKey.OAS_DEFER, + FieldKey.INCOME_AVAILABLE, FieldKey.LEGAL_STATUS, FieldKey.LIVING_COUNTRY, FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, ]) - }) - - it('requires fields when only income/age/marital/country/legal/lifeCanada/years/socialCountry/partnerBenefits provided', async () => { - const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, - maritalStatus: MaritalStatus.PARTNERED, - ...canadian, - livedOutsideCanada: true, - yearsInCanadaSince18: 5, - everLivedSocialCountry: true, - partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: undefined, - ...partnerNoHelpNeeded, - }) - expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) - expect(res.body.missingFields).toEqual([FieldKey.PARTNER_INCOME]) expect(res.body.visibleFields).toEqual([ FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, + FieldKey.OAS_DEFER, + FieldKey.INCOME_AVAILABLE, FieldKey.LEGAL_STATUS, FieldKey.LIVING_COUNTRY, FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, ]) }) it('requires no fields when all provided', async () => { const res = await mockGetRequest({ - income: 10000, + ...income10k, age: 65, - oasAge: 65, + oasDefer: true, + oasAge: 70, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 5, everLivedSocialCountry: true, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 10000, - ...partnerNoHelpNeeded, + partnerAge: 65, + partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, + partnerLivingCountry: LivingCountry.CANADA, + partnerLivedOutsideCanada: true, + partnerYearsInCanadaSince18: 5, + partnerEverLivedSocialCountry: true, }) expect(res.body.summary.state).toEqual(EstimationSummaryState.UNAVAILABLE) expect(res.body.missingFields).toEqual([]) expect(res.body.visibleFields).toEqual([ FieldKey.AGE, + FieldKey.OAS_DEFER, FieldKey.OAS_AGE, + FieldKey.INCOME_AVAILABLE, FieldKey.INCOME, FieldKey.LEGAL_STATUS, FieldKey.LIVING_COUNTRY, @@ -361,18 +87,20 @@ describe('field requirement analysis', () => { FieldKey.YEARS_IN_CANADA_SINCE_18, FieldKey.EVER_LIVED_SOCIAL_COUNTRY, FieldKey.MARITAL_STATUS, + FieldKey.PARTNER_INCOME_AVAILABLE, FieldKey.PARTNER_INCOME, FieldKey.PARTNER_BENEFIT_STATUS, + FieldKey.PARTNER_YEARS_IN_CANADA_SINCE_18, + FieldKey.PARTNER_EVER_LIVED_SOCIAL_COUNTRY, ]) }) }) describe('field requirements analysis: conditional fields', () => { - it('requires "yearsInCanadaSince18" when lifeCanada=false', async () => { + it('requires "yearsInCanadaSince18" when livedOutsideCanada=true', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -382,23 +110,13 @@ describe('field requirements analysis: conditional fields', () => { }) expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) expect(res.body.missingFields).toEqual([FieldKey.YEARS_IN_CANADA_SINCE_18]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.MARITAL_STATUS, - ]) + expect(res.body.visibleFields).toContain(FieldKey.YEARS_IN_CANADA_SINCE_18) }) it('requires "everLivedSocialCountry" when living in Canada and under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -408,24 +126,13 @@ describe('field requirements analysis: conditional fields', () => { }) expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) expect(res.body.missingFields).toEqual([FieldKey.EVER_LIVED_SOCIAL_COUNTRY]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, - FieldKey.MARITAL_STATUS, - ]) + expect(res.body.visibleFields).toContain(FieldKey.EVER_LIVED_SOCIAL_COUNTRY) }) - it('requires "everLivedSocialCountry" when living in No Agreement and under 10 years in Canada', async () => { + it('requires "everLivedSocialCountry" when living in No Agreement and under 20 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -436,24 +143,13 @@ describe('field requirements analysis: conditional fields', () => { }) expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) expect(res.body.missingFields).toEqual([FieldKey.EVER_LIVED_SOCIAL_COUNTRY]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.YEARS_IN_CANADA_SINCE_18, - FieldKey.EVER_LIVED_SOCIAL_COUNTRY, - FieldKey.MARITAL_STATUS, - ]) + expect(res.body.visibleFields).toContain(FieldKey.EVER_LIVED_SOCIAL_COUNTRY) }) it('requires partner questions when marital=married', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, @@ -461,19 +157,10 @@ describe('field requirements analysis: conditional fields', () => { }) expect(res.body.summary.state).toEqual(EstimationSummaryState.MORE_INFO) expect(res.body.missingFields).toEqual([ - FieldKey.PARTNER_INCOME, - FieldKey.PARTNER_BENEFIT_STATUS, - ]) - expect(res.body.visibleFields).toEqual([ - FieldKey.AGE, - FieldKey.OAS_AGE, - FieldKey.INCOME, - FieldKey.LEGAL_STATUS, - FieldKey.LIVING_COUNTRY, - FieldKey.LIVED_OUTSIDE_CANADA, - FieldKey.MARITAL_STATUS, - FieldKey.PARTNER_INCOME, + FieldKey.PARTNER_INCOME_AVAILABLE, FieldKey.PARTNER_BENEFIT_STATUS, ]) + expect(res.body.visibleFields).toContain(FieldKey.PARTNER_INCOME_AVAILABLE) + expect(res.body.visibleFields).toContain(FieldKey.PARTNER_BENEFIT_STATUS) }) }) diff --git a/__tests__/pages/api/help-me-find-out.test.ts b/__tests__/pages/api/help-me-find-out.test.ts index 9a07fbe86..400ea04cc 100644 --- a/__tests__/pages/api/help-me-find-out.test.ts +++ b/__tests__/pages/api/help-me-find-out.test.ts @@ -7,29 +7,33 @@ import { ResultKey, ResultReason, } from '../../../utils/api/definitions/enums' -import { legalValues } from '../../../utils/api/scrapers/output' +import legalValues from '../../../utils/api/scrapers/output' import { + age60NoDefer, + age65NoDefer, canadian, expectAlwEligible, expectOasEligible, expectOasGisEligible, expectOasGisTooYoung, + incomeZero, + partnerIncomeZero, } from './expectUtils' import { mockGetRequest } from './factory' describe('Help Me Find Out scenarios', () => { - it(`works when client old, partner old (partner=noOas, therefore gis income limit ${legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW}, gis table 3)`, async () => { + it(`works when client old, partner old (partner=noOas, therefore gis income limit ${legalValues.gis.spouseNoOasIncomeLimit}, gis table 3)`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseNoOasIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 65, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -45,23 +49,23 @@ describe('Help Me Find Out scenarios', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_PARTNER_NO_OAS_NO_ALW - 1, + income: legalValues.gis.spouseNoOasIncomeLimit - 1, }) expectOasGisEligible(res) expect(res.body.results.gis.entitlement.result).toEqual(0.79) // table 3 }) - it(`works when client old, partner old (partner=partialOas, therefore gis income limit ${legalValues.MAX_GIS_INCOME_PARTNER_OAS}, gis table 2)`, async () => { + it(`works when client old, partner old (partner=partialOas, therefore gis income limit ${legalValues.gis.spouseOasIncomeLimit}, gis table 2)`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseOasIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 65, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -77,23 +81,23 @@ describe('Help Me Find Out scenarios', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS - 1, + income: legalValues.gis.spouseOasIncomeLimit - 1, }) expectOasGisEligible(res) expect(res.body.results.gis.entitlement.result).toEqual(0.68) // table 2 }) - it(`works when client old, partner old (partner=fullOas, therefore gis income limit ${legalValues.MAX_GIS_INCOME_PARTNER_OAS}, gis table 2)`, async () => { + it(`works when client old, partner old (partner=fullOas, therefore gis income limit ${legalValues.gis.spouseOasIncomeLimit}, gis table 2)`, async () => { const input = { - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.gis.spouseOasIncomeLimit, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 65, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -109,23 +113,23 @@ describe('Help Me Find Out scenarios', () => { expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) res = await mockGetRequest({ ...input, - income: legalValues.MAX_GIS_INCOME_PARTNER_OAS - 1, + income: legalValues.gis.spouseOasIncomeLimit - 1, }) expectOasGisEligible(res) expect(res.body.results.gis.entitlement.result).toEqual(0.68) // table 2 }) it(`works when client old, partner young (partner=noAllowance, therefore gis table 3)`, async () => { const input = { - income: legalValues.MAX_ALW_INCOME, // too high for allowance - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.alw.alwIncomeLimit, // too high for allowance + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 60, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -140,16 +144,16 @@ describe('Help Me Find Out scenarios', () => { }) it('works when client old, partner young (partner=allowance, therefore gis table 4)', async () => { const input = { - income: legalValues.MAX_ALW_INCOME - 1, // okay for allowance - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.alw.alwIncomeLimit - 1, // okay for allowance + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 60, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -163,16 +167,15 @@ describe('Help Me Find Out scenarios', () => { }) it('works when client young, partner young (no one gets anything)', async () => { const input = { - income: 0, - age: 60, - oasAge: 65, + ...incomeZero, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 60, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -200,16 +203,15 @@ describe('Help Me Find Out scenarios', () => { }) it('works when client young, partner old (partner=gis, therefore client alw eligible)', async () => { const input = { - income: 0, - age: 60, - oasAge: 65, + ...incomeZero, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 65, partnerLivingCountry: LivingCountry.CANADA, partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -232,16 +234,15 @@ describe('Help Me Find Out scenarios', () => { }) it('works when client young, partner old (partner=noGis, therefore client alw ineligible)', async () => { const input = { - income: 0, - age: 60, - oasAge: 65, + ...incomeZero, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: false, yearsInCanadaSince18: undefined, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.HELP_ME, - partnerIncome: 0, + ...partnerIncomeZero, partnerAge: 65, partnerLivingCountry: LivingCountry.NO_AGREEMENT, // gis ineligible partnerLegalStatus: LegalStatus.CANADIAN_CITIZEN, diff --git a/__tests__/pages/api/index.test.ts b/__tests__/pages/api/index.test.ts index 9728cf361..861139b48 100644 --- a/__tests__/pages/api/index.test.ts +++ b/__tests__/pages/api/index.test.ts @@ -7,13 +7,19 @@ import { ResultKey, ResultReason, } from '../../../utils/api/definitions/enums' +import legalValues from '../../../utils/api/scrapers/output' import { + age60NoDefer, + age65NoDefer, canadaWholeLife, canadian, expectAfsEligible, expectAlwEligible, expectGisEligible, expectOasEligible, + income10k, + incomeZero, + partnerIncomeZero, partnerNoHelpNeeded, partnerUndefined, } from './expectUtils' @@ -22,9 +28,8 @@ import { mockGetRequest, mockPartialGetRequest } from './factory' describe('OAS entitlement scenarios', () => { it('returns "eligible for $619.38" when 39 years in Canada (rounding test)', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -39,9 +44,8 @@ describe('OAS entitlement scenarios', () => { describe('GIS entitlement scenarios', () => { it('returns "$394.68" when single and 10000 income', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, ...canadaWholeLife, @@ -51,9 +55,8 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$959.26" when single and 0 income', async () => { const res = await mockGetRequest({ - income: 0, - age: 65, - oasAge: 65, + ...incomeZero, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, ...canadaWholeLife, @@ -63,41 +66,39 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$850.26" when married and 10000 income and no partner OAS', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.NONE, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectGisEligible(res, 861.86) }) it('returns "$959.26" when married and 0 income and no partner OAS', async () => { const res = await mockGetRequest({ - income: 0, - age: 65, - oasAge: 65, + ...incomeZero, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.NONE, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectGisEligible(res, 968.86) }) it('returns "$819.26" when married and 10000 income + 1000 partner income and no partner OAS', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.NONE, + partnerIncomeAvailable: true, partnerIncome: 1000, ...partnerNoHelpNeeded, }) @@ -105,13 +106,13 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$306.33" when married and 10000 income + 1000 partner income and partner OAS', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, + partnerIncomeAvailable: true, partnerIncome: 1000, ...partnerNoHelpNeeded, }) @@ -119,13 +120,13 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$521.33" when married and 10000 income + 1000 partner income and partner Allowance', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.ALW, + partnerIncomeAvailable: true, partnerIncome: 1000, ...partnerNoHelpNeeded, }) @@ -133,37 +134,35 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$577.43" when married and 0 income + 0 partner income and partner OAS', async () => { const res = await mockGetRequest({ - income: 0, - age: 65, - oasAge: 65, + ...incomeZero, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectGisEligible(res, 583.2) }) it('returns "$577.43" when married and 0 income + 0 partner income and partner Allowance', async () => { const res = await mockGetRequest({ - income: 0, - age: 65, - oasAge: 65, + ...incomeZero, + ...age65NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.ALW, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectGisEligible(res, 583.2) }) it('returns "$1239.38" when single and 1000 income, only 20 years in Canada (Partial OAS)', async () => { const res = await mockGetRequest({ + incomeAvailable: true, income: 1000, - age: 65, - oasAge: 65, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -175,9 +174,9 @@ describe('GIS entitlement scenarios', () => { }) it('returns "$1399.95" when single and 1000 income, only 10 years in Canada (Partial OAS)', async () => { const res = await mockGetRequest({ + incomeAvailable: true, income: 1000, - age: 65, - oasAge: 65, + ...age65NoDefer, maritalStatus: MaritalStatus.SINGLE, ...canadian, livedOutsideCanada: true, @@ -192,16 +191,15 @@ describe('GIS entitlement scenarios', () => { describe('basic Allowance scenarios', () => { it('returns "ineligible" when partner not receiving OAS', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 10, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.NONE, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expect(res.body.results.alw.eligibility.result).toEqual( @@ -216,14 +214,14 @@ describe('basic Allowance scenarios', () => { describe('Allowance entitlement scenarios', () => { it('returns "eligible for $334.33" when 40 years in Canada and income=20000', async () => { const res = await mockGetRequest({ + incomeAvailable: true, income: 20000, - age: 60, - oasAge: 65, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectAlwEligible(res, 341.68) @@ -231,28 +229,26 @@ describe('Allowance entitlement scenarios', () => { it('returns "eligible for $565.35" when 40 years in Canada and income=10000', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectAlwEligible(res, 565.35) }) it('returns "eligible for $1231.87" when 40 years in Canada and income=0', async () => { const res = await mockGetRequest({ - income: 0, - age: 60, - oasAge: 65, + ...incomeZero, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, ...canadaWholeLife, partnerBenefitStatus: PartnerBenefitStatus.OAS_GIS, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expectAlwEligible(res, 1231.87) @@ -262,9 +258,9 @@ describe('Allowance entitlement scenarios', () => { describe('basic Allowance for Survivor scenarios', () => { it('returns "ineligible due to age" when age 65 and high income', async () => { const res = await mockPartialGetRequest({ - income: 26257, - age: 65, - oasAge: 65, + incomeAvailable: true, + income: legalValues.alw.afsIncomeLimit + 1, + ...age65NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, @@ -277,9 +273,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "ineligible" when age over 64', async () => { const res = await mockGetRequest({ - income: 10000, - age: 65, - oasAge: 65, + ...income10k, + ...age65NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, livedOutsideCanada: true, @@ -294,9 +289,10 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "ineligible" when age under 60', async () => { const res = await mockGetRequest({ - income: 10000, + ...income10k, age: 59, - oasAge: 65, + oasDefer: false, + oasAge: undefined, maritalStatus: MaritalStatus.WIDOWED, ...canadian, livedOutsideCanada: true, @@ -313,9 +309,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "ineligible" when citizen and under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, livedOutsideCanada: true, @@ -332,16 +327,15 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "ineligible" when married', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.PARTNERED, ...canadian, livedOutsideCanada: true, yearsInCanadaSince18: 10, everLivedSocialCountry: undefined, partnerBenefitStatus: PartnerBenefitStatus.NONE, - partnerIncome: 0, + ...partnerIncomeZero, ...partnerNoHelpNeeded, }) expect(res.body.results.afs.eligibility.result).toEqual( @@ -353,9 +347,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "eligible" when widowed', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, livedOutsideCanada: true, @@ -367,9 +360,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "eligible" when living in Agreement and 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -382,9 +374,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "unavailable" when living in Agreement and under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, livingCountry: LivingCountry.AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -402,9 +393,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "eligible" when living in No Agreement and 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -417,9 +407,8 @@ describe('basic Allowance for Survivor scenarios', () => { }) it('returns "ineligible" when living in No Agreement and under 10 years in Canada', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, livingCountry: LivingCountry.NO_AGREEMENT, legalStatus: LegalStatus.CANADIAN_CITIZEN, @@ -440,9 +429,9 @@ describe('basic Allowance for Survivor scenarios', () => { describe('AFS entitlement scenarios', () => { it('returns "eligible for $260.10" when 40 years in Canada and income=20000', async () => { const res = await mockGetRequest({ + incomeAvailable: true, income: 20000, - age: 60, - oasAge: 65, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, @@ -452,9 +441,8 @@ describe('AFS entitlement scenarios', () => { }) it('returns "eligible for $681.35" when 40 years in Canada and income=10000', async () => { const res = await mockGetRequest({ - income: 10000, - age: 60, - oasAge: 65, + ...income10k, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, @@ -464,9 +452,8 @@ describe('AFS entitlement scenarios', () => { }) it('returns "eligible for $1468.47" when 40 years in Canada and income=0', async () => { const res = await mockGetRequest({ - income: 0, - age: 60, - oasAge: 65, + ...incomeZero, + ...age60NoDefer, maritalStatus: MaritalStatus.WIDOWED, ...canadian, ...canadaWholeLife, diff --git a/client-state/models/Form.ts b/client-state/models/Form.ts index c1a7a3439..b48796e22 100644 --- a/client-state/models/Form.ts +++ b/client-state/models/Form.ts @@ -7,7 +7,11 @@ import { } from '../../i18n/web' import { BenefitHandler } from '../../utils/api/benefitHandler' import { Language, ValidationErrors } from '../../utils/api/definitions/enums' -import { FieldData, FieldKey } from '../../utils/api/definitions/fields' +import { + FieldData, + fieldDefinitions, + FieldKey, +} from '../../utils/api/definitions/fields' import MainHandler from '../../utils/api/mainHandler' import { fixedEncodeURIComponent } from '../../utils/web/helpers/utils' import { RootStore } from '../store' @@ -54,11 +58,25 @@ export const Form = types self.fields.remove(field) } }, + sortFields(): void { + self.fields.sort( + ( + a: Instance, + b: Instance + ): number => { + const keyList: string[] = Object.keys(fieldDefinitions) + const indexA: number = keyList.findIndex((value) => value === a.key) + const indexB: number = keyList.findIndex((value) => value === b.key) + return indexA - indexB + } + ) + }, })) .actions((self) => ({ addField(data: SnapshotIn): void { try { self.fields.push({ ...data }) + self.sortFields() } catch (error) { console.log('error occurred while adding field to self.fields', error) } @@ -125,7 +143,6 @@ export const Form = types value: defaultValue ?? null, helpText: helpText ?? null, }) - self.fields.sort(BenefitHandler.sortFields) } // field does exist, update if any data has changed else if (field.label !== fieldData.label) { @@ -140,7 +157,6 @@ export const Form = types }, // used for calling the main benefit processor buildObjectWithFormData(language: Language): { [key: string]: string } { - console.log('buildObjectWithFormData') let input = { _language: language } for (const field of self.fields) { if (!field.value) continue @@ -148,17 +164,24 @@ export const Form = types } return input }, - // used for calling the main benefit processor using the array from the internal state - buildArrayWithFormData(language: Language): [string, string][] { - console.log('buildArrayWithFormData') + // used internally for the UI + buildArrayWithFormData(): [FieldKey, string][] { let input = [] - input.push(['_language', language]) + self.sortFields() for (const field of self.fields) { if (!field.value) continue input.push([field.key, field.sanitizeInput()]) } return input }, + })) + .actions((self) => ({ + // used for calling the main benefit processor using the array from the internal state + buildArrayWithFormDataAndLanguage(language: Language): [string, string][] { + let input: [string, string][] = self.buildArrayWithFormData() + input.push(['_language', language]) + return input + }, // used for API requests, which is currently for the CSV function buildQueryStringWithFormData(): string { const parent = getParent(self) as Instance @@ -173,7 +196,9 @@ export const Form = types .actions((self) => ({ saveInputsToState: flow(function* () { const parent = getParent(self) as Instance - const inputArray = self.buildArrayWithFormData(parent.langBrowser) + const inputArray = self.buildArrayWithFormDataAndLanguage( + parent.langBrowser + ) parent.setInputs(inputArray) parent.saveStoreState() }), diff --git a/client-state/store.ts b/client-state/store.ts index b7f39043e..a83588a50 100644 --- a/client-state/store.ts +++ b/client-state/store.ts @@ -13,6 +13,7 @@ import { EntitlementResultType, EstimationSummaryState, Language, + LinkIcon, LinkLocation, ResultKey, } from '../utils/api/definitions/enums' @@ -25,6 +26,7 @@ export const EligibilityResult = types.model({ }) export const DeferralResult = types.model({ + age: types.maybe(types.number), increase: types.maybe(types.number), years: types.maybe(types.number), }) @@ -37,23 +39,37 @@ export const EntitlementResult = types.model({ deferral: types.maybe(DeferralResult), }) -export const Eligibility = types.model({ - eligibility: types.maybe(EligibilityResult), - entitlement: types.maybe(EntitlementResult), +export const CollapsedText = types.model({ + heading: types.string, + text: types.string, }) -export const OAS = Eligibility.named('OAS') -export const GIS = Eligibility.named('GIS') -export const AFS = Eligibility.named('AFS') -export const Allowance = Eligibility.named('Allowance') - export const SummaryLink = types.model({ url: types.string, text: types.string, order: types.number, location: types.enumeration(Object.values(LinkLocation)), + icon: types.maybe(types.enumeration(Object.values(LinkIcon))), +}) + +export const CardDetail = types.model({ + mainText: types.string, + collapsedText: types.maybe(types.array(CollapsedText)), + links: types.maybe(types.array(SummaryLink)), }) +export const BenefitResult = types.model({ + benefitKey: types.maybe(types.string), + eligibility: types.maybe(EligibilityResult), + entitlement: types.maybe(EntitlementResult), + cardDetail: types.maybe(CardDetail), +}) + +export const OAS = BenefitResult.named('OAS') +export const GIS = BenefitResult.named('GIS') +export const AFS = BenefitResult.named('AFS') +export const Allowance = BenefitResult.named('Allowance') + export const Summary = types .model({ state: types.maybe( @@ -131,6 +147,9 @@ export const RootStore = types console.log('generated input object', input) return input }, + getResultArray() { + return [self.oas, self.gis, self.allowance, self.afs] + }, })) .actions((self) => ({ setActiveTab(num: number) { diff --git a/components/EligibilityPage/index.tsx b/components/EligibilityPage/index.tsx index c10409b32..37b6c2a7b 100644 --- a/components/EligibilityPage/index.tsx +++ b/components/EligibilityPage/index.tsx @@ -176,7 +176,7 @@ export const EligibilityPage: React.VFC = observer(({}) => { type={field.type} name={field.key} label={field.label} - onChange={debounce((e) => handleOnChange(step, field, e), 500)} + onChange={debounce((e) => handleOnChange(step, field, e), 100)} placeholder={field.placeholder ?? ''} value={field.value} helpText={field.helpText} @@ -232,6 +232,7 @@ export const EligibilityPage: React.VFC = observer(({}) => { keyforid={field.key} label={field.label} onChange={(e) => handleOnChange(step, field, e)} + helpText={field.helpText} required /> diff --git a/components/Forms/FormButtons/index.tsx b/components/Forms/FormButtons/index.tsx deleted file mode 100644 index d3d24e404..000000000 --- a/components/Forms/FormButtons/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Button } from '@dts-stn/decd-design-system' -import { Instance } from 'mobx-state-tree' -import { NextRouter, useRouter } from 'next/router' -import { Form } from '../../../client-state/models/Form' -import { RootStore } from '../../../client-state/store' -import { WebTranslations } from '../../../i18n/web' -import { useMediaQuery, useStore, useTranslation } from '../../Hooks' - -export const FormButtons: React.FC<{}> = ({}) => { - const router = useRouter() - const tsln = useTranslation() - const root = useStore() - const form = root.form - const isMobile = useMediaQuery(992) - - return ( -
- {isMobile && ( - - )} -
- ) -} - -const SubmitButton: React.FC<{ - router: NextRouter - form: Instance - root: Instance - label: string -}> = ({ router, form, root, label }) => { - return ( -