diff --git a/.azuredevops/dynamic-branches.yml b/.azuredevops/dynamic-branches.yml new file mode 100644 index 000000000..00abff274 --- /dev/null +++ b/.azuredevops/dynamic-branches.yml @@ -0,0 +1,98 @@ +trigger: + - none + +pr: develop + +variables: + azure.servicePrincipal: '' + webapp.name: '' + webapp.resourceGroup: '' + webapp.slotName: null + azureContainerRegistry.name: '' + azureContainerRegistry.repository: '' + azureContainerRegistry.domain: '' + azureContainerRegistry.tag: '' + System.Debug: false + +steps: + - task: Docker@2 + inputs: + containerRegistry: '$(azureContainerRegistry.name)' + repository: '$(azureContainerRegistry.repository)' + command: 'login' + - script: 'docker pull $(azureContainerRegistry.domain)/$(azureContainerRegistry.repository):latest' + displayName: Pull latest for layer caching + continueOnError: true + + - task: Docker@2 + displayName: 'Build image' + inputs: + containerRegistry: '$(azureContainerRegistry.name)' + repository: '$(azureContainerRegistry.repository)' + command: 'build' + Dockerfile: '**/Dockerfile' + tags: | + $(azureContainerRegistry.tag) + latest + arguments: | + --cache-from $(azureContainerRegistry.domain)/$(azureContainerRegistry.repository):latest + + - task: Docker@2 + displayName: 'Push image' + inputs: + containerRegistry: '$(azureContainerRegistry.name)' + repository: '$(azureContainerRegistry.repository)' + command: 'push' + tags: | + $(azureContainerRegistry.tag) + latest + + - task: PowerShell@2 + displayName: 'Decide which AppService slot to put this preview in' + inputs: + targetType: 'inline' + script: | + [int] $slotNumber = $(System.PullRequest.PullRequestId) % 4 + Write-Host "Generated slot number:" + Write-Host "$slotNumber" + Write-Host "From PRID" + Write-Host "$(System.PullRequest.PullRequestId)" + Write-Host "##vso[task.setvariable variable=webapp.slotName]$slotNumber" + + - task: AzureCLI@2 + displayName: 'Create new slot in App Service' + inputs: + azureSubscription: $(azure.servicePrincipal) + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + az webapp deployment slot create \ + --name $(webapp.name) \ + --resource-group $(webapp.resourceGroup) \ + --slot pr-preview-$(webapp.slotName) \ + --configuration-source $(webapp.name) + az webapp identity assign \ + -g $(webapp.resourceGroup) \ + -n $(webapp.name) \ + --slot pr-preview-$(webapp.slotName) \ + --identities /subscriptions/400c5730-25f5-4ee6-a933-8b289b9ccb0d/resourcegroups/rg-dts-id-shared/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id-SCLabs-Shared + + - task: AzureCLI@2 + displayName: 'Deploy pr image to new slot' + inputs: + azureSubscription: $(azure.servicePrincipal) + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + az webapp config container set \ + --docker-custom-image-name $(azureContainerRegistry.domain)/$(azureContainerRegistry.repository):$(azureContainerRegistry.tag) \ + --name $(webapp.name) \ + --slot pr-preview-$(webapp.slotName) \ + --resource-group $(webapp.resourceGroup) + + - task: GitHubComment@0 + displayName: 'Post a comment with a link to the new PR preview' + inputs: + gitHubConnection: "Adam'sGitHub-9/15/2023" + repositoryName: '$(Build.Repository.Name)' + comment: 'Check out a preview of your pull request here: https://$(webapp.name)-pr-preview-$(webapp.slotName).azurewebsites.net' diff --git a/Dockerfile b/Dockerfile index 94b47ae4b..ea170b4b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -93,4 +93,6 @@ COPY --chown=55:$group public ./public RUN VERSION_NEXT=`node -p -e "require('./package.json').dependencies.next"`&& yarn add next@"$VERSION_NEXT" USER $user +EXPOSE 3000 + CMD [ "yarn", "start" ] \ No newline at end of file diff --git a/__tests__/pages/api/general.test.ts b/__tests__/pages/api/general.test.ts index 623f3fe25..588e0d423 100644 --- a/__tests__/pages/api/general.test.ts +++ b/__tests__/pages/api/general.test.ts @@ -39,11 +39,11 @@ describe('translation checks', () => { describe('country checks', () => { const COUNTRY_COUNT = 196 const handlerEn = new BenefitHandler({ _language: Language.EN }) - handlerEn.requiredFields = [FieldKey.LIVING_COUNTRY] - const fieldDataEn = handlerEn.fieldData as Array + handlerEn.fields.requiredFields = [FieldKey.LIVING_COUNTRY] + const fieldDataEn = handlerEn.fields.fieldData as Array const handlerFr = new BenefitHandler({ _language: Language.FR }) - handlerFr.requiredFields = [FieldKey.LIVING_COUNTRY] - const fieldDataFr = handlerFr.fieldData as Array + handlerFr.fields.requiredFields = [FieldKey.LIVING_COUNTRY] + const fieldDataFr = handlerFr.fields.fieldData as Array it(`produces a list of ${COUNTRY_COUNT} countries (EN and FR)`, async () => { expect(fieldDataEn[0].values.length).toEqual(COUNTRY_COUNT) expect(fieldDataFr[0].values.length).toEqual(COUNTRY_COUNT) diff --git a/__tests__/pages/api/gisCoupleAlwBenefit.test.ts b/__tests__/pages/api/gisCoupleAlwBenefit.test.ts index a309279d2..d8fa7cd46 100644 --- a/__tests__/pages/api/gisCoupleAlwBenefit.test.ts +++ b/__tests__/pages/api/gisCoupleAlwBenefit.test.ts @@ -154,12 +154,12 @@ describe('gisCoupleALWBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.FULL, 1045.11) + expectOasEligible(res, EntitlementResultType.FULL, 768.46) expectGisEligible(res, 241.52) expectAlwTooOld(res) expectAlwsMarital(res) //Future Benefit - expectFutureOasGisBenefitEligible(res, 100, 1045.11, 8.3, 0) + expectFutureOasGisBenefitEligible(res, 100, 768.46, 8.3, 0) //partner results expectOasNotEligible(res, true) @@ -177,12 +177,12 @@ describe('gisCoupleALWBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 857.6) - expectGisEligible(res, 318.37) + expectOasEligible(res, EntitlementResultType.FULL, 768.46) + expectGisEligible(res, 241.52) expectAlwTooOld(res) expectAlwsMarital(res) //Future Benefit - expectFutureOasGisBenefitEligible(res, 94, 857.6, 72.15, 0) + expectFutureOasGisBenefitEligible(res, 94, 768.46, 0, 0) //partner results expectOasNotEligible(res, true) diff --git a/__tests__/pages/api/gisCoupleOnePenBenefit.test.ts b/__tests__/pages/api/gisCoupleOnePenBenefit.test.ts index a4514fbaa..82b391ec4 100644 --- a/__tests__/pages/api/gisCoupleOnePenBenefit.test.ts +++ b/__tests__/pages/api/gisCoupleOnePenBenefit.test.ts @@ -108,17 +108,18 @@ describe('gisCoupleOnePenBenefit', () => { it('should pass 51 test - CALC-51', async () => { const desiredName = 'CALC-51' // Replace with the desired name const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.FULL, 1045.11) + expectOasEligible(res, EntitlementResultType.FULL, 768.46) expectGisEligible(res, 0.82) expectAlwTooOld(res) expectAlwsMarital(res) //Future Benefit - expectFutureOasGisBenefitEligible(res, 82, 1045.11, 0.82, 0) - expectFutureOasGisBenefitEligible(res, 87, 1045.11, 0.0, 1) + expectFutureOasGisBenefitEligible(res, 82, 768.46, 0.82, 0) + expectFutureOasGisBenefitEligible(res, 87, 768.46, 0.0, 1) //partner results expectAllIneligible(res, true) diff --git a/__tests__/pages/api/gisCoupleTwoPensBenefit.test.ts b/__tests__/pages/api/gisCoupleTwoPensBenefit.test.ts index f95989c5a..d6c755b5d 100644 --- a/__tests__/pages/api/gisCoupleTwoPensBenefit.test.ts +++ b/__tests__/pages/api/gisCoupleTwoPensBenefit.test.ts @@ -296,8 +296,8 @@ describe('gisCoupleTwoPensBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 731.57) - expectGisEligible(res, 1066.99) + expectOasEligible(res, EntitlementResultType.PARTIAL, 717.6) + expectGisEligible(res, 1047.78) expectAlwTooOld(res) expectAlwsMarital(res) @@ -314,7 +314,7 @@ describe('gisCoupleTwoPensBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.FULL, 1045.11) + expectOasEligible(res, EntitlementResultType.FULL, 999) expectGisEligible(res, 561.45) expectAlwTooOld(res) expectAlwsMarital(res) @@ -332,7 +332,7 @@ describe('gisCoupleTwoPensBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.FULL, 1045.11) + expectOasEligible(res, EntitlementResultType.FULL, 860.68) expectGisEligible(res, 92.82) expectAlwTooOld(res) expectAlwsMarital(res) @@ -350,7 +350,7 @@ describe('gisCoupleTwoPensBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 857.6) + expectOasEligible(res, EntitlementResultType.FULL, 768.46) expectGisEligible(res, 0.0) expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) expectAlwTooOld(res) diff --git a/__tests__/pages/api/gisSingleBenefit.test.ts b/__tests__/pages/api/gisSingleBenefit.test.ts index f7c3bcbf7..522dd94ea 100644 --- a/__tests__/pages/api/gisSingleBenefit.test.ts +++ b/__tests__/pages/api/gisSingleBenefit.test.ts @@ -192,8 +192,8 @@ describe('gisSingleBenefit', () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 267.89) - expectGisEligible(res, 537.74) + expectOasEligible(res, EntitlementResultType.PARTIAL, 288.18) + expectGisEligible(res, 480.11) expectAlwTooOld(res) expectAlwsMarital(res) }) diff --git a/__tests__/pages/api/july2013Deferral.test.ts b/__tests__/pages/api/july2013Deferral.test.ts new file mode 100644 index 000000000..e90a38223 --- /dev/null +++ b/__tests__/pages/api/july2013Deferral.test.ts @@ -0,0 +1,419 @@ +import { + EntitlementResultType, + ResultReason, +} from '../../../utils/api/definitions/enums' +import { getTransformedPayloadByName } from '../../utils/excelReaderUtil' +import { + expectOasEligible, + expectGisEligible, + expectAlwTooOld, + expectAlwsMarital, + expectAllIneligible, + expectDeferralTable, + expectFutureDeferralTable, + expectFutureOasGisBenefitEligible, + expectFutureAwlBenefitEligible, + expectOasNotEligible, + expectGisNotEligible, + expectAlwAlwsTooOld, +} from '../../utils/expectUtils' + +import { mockGetRequest } from '../../utils/factory' + +//file for extracting test data +const filePath = '__tests__/utils/ScenariosWith2023Q3RatesAndThresholds.xlsx' + +describe('july2013Deferral', () => { + /* CALC-166 */ + it('should pass 166 test - CALC-166', async () => { + const desiredName = 'CALC-166' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.FULL, 768.46) + expectGisEligible(res, 62.3) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 638.34, true) + expectAlwTooOld(res, true) + }) + + /* CALC-167 */ + it('should pass 167 test - CALC-167', async () => { + const desiredName = 'CALC-167' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.02) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 0), true + expectAlwTooOld(res, true) + }) + + /* CALC-168 */ + it('should pass 168 test - CALC-168', async () => { + const desiredName = 'CALC-168' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.NONE, 0) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 174.65, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-169 */ + it('should pass 169 test - CALC-169', async () => { + const desiredName = 'CALC-169' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 403.45) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-170 */ + it('should pass 170 test - CALC-170', async () => { + const desiredName = 'CALC-170' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.02) + expectGisEligible(res, 465.74) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 537.92, true) + expectGisEligible(res, 292.84, true) + expectAlwTooOld(res, true) + }) + + /* CALC-171 */ + it('should pass 171 test - CALC-171', async () => { + const desiredName = 'CALC-171' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 403.45) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 326.6, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-172 */ + it('should pass 172 test - CALC-172', async () => { + const desiredName = 'CALC-172' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 241.69) + expectGisEligible(res, 429.64) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 429.64, true) + expectAlwTooOld(res, true) + }) + + /* CALC-173 */ + it('should pass 173 test - CALC-173', async () => { + const desiredName = 'CALC-173' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 212.6) + expectGisEligible(res, 514.43) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 533.64, true) + expectAlwTooOld(res, true) + }) + + /* CALC-174 */ + it('should pass 174 test - CALC-174', async () => { + const desiredName = 'CALC-174' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 243.99) + expectGisEligible(res, 1204.43) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 1204.43, true) + expectAlwTooOld(res, true) + }) + + /* CALC-175 */ + it('should pass 175 test - CALC-175', async () => { + const desiredName = 'CALC-175' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 326.6) + expectGisEligible(res, 0) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 268.96, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-176 */ + it('should pass 176 test - CALC-176', async () => { + const desiredName = 'CALC-176' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.79) + expectGisEligible(res, 769.8) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 211.33, true) + expectGisEligible(res, 827.43, true) + expectAlwTooOld(res, true) + }) + + /* CALC-177 */ + it('should pass 177 test - CALC-177', async () => { + const desiredName = 'CALC-177' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 403.45) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-178 */ + it('should pass 178 test - CALC-178', async () => { + const desiredName = 'CALC-178' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.02) + expectGisEligible(res, 0) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 307.38, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-179 */ + it('should pass 179 test - CALC-179', async () => { + const desiredName = 'CALC-179' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 226.7) + expectGisEligible(res, 1204.43) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 537.92, true) + expectGisEligible(res, 858.63, true) + expectAlwTooOld(res, true) + }) + + /* CALC-180 */ + it('should pass 180 test - CALC-180', async () => { + const desiredName = 'CALC-180' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 286.14) + expectGisEligible(res, 514.43) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 288.18, true) + expectGisEligible(res, 437.59, true) + expectAlwTooOld(res, true) + }) + + /* CALC-181 */ + it('should pass 181 test - CALC-181', async () => { + const desiredName = 'CALC-181' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.NONE, 0) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.02, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-182 */ + it('should pass 182 test - CALC-182', async () => { + const desiredName = 'CALC-182' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 494.24) + expectGisEligible(res, 465.74) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 268.96, true) + expectGisEligible(res, 561.8, true) + expectAlwTooOld(res, true) + }) + + /* CALC-183 */ + it('should pass 183 test - CALC-183', async () => { + const desiredName = 'CALC-183' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.FULL, 768.46) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.FULL, 768.46, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-184 */ + it('should pass 184 test - CALC-184', async () => { + const desiredName = 'CALC-184' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 365.02) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) + + /* CALC-185 */ + it('should pass 185 test - CALC-185', async () => { + const desiredName = 'CALC-185' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 205.95) + expectGisEligible(res, 742.64) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 192.12, true) + expectGisEligible(res, 742.64, true) + expectAlwTooOld(res, true) + }) + + /* CALC-186 */ + it('should pass 186 test - CALC-186', async () => { + const desiredName = 'CALC-186' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 261.28) + expectGisEligible(res, 846.64) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.PARTIAL, 557.14, true) + expectGisEligible(res, 481.63, true) + expectAlwTooOld(res, true) + }) + + /* CALC-187 */ + it('should pass 187 test - CALC-187', async () => { + const desiredName = 'CALC-187' + const extractedPayload = getTransformedPayloadByName(filePath, desiredName) + const res = await mockGetRequest(extractedPayload) + + //client results + expectOasEligible(res, EntitlementResultType.PARTIAL, 403.45) + expectGisEligible(res, 0) + expectAlwTooOld(res) + expectAlwsMarital(res) + + //partner results + expectOasEligible(res, EntitlementResultType.FULL, 768.46, true) + expectGisEligible(res, 0, true) + expectAlwTooOld(res, true) + }) +}) diff --git a/__tests__/pages/api/oasBenefit.test.ts b/__tests__/pages/api/oasBenefit.test.ts index 3ea0025db..d2154702b 100644 --- a/__tests__/pages/api/oasBenefit.test.ts +++ b/__tests__/pages/api/oasBenefit.test.ts @@ -76,8 +76,8 @@ it('should pass the second test - OAS-CALC-02', async () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 853.45) - expectGisEligible(res, 243.15) + expectOasEligible(res, EntitlementResultType.FULL, 768.46) + expectGisEligible(res, 166.3) expectAlwTooOld(res) expectAlwsMarital(res) @@ -126,7 +126,7 @@ it('should pass the second test - OAS-CALC-02', async () => { const res = await mockGetRequest(extractedPayload) //client results - expectOasEligible(res, EntitlementResultType.PARTIAL, 391.92) + expectOasEligible(res, EntitlementResultType.PARTIAL, 384.23) expectGisEligible(res) expect(res.body.results.gis.eligibility.reason).toEqual(ResultReason.INCOME) expectAlwTooOld(res) diff --git a/__tests__/utils/ScenariosWith2023Q3RatesAndThresholds.xlsx b/__tests__/utils/ScenariosWith2023Q3RatesAndThresholds.xlsx index 290fb27d7..0f5cfdedd 100644 Binary files a/__tests__/utils/ScenariosWith2023Q3RatesAndThresholds.xlsx and b/__tests__/utils/ScenariosWith2023Q3RatesAndThresholds.xlsx differ diff --git a/__tests__/utils/excelReaderUtil.test.ts b/__tests__/utils/excelReaderUtil.test.ts index 2fd7b0de6..0480c2af6 100644 --- a/__tests__/utils/excelReaderUtil.test.ts +++ b/__tests__/utils/excelReaderUtil.test.ts @@ -8,7 +8,7 @@ describe('Excel Reader Utility Tests', () => { const extractedPayload = getTransformedPayloadByName(filePath, desiredName) if (extractedPayload) { - console.log('Extracted Payload:', extractedPayload) + // console.log('Extracted Payload:', extractedPayload) // Add your assertions here //expect(extractedPayload.length).toBeGreaterThan(0) //expect(jsonPayload.length).toBeGreaterThan(0) diff --git a/__tests__/utils/excelReaderUtil.ts b/__tests__/utils/excelReaderUtil.ts index c6a0af3f7..37bc2223e 100644 --- a/__tests__/utils/excelReaderUtil.ts +++ b/__tests__/utils/excelReaderUtil.ts @@ -1,4 +1,3 @@ -import { calculateAge } from '../../utils/api/helpers/utils' import * as XLSX from 'xlsx' import { LegalStatus, @@ -6,6 +5,7 @@ import { MaritalStatus, PartnerBenefitStatus, } from '../../utils/api/definitions/enums' +import { calculateFutureYearMonth } from '../../utils/api/helpers/utils' export function getTransformedPayloadByName( filePath: string, @@ -35,12 +35,8 @@ function readExcelData(filePath: string): string[] { function createTransformedPayload(rowToTransform: string): Record { let payload: Record = { income: roundedIncome(rowToTransform["User's Net Worldwide Income"]), - age: rowToTransform['Age '].toString().includes(';') - ? calculateAge( - extractValue(rowToTransform['Age '], 1), - extractValue(rowToTransform['Age '], 0) - ) - : rowToTransform['Age '], + age: rowToTransform['Age'], + clientBirthDate: rowToTransform['Birth Year and Month'], receiveOAS: transformValue(rowToTransform["Rec'ing OAS (Yes / No)"]), oasDeferDuration: rowToTransform['Delay (# of Years and Months)'] === 'N/A' @@ -53,11 +49,11 @@ function createTransformedPayload(rowToTransform: string): Record { //oasDefer: false, // no longer used. //oasAge: 0, maritalStatus: transformMaritalStatusValue( - rowToTransform['Marital Status\r\n(With or Without Partner, Widowed)'] + rowToTransform['Marital Status (With or Without Partner, Widowed)'] ), invSeparated: transformValue(rowToTransform['Inv Sep (Yes / No)']), - livingCountry: transformLivingContryValue( - rowToTransform['Country of Residence\r\n(Canada, Not Canada)'] + livingCountry: transformLivingCountryValue( + rowToTransform['Country of Residence (Canada, Not Canada)'] ), // country code legalStatus: transformLegalStatusValue( rowToTransform['Legal Status (Yes / No)'] @@ -77,9 +73,11 @@ function createTransformedPayload(rowToTransform: string): Record { 'false' || transformValue(rowToTransform["Rec'ing OAS (Yes / No)"]) === undefined ? transformYearsInCanadaSinceOAS18Value( + rowToTransform['Age'], rowToTransform[ '# of years resided in Canada after age 18 (Full, 40, 10, etc.)' - ] + ], + rowToTransform['Birth Year and Month'] ) : undefined : undefined, @@ -91,9 +89,11 @@ function createTransformedPayload(rowToTransform: string): Record { ) !== 'true' ? transformValue(rowToTransform["Rec'ing OAS (Yes / No)"]) === 'true' ? transformYearsInCanadaSinceOAS18Value( + rowToTransform['Age'], rowToTransform[ '# of years resided in Canada after age 18 (Full, 40, 10, etc.)' - ] + ], + rowToTransform['Birth Year and Month'] ) : undefined : undefined, @@ -107,10 +107,15 @@ function createTransformedPayload(rowToTransform: string): Record { ? undefined : rowToTransform["Partner's Net Worldwide Income"], // partner income partnerAge: - rowToTransform["Partner's Age (Years and months)"] === 'N/A' + rowToTransform['Partner Age'] === 'N/A' ? undefined - : rowToTransform["Partner's Age (Years and months)"], - partnerLivingCountry: transformLivingContryValue( + : rowToTransform['Partner Age'], + partnerBirthDate: rowToTransform['Partner Birth Year and Month'] + .toString() + .includes(';') + ? rowToTransform['Partner Birth Year and Month'] + : undefined, + partnerLivingCountry: transformLivingCountryValue( rowToTransform["Partner's Country of Residence (Canada, Not Canada)"] ), // country code partnerLegalStatus: transformLegalStatusValue( @@ -122,9 +127,11 @@ function createTransformedPayload(rowToTransform: string): Record { ] ), partnerYearsInCanadaSince18: transformYearsInCanadaSinceOAS18Value( + rowToTransform['Partner Age'], rowToTransform[ 'Partner: # of years resided in Canada after age 18 (Full, 40, 10, etc.)' - ] + ], + rowToTransform['Partner Birth Year and Month'] ), } payload = Object.fromEntries( @@ -133,7 +140,6 @@ function createTransformedPayload(rowToTransform: string): Record { ) ) - //console.log('payload:', payload) return payload } @@ -147,7 +153,7 @@ function transformValue(value: string): string | undefined { return undefined } -function transformLivingContryValue(value: string): string | undefined { +function transformLivingCountryValue(value: string): string | undefined { if (value.toString().toUpperCase() === 'CANADA') { return LivingCountry.CANADA } else if (value.toString().toUpperCase() === 'NOT CANADA') { @@ -158,15 +164,19 @@ function transformLivingContryValue(value: string): string | undefined { } function transformYearsInCanadaSinceOAS18Value( - value: string, + age: number, + value: number, + birthDate: string, partner?: boolean ): string | undefined { if (value.toString().toUpperCase() === 'FULL') { return undefined } else if (value.toString().toUpperCase() === 'N/A') { return undefined + } else if (value.toString().toLowerCase().includes('s')) { + return String(value).split('s')[1] } - return String(value) // Number(value) + return String(value) } function transformLegalStatusValue(value: string): string | undefined { diff --git a/client-state/Form.ts b/client-state/Form.ts index 01f035a5d..afa2f606b 100644 --- a/client-state/Form.ts +++ b/client-state/Form.ts @@ -1,6 +1,7 @@ import Joi from 'joi' import { getWebTranslations, WebTranslations } from '../i18n/web' import { BenefitHandler } from '../utils/api/benefitHandler' +import { FieldsHandler } from '../utils/api/fieldsHandler' import { Language, ValidationErrors } from '../utils/api/definitions/enums' import { FieldConfig, FieldKey } from '../utils/api/definitions/fields' import { VisibleFieldsObject } from '../utils/web/types' @@ -17,7 +18,7 @@ export class Form { inputHelper: InputHelper, visibleFieldsObject: VisibleFieldsObject ) { - this.allFieldConfigs = BenefitHandler.getAllFieldData(language) + this.allFieldConfigs = FieldsHandler.getAllFieldData(language) this.fields = this.allFieldConfigs.map((config) => { return new FormField(config, inputHelper, visibleFieldsObject) }) @@ -58,7 +59,7 @@ export class Form { try { const handler = new BenefitHandler({ _language: this.language }) let text = tsln.validationErrors[errorKeyOrText] // throws error when error not handled/defined in ValidationErrors - text = handler.replaceTextVariables(text) + text = handler.fields.replaceTextVariables(handler, text) allErrorsParsed[fieldKey] = { text, successful: true } } catch { let successfulErrorExists = allErrorsParsed[fieldKey] !== undefined diff --git a/client-state/InputHelper.ts b/client-state/InputHelper.ts index a3d170875..9395b3dde 100644 --- a/client-state/InputHelper.ts +++ b/client-state/InputHelper.ts @@ -69,7 +69,10 @@ export class InputHelper { } get asObjectWithLanguage(): { [x in FieldKeyOrLanguage]?: string } { - return { ...this.asObject, _language: this.language } + return { + ...this.asObject, + _language: this.language, + } } static sanitizeValue(value: string, language: string): string { diff --git a/components/Forms/Accordion.tsx b/components/Forms/Accordion.tsx new file mode 100644 index 000000000..449c6f3e1 --- /dev/null +++ b/components/Forms/Accordion.tsx @@ -0,0 +1,29 @@ +/* eslint-disable @next/next/no-img-element */ +import React from 'react' + +interface AccordionProps { + title: React.ReactNode + children: React.ReactNode + isOpen: boolean + onClick: React.MouseEventHandler +} + +export const Accordion: React.FC = ({ + title, + children, + isOpen, + onClick, +}) => { + return ( +
+ + {isOpen &&
{children}
} +
+ ) +} diff --git a/components/Forms/Duration.tsx b/components/Forms/Duration.tsx index f7d1d6abb..f9546856d 100644 --- a/components/Forms/Duration.tsx +++ b/components/Forms/Duration.tsx @@ -27,26 +27,71 @@ const Duration: FC = ({ }) => { const tsln = useTranslation() const [durationInput, setDurationInput] = useState(null) + const [resideny, setResidency] = useState(null) // TODO: if residency is known, we need to base drop down year/month on age of eligibility, not just age in July 2013. For now assume minimum required 10 years - const diff = Number(age) <= 70 ? Number(age) - 65 : 5 - const maxYears = Math.floor(diff) + const calculate2013Age = (ageDateObj) => { + const { month, year } = ageDateObj - // Returns num of months for select option - const getMaxMonths = (age) => { - const birthMonth = ageDate.month - const today = new Date() - const month = today.getMonth() + 1 + let yearsDifference = 2013 - year + let monthsDifference = 7 - month + + if (monthsDifference < 0) { + yearsDifference -= 1 + monthsDifference += 12 + } + + const age = yearsDifference + monthsDifference / 12 + return parseFloat(age.toFixed(2)) + } + + const getMaxYears = (ageJ2013) => { + let years + if (ageJ2013 < 65) { + const diff = Number(age) <= 70 ? Number(age) - 65 : 5 + years = Math.floor(diff) + } else if (ageJ2013 >= 70) { + years = 0 + } else { + // between ages 65 and 70 in July 2013 + years = Math.floor(70 - ageJ2013) + } - let monthsDiff = month - birthMonth - if (monthsDiff < 0) monthsDiff += 12 + return years + } + + const ageJuly2013 = calculate2013Age(ageDate) + const maxYears = getMaxYears(ageJuly2013) + + // Returns num of months for select option + const getMaxMonths = () => { + let months + if (ageJuly2013 < 65) { + const birthMonth = ageDate.month + const today = new Date() + const month = today.getMonth() + 1 + + let monthsDiff = month - birthMonth + if (monthsDiff < 0) monthsDiff += 12 + months = monthsDiff + } else if (ageJuly2013 >= 70) { + months = 0 + } else { + months = Math.round((Math.ceil(ageJuly2013) - ageJuly2013) * 12) + } - return age < 70 ? monthsDiff : 0 + return months } - // Dynamically populate select options. Return object that represents years and months away from age 65 but upto 70 const getSelectOptions = (maxMonths = 11) => { + let years = maxYears + let months = maxMonths + if (ageJuly2013 >= 70) { + years = 0 + months = 0 + } + if (durationInput?.years === maxYears) { - const maxMonths = getMaxMonths(age) + const maxMonths = getMaxMonths() if (durationInput?.months > maxMonths) { const newDuration = { ...durationInput, months: 0 } setDurationInput(newDuration) @@ -54,7 +99,7 @@ const Duration: FC = ({ } } - return { years: maxYears, months: maxMonths } + return { years, months } } const [selectOptions, setSelectOptions] = useState(getSelectOptions()) @@ -70,7 +115,7 @@ const Duration: FC = ({ useEffect(() => { setSelectOptions(getSelectOptions()) if (durationInput?.years === maxYears) { - const maxMonths = getMaxMonths(age) + const maxMonths = getMaxMonths() setSelectOptions(getSelectOptions(maxMonths)) if (durationInput?.months > maxMonths) { setDurationInput({ ...durationInput, months: 0 }) diff --git a/components/Layout/Header.tsx b/components/Layout/Header.tsx index 3376a2c30..7fe1f01c6 100644 --- a/components/Layout/Header.tsx +++ b/components/Layout/Header.tsx @@ -7,8 +7,16 @@ interface HeaderProps { id: string locale: string langUrl: string + topNavProps: { + skipToMain: string + skipToMainPath: string + skipToAbout: string + skipToAboutPath: string + switchToBasic: string + switchToBasicPath: string + displayAlternateLink: boolean + } headerText: { - skipToMainContent: string globalHeader: string testSiteNotice: string officialSiteNavigation: string @@ -22,6 +30,7 @@ export function Header({ id, locale, langUrl, + topNavProps, headerText, breadcrumbItems = [], }: HeaderProps) { @@ -31,16 +40,45 @@ export function Header({ return ( <> -