From ae59d66b96dc6cb672ea260338a75c69f9b2c2d2 Mon Sep 17 00:00:00 2001 From: Leah Schumann Date: Wed, 5 Oct 2022 15:26:57 -0400 Subject: [PATCH 01/27] Made 'url' property a function of applicationAbbreviation --- src/constants/application-config.js | 1 + src/constants/endpoints.js | 12 ++++++------ src/store/index.js | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/constants/application-config.js b/src/constants/application-config.js index f42a2c183..0e185cff4 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -7,6 +7,7 @@ const applicationConfig = { COOKIE_PATH: "/", CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" APPLICATION_NAME: "FixMyGlass", + APPLICATION_ABBREVIATION: "fmg", SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass" }; diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index d0e05919b..7545f38b0 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,10 +1,14 @@ const endpoints = { GetRouteInfo: { - url: "/content/api/v1/content/RouteInfo", + url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, method: "POST", }, GetHomepageInfo: { - url: "/content/api/v1/content/HomepageInfo", + url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + method: "GET", + }, + GetPageData: { + url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, method: "GET", }, GetVehicleYears: { @@ -31,10 +35,6 @@ const endpoints = { url: "/parts/api/v1/parts/damage-options", method: "GET", }, - GetPageData: { - url: "/content/api/v1/content", - method: "GET", - }, LookupVehicleByYmms: { url: "/vehicle/api/v1/vehicle/Lookup", method: "GET", diff --git a/src/store/index.js b/src/store/index.js index 95dd63ef7..233a57d37 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -538,7 +538,7 @@ export const actions = { getRouteInfo(context, { pageName }) { return globalMethods.callHttpClient({ method: endpoints.GetRouteInfo.method, - endpoint: endpoints.GetRouteInfo.url, + endpoint: endpoints.GetRouteInfo.url(applicationConfig.APPLICATION_ABBREVIATION), payload: { pageName: pageName, }, @@ -547,13 +547,13 @@ export const actions = { getHomepageName(context) { return globalMethods.callHttpClient({ method: endpoints.GetHomepageInfo.method, - endpoint: endpoints.GetHomepageInfo.url, + endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION), }); }, getPageData(context, { pageName }) { return globalMethods.callHttpClient({ method: endpoints.GetPageData.method, - endpoint: `${endpoints.GetPageData.url}/${pageName}`, + endpoint: endpoints.GetPageData.url(applicationConfig.APPLICATION_ABBREVIATION, pageName), payload: {}, }); }, From 2715f524e900ecb74a8aff576d838d1482378beb Mon Sep 17 00:00:00 2001 From: FrankRua Date: Tue, 25 Oct 2022 14:21:42 -0400 Subject: [PATCH 02/27] Deploy to both buckets --- azure-pipelines.yml | 283 ++++++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 139 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 207c013be..5d37f238c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,6 +1,6 @@ trigger: branches: - include: [ develop, release/* ] + include: [develop, release/*] paths: exclude: - deployment/* @@ -8,7 +8,7 @@ trigger: - "*" pr: branches: - include: [ '*' ] + include: ["*"] paths: exclude: - deployment/* @@ -35,144 +35,149 @@ variables: stages: # PR's - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - - stage: TestPr - displayName: Run Unit Tests For PullRequest - jobs: - - template: templates/digital/vue-jest-run-unit-tests.yml@AzureDevOps - parameters: - nodeContainer: node - npmLocation: $(Build.SourcesDirectory) - testResultsFile: junit.xml - summaryFileLocation: $(Build.SourcesDirectory)/coverage/cobertura-coverage.xml + - stage: TestPr + displayName: Run Unit Tests For PullRequest + jobs: + - template: templates/digital/vue-jest-run-unit-tests.yml@AzureDevOps + parameters: + nodeContainer: node + npmLocation: $(Build.SourcesDirectory) + testResultsFile: junit.xml + summaryFileLocation: $(Build.SourcesDirectory)/coverage/cobertura-coverage.xml + - # Dev Build/Deploy - ${{ else }}: - - stage: Dev - condition: eq(variables['Build.SourceBranch'], variables['dev-branch'] ) - variables: - - group: FixMyGlassDev - jobs: - - deployment: devBuildDeployment - displayName: Build and Deploy FMG - Dev - environment: digitalCloud-dev - container: node - workspace: - clean: all - strategy: - runOnce: - deploy: - steps: - - checkout: self - clean: true - - template: templates/digital/step-build-vue.yml@AzureDevOps - parameters: - buildOutputDir: dist - environment: Dev - - template: templates/digital/step-deploy-vue.yml@AzureDevOps - parameters: - artifactName: vueDistDev - awsProfile: $(devDeploymentProfile) - outputPath: /fmg/ - deployBuckets: - safelite-dev-fmg-us-east-1: - clearFolder: true - deployFolder: '' - region: us-east-1 - appDeployVariables: - __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) - __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) - __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) - __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) - indexDeployVariables: - __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) - __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) - cfDistributionId: $(cfDistributionId) + # Dev Build/Deploy + - stage: Dev + condition: eq(variables['Build.SourceBranch'], variables['dev-branch'] ) + variables: + - group: FixMyGlassDev + jobs: + - deployment: devBuildDeployment + displayName: Build and Deploy FMG - Dev + environment: digitalCloud-dev + container: node + workspace: + clean: all + strategy: + runOnce: + deploy: + steps: + - checkout: self + clean: true + - template: templates/digital/step-build-vue.yml@AzureDevOps + parameters: + buildOutputDir: dist + environment: Dev + - template: templates/digital/step-deploy-vue.yml@AzureDevOps + parameters: + artifactName: vueDistDev + awsProfile: $(devDeploymentProfile) + outputPath: /fmg/ + deployBuckets: + safelite-dev-fmg-us-east-1: + clearFolder: true + deployFolder: "" + region: us-east-1 + safelite-dev-fmg-us-east-2: + clearFolder: true + deployFolder: "" + region: us-east-2 + appDeployVariables: + __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) + __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) + __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) + indexDeployVariables: + __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) + __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) + cfDistributionId: $(cfDistributionId) + # QA Build/Deploy + - stage: Qa + condition: eq(variables['Build.SourceBranch'], variables['qa-branch'] ) + variables: + - group: FixMyGlassQa + jobs: + - deployment: qaBuildDeployment + displayName: Build and Deploy FMG - QA + environment: NoApproval-All + container: node + workspace: + clean: all + strategy: + runOnce: + deploy: + steps: + - checkout: self + clean: true + - template: templates/digital/step-build-vue.yml@AzureDevOps + parameters: + buildOutputDir: dist + environment: Qa + - template: templates/digital/step-deploy-vue.yml@AzureDevOps + parameters: + artifactName: vueDistQa + awsProfile: $(qaDeploymentProfile) + outputPath: /fmg/ + deployBuckets: + safelite-qa-fmg-us-east-1: + clearFolder: true + deployFolder: "" + region: us-east-1 + appDeployVariables: + __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) + __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) + __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) + indexDeployVariables: + __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) + __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) + cfDistributionId: $(cfDistributionId) - # QA Build/Deploy - - stage: Qa - condition: eq(variables['Build.SourceBranch'], variables['qa-branch'] ) - variables: - - group: FixMyGlassQa - jobs: - - deployment: qaBuildDeployment - displayName: Build and Deploy FMG - QA - environment: NoApproval-All - container: node - workspace: - clean: all - strategy: - runOnce: - deploy: - steps: - - checkout: self - clean: true - - template: templates/digital/step-build-vue.yml@AzureDevOps - parameters: - buildOutputDir: dist - environment: Qa - - template: templates/digital/step-deploy-vue.yml@AzureDevOps - parameters: - artifactName: vueDistQa - awsProfile: $(qaDeploymentProfile) - outputPath: /fmg/ - deployBuckets: - safelite-qa-fmg-us-east-1: - clearFolder: true - deployFolder: '' - region: us-east-1 - appDeployVariables: - __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) - __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) - __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) - __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) - indexDeployVariables: - __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) - __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) - cfDistributionId: $(cfDistributionId) - - # Prod Build/Deploy - - stage: Prod - condition: succeeded('Qa') - variables: - - group: FixMyGlassProd - jobs: - - deployment: prodBuildDeployment - displayName: Build and Deploy FMG - Prod - environment: digitalCloud-prod - container: node - workspace: - clean: all - strategy: - runOnce: - deploy: - steps: - - checkout: self - clean: true - - template: templates/digital/step-build-vue.yml@AzureDevOps - parameters: - buildOutputDir: dist - environment: Prod - - template: templates/digital/step-deploy-vue.yml@AzureDevOps - parameters: - artifactName: vueDistProd - awsProfile: $(prodDeploymentProfile) - outputPath: /fmg/ - deployBuckets: - safelite-prod-fmg-us-east-1: - clearFolder: true - deployFolder: '' - region: us-east-1 - appDeployVariables: - __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) - __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) - __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) - __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) - indexDeployVariables: - __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) - __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) - cfDistributionId: $(cfDistributionId) - - template: templates/digital/auto-tag.yml@AzureDevOps - parameters: - userName: SafeliteAzureDevops - userEmail: githubazuredevops@safelite.com \ No newline at end of file + # Prod Build/Deploy + - stage: Prod + condition: succeeded('Qa') + variables: + - group: FixMyGlassProd + jobs: + - deployment: prodBuildDeployment + displayName: Build and Deploy FMG - Prod + environment: digitalCloud-prod + container: node + workspace: + clean: all + strategy: + runOnce: + deploy: + steps: + - checkout: self + clean: true + - template: templates/digital/step-build-vue.yml@AzureDevOps + parameters: + buildOutputDir: dist + environment: Prod + - template: templates/digital/step-deploy-vue.yml@AzureDevOps + parameters: + artifactName: vueDistProd + awsProfile: $(prodDeploymentProfile) + outputPath: /fmg/ + deployBuckets: + safelite-prod-fmg-us-east-1: + clearFolder: true + deployFolder: "" + region: us-east-1 + appDeployVariables: + __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) + __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__) + __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) + indexDeployVariables: + __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) + __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) + cfDistributionId: $(cfDistributionId) + - template: templates/digital/auto-tag.yml@AzureDevOps + parameters: + dependsOn: prodBuildDeployment + userName: SafeliteAzureDevops + userEmail: githubazuredevops@safelite.com From 0bc01b92e52f37a1406c305641a5ffdd2bc6a922 Mon Sep 17 00:00:00 2001 From: FrankRua Date: Thu, 20 Oct 2022 10:35:52 -0400 Subject: [PATCH 03/27] Test branch --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d37f238c..989217f02 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,7 +49,7 @@ stages: - ${{ else }}: # Dev Build/Deploy - stage: Dev - condition: eq(variables['Build.SourceBranch'], variables['dev-branch'] ) + condition: eq(variables['Build.SourceBranch'], variables['test-branch'] ) variables: - group: FixMyGlassDev jobs: From 1ff0fe323b20855596442de4ac79bc8f74dbd302 Mon Sep 17 00:00:00 2001 From: FrankRua Date: Thu, 20 Oct 2022 10:43:31 -0400 Subject: [PATCH 04/27] switch back to dev branch --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 989217f02..5d37f238c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,7 +49,7 @@ stages: - ${{ else }}: # Dev Build/Deploy - stage: Dev - condition: eq(variables['Build.SourceBranch'], variables['test-branch'] ) + condition: eq(variables['Build.SourceBranch'], variables['dev-branch'] ) variables: - group: FixMyGlassDev jobs: From 72ae029c20349960fd8f90692a1ef377b098fb3d Mon Sep 17 00:00:00 2001 From: FrankRua Date: Tue, 25 Oct 2022 13:32:06 -0400 Subject: [PATCH 05/27] multi-region support --- azure-pipelines.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d37f238c..002f5192e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -125,6 +125,10 @@ stages: clearFolder: true deployFolder: "" region: us-east-1 + safelite-qa-fmg-us-east-2: + clearFolder: true + deployFolder: "" + region: us-east-2 appDeployVariables: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) @@ -167,6 +171,10 @@ stages: clearFolder: true deployFolder: "" region: us-east-1 + safelite-prod-fmg-us-east-2: + clearFolder: true + deployFolder: "" + region: us-east-2 appDeployVariables: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) From 6f4b961313cc55c5ae5cbdbc46f8d47a4a1185a8 Mon Sep 17 00:00:00 2001 From: FrankRua Date: Tue, 25 Oct 2022 14:24:34 -0400 Subject: [PATCH 06/27] config change --- azure-pipelines.yml | 2 +- vue.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 002f5192e..c06ae5c43 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -26,7 +26,7 @@ resources: type: github name: Safelite/AzureDevOps endpoint: Safelite - ref: refs/tags/t5.5.19 + ref: refs/tags/t5.5.31 variables: - group: Digital-Infrastructure diff --git a/vue.config.js b/vue.config.js index 6ddcd54de..64c83dd9e 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,5 +1,5 @@ process.env.VUE_APP_CONSUMER_CF_DISTRO = - "https://consumerapidev.safelite.com"; + "https://digitalapi.dev.safelite.io"; process.env.VUE_APP_HERITAGE_FUNNEL = "http://localhost:38000/default.aspx"; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = From 610031f3244232acf46c031ada8efd6c619eb4e2 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 25 Oct 2022 14:52:40 -0400 Subject: [PATCH 07/27] CSR-749 save-session additional data --- src/layouts/estimate/estimate.vue | 1 - src/store/index.js | 99 ++++++++++++++++++------------- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index faf2c8ed6..968b3c775 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -186,7 +186,6 @@ export default { async forwardButtonAction() { if (this.isRepair){ const zipCodeData = await this.getZipCodeData(this.serviceZipCode); - //todo: validation await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false); await this.dispatchStoreAction(storeActions.SAVE_SERVICE_LOCATION, { zipCode: this.serviceZipCode, diff --git a/src/store/index.js b/src/store/index.js index 250971bd9..0b50b0fdc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -805,48 +805,65 @@ export const actions = { method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, payload: { - vehicle: { - carId: vehicle.carId, - year: vehicle.year, - make: vehicle.make, - model: vehicle.model, - style: vehicle.style, - vin: vehicle.vin, - registration: { - firstName: vehicle.registration.firstName, - lastName: vehicle.registration.lastName, - streetAddress: vehicle.registration.address, - city: vehicle.registration.city, - state: vehicle.registration.state, - zipCode: vehicle.registration.zipCode, - licensePlateNumber: vehicle.registration.licensePlate, + applicationUser: { + crmCustomerId: applicationUser.crmCustomerId, + experiments: applicationUser.experiments, + lastPage: applicationUser.lastPageVisited, + pageData: applicationUser.pageData, + savedSessionId: applicationUser.savedSessionId, + }, + order: { + vehicle: { + carId: vehicle.carId, + year: vehicle.year, + make: vehicle.make, + model: vehicle.model, + style: vehicle.style, + vin: vehicle.vin, + registration: { + firstName: vehicle.registration.firstName, + lastName: vehicle.registration.lastName, + streetAddress: vehicle.registration.address, + city: vehicle.registration.city, + state: vehicle.registration.state, + zipCode: vehicle.registration.zipCode, + licensePlateNumber: vehicle.registration.licensePlate, + }, }, - }, - damage: { - numberOfChips: damage.numberOfChips, - glassToReplace: damage.glassToReplace, - isRepair: damage.isRepair - }, - customer: { - emailAddress: order.customer.emailAddress, - }, - lineItems: { - glassParts: lineItems.glassParts - }, - serviceLocation: { - streetAddress: order.serviceLocation.address, - city: order.serviceLocation.city, - state: order.serviceLocation.state, - zipCode: order.serviceLocation.zipCode - }, - referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place - referralDate: order.referralDate, - accountNumber: order.accountNumber?.toString(), - existingPromoCode: null, - lastPage: applicationUser.lastPageVisited, - crmCustomerId: applicationUser.crmCustomerId, - savedSessionId: applicationUser.savedSessionId, - experiments: applicationUser.experiments, + customer: { + emailAddress: order.customer.emailAddress, + }, + damage: { + numberOfChips: damage.numberOfChips, + glassToReplace: damage.glassToReplace, + isRepair: damage.isRepair, + partQuestionAnswers: order.damage.partQuestionAnswers, + moldingQuestionAnswers: order.damage.moldingQuestionAnswers, + capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers + }, + lineItems: { + glassParts: lineItems.glassParts + }, + payment: { + InsuranceCoverage: { + isVerified: order.payment.insuranceCoverage.isVerified ?? false + }, + isInsurance: order.payment.isInsurance ?? false + }, + accountNumber: order.accountNumber?.toString(), + providerNumber: "", + serviceLocation: { + streetAddress: order.serviceLocation.address, + city: order.serviceLocation.city, + state: order.serviceLocation.state, + zipCode: order.serviceLocation.zipCode + }, + existingPromoCode: null, + referralCorrelationId: order.referralCorrelationId, + referralDate: order.referralDate, + referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place + referralSequenceNumber: order.referralNumber?.toString(), // TODO Pass the referralSequence number once insurance flow creates it + } }, }); }, From 3a674d64dc4c436f54676e5a71a9086aba357714 Mon Sep 17 00:00:00 2001 From: CarlNation Date: Tue, 25 Oct 2022 16:03:38 -0400 Subject: [PATCH 08/27] Fix broken test --- src/store/index.js | 6 +++--- src/store/store.spec.js | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0b50b0fdc..5951a7cb8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -834,9 +834,9 @@ export const actions = { emailAddress: order.customer.emailAddress, }, damage: { - numberOfChips: damage.numberOfChips, - glassToReplace: damage.glassToReplace, - isRepair: damage.isRepair, + numberOfChips: order.damage.numberOfChips, + glassToReplace: order.damage.glassToReplace, + isRepair: order.damage.isRepair, partQuestionAnswers: order.damage.partQuestionAnswers, moldingQuestionAnswers: order.damage.moldingQuestionAnswers, capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 6ad366989..5bf50348b 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -603,7 +603,14 @@ describe("Actions", () => { vehicle: { registration: {} }, - damage: {}, + order:{ + damage: { + numberOfChips: "2", + partQuestionAnswers: {}, + moldingQuestionAnswers: {}, + capabilityQuestionAnswers: {} + } + }, applicationUser: { lastPageVisited: "test-page", crmCustomerId: "xxx-xxx-xxx", @@ -612,6 +619,18 @@ describe("Actions", () => { }; context.state = { order: { + damage: { + numberOfChips: "2", + partQuestionAnswers: {}, + moldingQuestionAnswers: {}, + capabilityQuestionAnswers: {} + }, + payment: { + insuranceCoverage: { + isVerified: false + }, + isInsurance: false + }, serviceLocation: {}, customer: {}, lineItems: {} From b63f77a7fcfc438b668722349540b2219ef685b2 Mon Sep 17 00:00:00 2001 From: Katie Date: Thu, 27 Oct 2022 15:23:48 -0400 Subject: [PATCH 09/27] CSR-869 Reset alerts when continue is clicked, add test --- src/helpers/unit-test-helper.js | 1 + src/layouts/vin-lookup/vin-lookup.spec.js | 121 +++++++++++++--------- src/layouts/vin-lookup/vin-lookup.vue | 8 ++ 3 files changed, 83 insertions(+), 47 deletions(-) diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index cc00e49d9..48c154d64 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -84,6 +84,7 @@ export const cookies = { "skey": "12345" }; +// Removes test cookies for testing cookie-helper and order-helper export function removeAllTestCookies() { Object.keys(cookies).forEach(key => { document.cookie = `${key}=;Max-Age=0;`; diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index 246b442b0..96dc1603b 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -12,24 +12,24 @@ jest.mock("@/store", () => ({ getters: { vehicle: { year: 2019, - carId: 'C00000' + carId: "C00000", }, order: { serviceLocation: { - zipCode: "45253" + zipCode: "45253", }, customer: { - emailAddress: "builddigitaltest@safelite.com" - } + emailAddress: "builddigitaltest@safelite.com", + }, }, payment: { insuranceCoverage: { - isVerified: true - } + isVerified: true, + }, }, damage: { - glassToReplace: "windshield" - } + glassToReplace: "windshield", + }, }, })); @@ -38,7 +38,6 @@ jest.mock("@/helpers/layout-helper.js", () => ({ settleAllPromises: jest.fn(), })); - jest.mock("@/helpers/damage-helper", () => ({ isGlassAvailableForCarId: jest.fn(() => { return Promise.resolve(); @@ -47,7 +46,6 @@ jest.mock("@/helpers/damage-helper", () => ({ getDamageString: jest.fn(), })); - describe("vin-lookup.vue", () => { it("Should update the funnel-footer forward button when VIN is changed", (done) => { //Arrange @@ -59,7 +57,6 @@ describe("vin-lookup.vue", () => { expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled(); done(); }); - }); it("Should call navigateForward() if the store carId matches the vin response carId and forward button is clicked", async () => { @@ -68,7 +65,7 @@ describe("vin-lookup.vue", () => { mockOutPromises({ carId: "C00000" }); wrapper.vm.navigateForward = jest.fn(); - // Act + // Act await wrapper.vm.forwardButtonAction(); //Assert @@ -78,14 +75,14 @@ describe("vin-lookup.vue", () => { it("Should not call navigateForward() if the store carId does not match the vin response carId and forward button is clicked", async () => { // Arrange const { wrapper } = setupMocks({}); - mockOutPromises({ carId: 'C11111' }); + mockOutPromises({ carId: "C11111" }); wrapper.vm.vinTouched = true; wrapper.vm.vin = ""; wrapper.vm.initialVin = "foo"; wrapper.vm.navigateForward = jest.fn(); - // Act + // Act await wrapper.vm.forwardButtonAction(); //Assert @@ -95,13 +92,13 @@ describe("vin-lookup.vue", () => { it("Should call navigateForward() if the store carId does not match the vin response carId but does match previously enterted carId and forward button is clicked", async () => { // Arrange const { wrapper } = setupMocks({}); - mockOutPromises({ carId: 'C11111' }); + mockOutPromises({ carId: "C11111" }); wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise); wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.previouslyEnteredCarId = 'C11111'; + wrapper.vm.previouslyEnteredCarId = "C11111"; - // Act + // Act await wrapper.vm.forwardButtonAction(); //Assert @@ -113,8 +110,8 @@ describe("vin-lookup.vue", () => { const { wrapper } = setupMocks({}); const zipValidationApiResponse = { data: { - isServiceable: false - } + isServiceable: false, + }, }; const zipPromise = Promise.resolve(zipValidationApiResponse); @@ -123,9 +120,9 @@ describe("vin-lookup.vue", () => { wrapper.vm.setupUiForNonServiceableZip = jest.fn(); wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.previouslyEnteredCarId = 'new carId'; + wrapper.vm.previouslyEnteredCarId = "new carId"; - // Act + // Act await wrapper.vm.forwardButtonAction(); //Assert @@ -140,9 +137,9 @@ describe("vin-lookup.vue", () => { wrapper.vm.initialVin = "!foo"; wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.previouslyEnteredCarId = 'new carId'; + wrapper.vm.previouslyEnteredCarId = "new carId"; - // Act + // Act await wrapper.vm.forwardButtonAction(); //Assert @@ -155,14 +152,14 @@ describe("vin-lookup.vue", () => { const { wrapper } = setupMocks({ customMountOptions: { router: { - navigateWithSaving: jest.fn() - } - } + navigateWithSaving: jest.fn(), + }, + }, }); wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); wrapper.setData({ isCarIdDifferent: true, - isSelectedGlassAvailableForVehicle: false + isSelectedGlassAvailableForVehicle: false, }); // Act @@ -170,8 +167,13 @@ describe("vin-lookup.vue", () => { //Assert expect(wrapper.vm.$router.navigateWithSaving).toBeCalledTimes(1); - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, wrapper.vm.$route, expect.anything(), expect.anything()); - }) + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( + navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, + wrapper.vm.$route, + expect.anything(), + expect.anything() + ); + }); test("carId matches => navigateForwardWithSingleCarMatch", async () => { // Arrange @@ -186,7 +188,7 @@ describe("vin-lookup.vue", () => { //Assert expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1); - }) + }); test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => { // Arrange @@ -201,50 +203,73 @@ describe("vin-lookup.vue", () => { //Assert expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1); - }) - }) + }); + }); describe("alerts", () => { test("Zip is invalid => show AlertInvalidZipWidget", async () => { // Arrange const { wrapper } = setupMocks({}); mockOutPromises({ isZipValid: false }); - await wrapper.setData({serviceZipCode: "11111"}) - + await wrapper.setData({ serviceZipCode: "11111" }); + // Act await wrapper.vm.forwardButtonAction(); // Assert expect(wrapper.vm.displayInvalidZipAlert).toEqual(true); - expect(wrapper.findComponent({ref: "alertInvalidZip"}).exists()).toBe(true); - }) - }) -}); + expect(wrapper.findComponent({ ref: "alertInvalidZip" }).exists()).toBe(true); + }); + test("alerts are displayed and continue button is clicked with issues fixed => alerts are reset", async () => { + // Arrange + const { wrapper } = setupMocks({}); + mockOutPromises({ isZipValid: true, isZipServiceable: true, carId: "CARID" }); + await wrapper.setData({ + displayInvalidZipAlert: true, + displayMatchedDifferentVehicleAlert: true, + displayNonServiceableZipAlert: true, + displayVinNotFoundAlert: true + }); + + // sanity check that there are alerts + expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(4); + + // Act + wrapper.vm.forwardButtonAction(); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(0); + }); + }); +}); function setupMocks({ customMountOptions }) { const mountOptions = getMountOptions({ - ...customMountOptions + ...customMountOptions, }); // Modify/augment default mount options mountOptions.global.mocks["$store"] = store; mountOptions.global.mixins = [mockMixin]; - mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods + mountOptions["attachTo"] = document.body; // append wrapper to document.body to test DOM methods const wrapper = shallowMount(vinLookup, mountOptions); mockOutStubFunctions(wrapper); return { wrapper }; } -function mockOutPromises({carId, isZipValid = true, isZipServiceable = true}) { +function mockOutPromises({ carId, isZipValid = true, isZipServiceable = true }) { const apiResponses = { vehicleLookupResponse: { - carId: carId + carId: carId, }, zipCodeData: { - isValid: true, isServiceable: true, state: "OH" - } + isValid: isZipValid, + isServiceable: isZipServiceable, + state: "OH", + }, }; settleAllPromises.mockImplementation(() => apiResponses); @@ -253,11 +278,13 @@ function mockOutPromises({carId, isZipValid = true, isZipServiceable = true}) { function mockOutStubFunctions(wrapper) { wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.getZipCodeData = jest.fn().mockReturnValue({ isValid: true, isServiceable: true, state: "OH" }); + wrapper.vm.getZipCodeData = jest + .fn() + .mockReturnValue({ isValid: true, isServiceable: true, state: "OH" }); } const mockMixin = { methods: { getCmsContent: jest.fn(() => "placeholder CMS content"), - } -} \ No newline at end of file + }, +}; diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 3614c74cf..a203ed22e 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -228,6 +228,8 @@ export default { }, async forwardButtonAction() { + this.resetAlerts(); + // If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation if (!this.vinPopulatedOnPageLoad) { const vehicleLookupResponse = this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, { vin: this.vin }); @@ -337,6 +339,12 @@ export default { return this.$refs.funnelFooter.removeLoader(); }, + resetAlerts() { + this.displayMatchedDifferentVehicleAlert = false; + this.displayNonServiceableZipAlert = false; + this.displayInvalidZipAlert = false; + this.displayVinNotFoundAlert = false; + }, async navigateForward(){ if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { this.$router.navigateWithSaving(this.navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, this.$route, {}, { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }); From a035e88325359f66012169245f752219e928d232 Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Thu, 27 Oct 2022 22:05:11 -0400 Subject: [PATCH 10/27] CSR-867: change some naming back to keep existing production vuex state --- src/helpers/damage-helper.js | 6 +- src/helpers/damage-helper.spec.js | 12 +- .../capability-questions.vue | 16 +- .../molding-questions/molding-questions.vue | 12 +- src/layouts/part-questions/part-questions.vue | 10 +- .../vehicle-damage/vehicle-damage.spec.js | 28 +-- src/layouts/vehicle-damage/vehicle-damage.vue | 44 ++--- .../glass-part-question.spec.js | 34 ++-- .../glass-part-question.vue | 26 +-- .../vehicle-parts/vehicle-parts.spec.js | 16 +- src/layouts/vehicle-parts/vehicle-parts.vue | 20 +- src/mixins/vehicle-questions-mixin.js | 10 +- src/mixins/vehicle-questions-mixin.spec.js | 184 +++++++++--------- src/store/index.js | 87 +++++++-- 14 files changed, 275 insertions(+), 230 deletions(-) diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 55d10738d..ed353e51b 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -19,7 +19,7 @@ export function getDamageString() { if (damageLocations.length > 1) { returnString = "match" } else { - switch(damageLocations[0]?.location) { + switch(damageLocations[0]?.glassLocation) { case "Windshield": returnString = "windshield" break; @@ -36,7 +36,7 @@ export function getDamageString() { export function getIsWindshieldOnly () { const damageLocations = store.getters.damage.glassToReplace; - const returnString = damageLocations.length === 1 && damageLocations[0]?.location === "Windshield" ? "windshield" : "glass"; + const returnString = damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield" ? "windshield" : "glass"; return returnString; } @@ -56,7 +56,7 @@ export async function isGlassAvailableForCarId(carId){ } for(const option of currentGlassOptions){ - if(!newGlassOptions.data[optionsMap[option.location]].availableReplacementOptions.includes(option.name)){ + if(!newGlassOptions.data[optionsMap[option.glassLocation]].availableReplacementOptions.includes(option.glassName)){ return false; } } diff --git a/src/helpers/damage-helper.spec.js b/src/helpers/damage-helper.spec.js index 2a46978dc..210bf96cc 100644 --- a/src/helpers/damage-helper.spec.js +++ b/src/helpers/damage-helper.spec.js @@ -16,7 +16,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ it("Should return match when multiple selected damage options are in the store", () => { // Arrange / Act - store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}, {location: "Passenger", name: "sideWindow"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}, {glassLocation: "Passenger", glassName: "sideWindow"}]; const damage = getDamageString(); @@ -29,7 +29,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ it("Should return windshield when Windshield is the only selected damage option in the store", () => { // Arrange / Act - store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}]; const damage = getDamageString(); @@ -42,7 +42,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => { // Arrange / Act - store.getters.damage.glassToReplace = [{location: "Passenger", name: "sideWindow"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Passenger", glassName: "sideWindow"}]; const damage = getDamageString(); @@ -55,7 +55,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ it("Should return rear window when Rear is the only selected damage option in the store", () => { // Arrange / Act - store.getters.damage.glassToReplace = [{location: "Rear", name: "rear"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Rear", glassName: "rear"}]; const damage = getDamageString(); @@ -67,7 +67,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ describe("damage-helper.js", () => { it("Should return true if no mismatches between each array exist", async () => { // Arrange - store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}]; // Act const isGlassAvailable = await isGlassAvailableForCarId(); @@ -80,7 +80,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({ describe("damage-helper.js", () => { it("Should return false if any mismatches between each array exist", async () => { // Arrange - store.getters.damage.glassToReplace = [{location: "Windshield", name: "sideWindow"}]; + store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "sideWindow"}]; const isGlassAvailable = await isGlassAvailableForCarId(); diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 6491a76df..187f02fe1 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -11,7 +11,7 @@ v-bind:isDismissible="false" />
@@ -86,7 +86,7 @@ export default { return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText"); }, windshieldPart() { - return this.pageData.partsOrQuestions.find(x => x.location === damageLocationsSelected.WINDSHIELD); + return this.pageData.partsOrQuestions.find(x => x.glassLocation === damageLocationsSelected.WINDSHIELD); }, windshieldPartInfo() { return this.windshieldPart.parts[0]; @@ -122,8 +122,8 @@ export default { const selectedAnswerResult2 = this.getCorrespondingAnswerResult2(glass.answerData.answerResult); return { - location: glass.location, - name: glass.name, + glassLocation: glass.glassLocation, + glassName: glass.glassName, result: glass.answerData.answerResult, result1: glass.answerData.answerResult, result2: selectedAnswerResult2, @@ -143,8 +143,8 @@ export default { // get parts from the capabilityQuestionAnswers let partsOrQuestions = this.pageData.partsOrQuestions; for (let answer of capabilityQuestionsAnswersArray) { - const correspondingPart = partsOrQuestions.find(partOrQuestion => partOrQuestion.location === answer.location); - const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, answer.location, false)).data; + const correspondingPart = partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === answer.glassLocation); + const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, answer.glassLocation, false)).data; partsOrQuestions.find(partOrQuestion => partOrQuestion.location === answer.location).parts = partFromCapabilityQuestionAnswer; } @@ -239,7 +239,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].location + this.capabilityQuestionsData[gpIndex].name + Date.now().toString(); + this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].glassLocation + this.capabilityQuestionsData[gpIndex].glassName + Date.now().toString(); // handle suppressing downstream in this question chain @@ -325,7 +325,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].location + this.capabilityQuestionsData[gpIndex].name + Date.now().toString(); + this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].glassLocation + this.capabilityQuestionsData[gpIndex].glassName + Date.now().toString(); } }); diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index c73c6e5e1..50cfe42c2 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -23,7 +23,7 @@
{ return { - location: glass.location, - name: glass.name, + glassLocation: glass.glassLocation, + glassName: glass.glassName, partNum: glass.answerData.answerResult, answeredQuestions: glass.answerData.answeredQuestions, isSuppressedPart: glass.isSuppressedPart, @@ -152,7 +152,7 @@ export default { let partsOrQuestions = this.pageData.partsOrQuestions; for (let answer of questionAnswersArray) { partsOrQuestions.find(partOrQuestion => { - return partOrQuestion.location === answer.location && partOrQuestion.name === answer.name; + return partOrQuestion.glassLocation === answer.glassLocation && partOrQuestion.glassName === answer.glassName; }).parts[0].childParts = [ { partNumber: answer.partNum @@ -250,7 +250,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].location + this.moldingQuestionsData[gpIndex].name + Date.now().toString(); + this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].glassLocation + this.moldingQuestionsData[gpIndex].glassName + Date.now().toString(); // handle suppressing downstream in this question chain @@ -336,7 +336,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].location + this.moldingQuestionsData[gpIndex].name + Date.now().toString(); + this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].glassLocation + this.moldingQuestionsData[gpIndex].glassName + Date.now().toString(); } diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index 0b0cc0165..7423cb6bb 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -23,7 +23,7 @@
{ return { - location: glass.location, - name: glass.name, + glassLocation: glass.glassLocation, + glassName: glass.glassName, result: glass.answerData.answerResult, answeredQuestions: glass.answerData.answeredQuestions, isSuppressedPart: glass.isSuppressedPart, @@ -246,7 +246,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].location + this.partsQuestionsData[gpIndex].name + Date.now().toString(); + this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].glassLocation + this.partsQuestionsData[gpIndex].glassName + Date.now().toString(); // handle suppressing downstream in this question chain @@ -332,7 +332,7 @@ export default { }); // Update the key to re-render this part's question-chain component - this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].location + this.partsQuestionsData[gpIndex].name + Date.now().toString(); + this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].glassLocation + this.partsQuestionsData[gpIndex].glassName + Date.now().toString(); } diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js index 27778feed..7791dff37 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.spec.js +++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js @@ -81,8 +81,8 @@ describe("vehicle-damage.vue", () => { //Arrange const partsData = { partsOrQuestions: [{ - name: "Single", - location: "Windshield", + glassName: "Single", + glassLocation: "Windshield", parts: null, partQuestions: [{ questionSequence: 1, @@ -144,8 +144,8 @@ describe("vehicle-damage.vue", () => { wrapper.vm.selectedRearReplaceOptions = ["Stationary"]; - const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }, { location: "Driver", name: "Back" }, - { location: "Passenger", name: "Quarter" }, { location: "Rear", name: "Stationary" }]; + const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" }, + { glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }]; //Act vehicleDamage.beforeRouteEnter.call( @@ -168,8 +168,8 @@ describe("vehicle-damage.vue", () => { const partsData = { partsOrQuestions: [ { - location: "Windshield", - name: "Single", + glassLocation: "Windshield", + glassName: "Single", partQuestions: null, parts: [ { @@ -189,8 +189,8 @@ describe("vehicle-damage.vue", () => { ] }, { - name: "Stationary", - location: "Rear", + glassName: "Stationary", + glassLocation: "Rear", parts: [ { partNumber: "DB09626GTYN", @@ -235,7 +235,7 @@ describe("vehicle-damage.vue", () => { selectedWindshieldDamageType: "Replace" }; - const expectedGlassToReplace = [{ location: "Windshield", name: "Single" },]; + const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" },]; //Act vehicleDamage.beforeRouteEnter.call( @@ -509,7 +509,7 @@ describe("vehicle-damage.vue", () => { (c) => c(wrapper.vm) ); - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation }] }, isRepair: true }; + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation }] }, isRepair: true }; var glassSelections = wrapper.vm.getDamageLocationsFromStore(); @@ -553,7 +553,7 @@ describe("vehicle-damage.vue", () => { eventBusItem: jest.fn(), damage: { - glassToReplace: [{ location: damageLocation, name: damageName }], + glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }], isRepair: isRepair, numberOfChips: 2 }, @@ -583,7 +583,7 @@ describe("vehicle-damage.vue", () => { (c) => c(wrapper.vm) ); - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }] }, isRepair: true }; var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore(); @@ -610,7 +610,7 @@ describe("vehicle-damage.vue", () => { (c) => c(wrapper.vm) ); - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }] }, isRepair: true }; var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore(); @@ -634,7 +634,7 @@ describe("vehicle-damage.vue", () => { (c) => c(wrapper.vm) ); - store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, isRepair: true }; + store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }] }, isRepair: true }; var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore(); diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index f729b8b1a..2b9f08db3 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -179,16 +179,16 @@ export default { getDamageLocationsFromStore() { var glassSelections = []; - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.WINDSHIELD }) || + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.WINDSHIELD }) || store.getters.damage.isRepair) { glassSelections.push(damageLocationsSelected.WINDSHIELD); } - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.DRIVER || - glass.location === damageLocationsSelected.PASSENGER })) { + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.DRIVER || + glass.glassLocation === damageLocationsSelected.PASSENGER })) { glassSelections.push(damageLocationsSelected.SIDEDOOR); } - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.REAR })) { + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.REAR })) { glassSelections.push(damageLocationsSelected.REARWINDOW); } @@ -201,20 +201,20 @@ export default { if (store.getters.damage.isRepair === undefined) return windshieldOptions; if (!store.getters.damage.isRepair) { - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.WINDSHIELD && - glass.name === damageLocationsSelected.SINGLE })) { + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.WINDSHIELD && + glass.glassName === damageLocationsSelected.SINGLE })) { windShieldOptions.selectedWindshieldDamageType = damageLocationsSelected.REPLACE; windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.SINGLE); } - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.WINDSHIELD && - glass.name === damageLocationsSelected.DRIVER })) { + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.WINDSHIELD && + glass.glassName === damageLocationsSelected.DRIVER })) { windShieldOptions.selectedWindshieldDamageType = damageLocationsSelected.REPLACE; windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.DRIVER); } - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.WINDSHIELD && - glass.name === damageLocationsSelected.PASSENGER })) { + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.WINDSHIELD && + glass.glassName === damageLocationsSelected.PASSENGER })) { windShieldOptions.selectedWindshieldDamageType = damageLocationsSelected.REPLACE; windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.PASSENGER); } @@ -231,11 +231,11 @@ export default { getDoorSidesFromStore() { var doorSides = []; - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.DRIVER })){ + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.DRIVER })){ doorSides.push(damageLocationsSelected.DRIVERSIDE); } - if (store.getters.damage.glassToReplace?.some(glass => { return glass.location === damageLocationsSelected.PASSENGER })){ + if (store.getters.damage.glassToReplace?.some(glass => { return glass.glassLocation === damageLocationsSelected.PASSENGER })){ doorSides.push(damageLocationsSelected.PASSENGERSIDE); } @@ -246,8 +246,8 @@ export default { var driverSideReplaceOptions = []; store.getters.damage.glassToReplace?.forEach(glass => { - if (glass.location === damageLocationsSelected.DRIVER){ - driverSideReplaceOptions.push(glass.name); + if (glass.glassLocation === damageLocationsSelected.DRIVER){ + driverSideReplaceOptions.push(glass.glassName); } }); @@ -258,8 +258,8 @@ export default { var passengerSideReplaceOptions = []; store.getters.damage.glassToReplace?.forEach(glass => { - if (glass.location === damageLocationsSelected.PASSENGER){ - passengerSideReplaceOptions.push(glass.name); + if (glass.glassLocation === damageLocationsSelected.PASSENGER){ + passengerSideReplaceOptions.push(glass.glassName); } }); @@ -270,8 +270,8 @@ export default { var rearReplaceOptions = []; store.getters.damage.glassToReplace?.forEach(glass => { - if (glass.location === damageLocationsSelected.REAR){ - rearReplaceOptions.push(glass.name); + if (glass.glassLocation === damageLocationsSelected.REAR){ + rearReplaceOptions.push(glass.glassName); } }); @@ -304,25 +304,25 @@ export default { const selectedGlassToReplace = []; if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){ this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => { - selectedGlassToReplace.push({ location: damageLocationsSelected.WINDSHIELD, name: wsItem}); + selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.WINDSHIELD, glassName: wsItem}); }) } if (this.isDriverSideReplace){ this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => { - selectedGlassToReplace.push({ location: damageLocationsSelected.DRIVER, name: driverItem}); + selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.DRIVER, glassName: driverItem}); }) } if (this.isPassengerSideReplace){ this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => { - selectedGlassToReplace.push({ location: damageLocationsSelected.PASSENGER, name: passengerItem}); + selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.PASSENGER, glassName: passengerItem}); }) } if (this.isRearWindowDamageLocation) { this.selectedRearReplaceOptions.forEach(rearItem => { - selectedGlassToReplace.push({ location: damageLocationsSelected.REAR, name: rearItem}); + selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.REAR, glassName: rearItem}); }) } diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js index 2acf1d87d..52471bf34 100644 --- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js +++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.spec.js @@ -13,8 +13,8 @@ const featureListData = { { ColorAnswerText: 'Green Tint', FeatureAnswers: [{ FeatureAnswerText: "heated glass, solar, 1 hole", PartNumber: "DB12209GTYN" }] }, { ColorAnswerText: 'Gray Tint Privacy', FeatureAnswers: [{ FeatureAnswerText: "heated glass, solar, 1 hole", PartNumber: "DB12209YPYN" }] } ], - locationProp: "Rear", - nameProp: "Stationary", + glassLocationProp: "Rear", + glassNameProp: "Stationary", modelValueProp: {} } @@ -37,7 +37,7 @@ describe("glass-part-question.vue", () => { }); - test("Tint mapper, should get tint image by location and tintColor", async () => { + test("Tint mapper, should get tint image by glassLocation and tintColor", async () => { //Arrange @@ -72,7 +72,7 @@ describe("glass-part-question.vue", () => { //Arrange const { wrapper } = setupMocks(featureListData); store.getters.pageData.mockReset(); - store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{name: "Stationary", location: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}]}] }); + store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{glassName: "Stationary", glassLocation: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}]}] }); //Act await wrapper.vm.$nextTick(); @@ -111,7 +111,7 @@ describe("glass-part-question.vue", () => { test("default is selected if only one option", async () => { // Arrange store.getters.pageData.mockReset(); - store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{name: "Stationary", location: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}]}] }); + store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{glassName: "Stationary", glassLocation: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}]}] }); const { wrapper } = setupMocks(featureListData); // Act @@ -129,7 +129,7 @@ describe("glass-part-question.vue", () => { test("default is not selected if more than one option", async () => { // Arrange store.getters.pageData.mockReset(); - store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{name: "Stationary", location: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}, { partNumber: "DB12209GTYNXXX", color: "Green Tint"}]}] }); + store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{glassName: "Stationary", glassLocation: "Rear", parts: [{ partNumber: "DB12209GTYN", color: "Green Tint"}, { partNumber: "DB12209GTYNXXX", color: "Green Tint"}]}] }); const { wrapper } = setupMocks(featureListData); // Act @@ -150,13 +150,13 @@ describe("glass-part-question.vue", () => { ["Windshield", "Single", "Blue Tint", []], ["Driver", "Quarter", "Green Tint", []] ]; - test.each(partsForSelectedTintTestCases)("partsForSelectedTint returns correct parts", async (location, name, selectedTint, expectedResults) => { + test.each(partsForSelectedTintTestCases)("partsForSelectedTint returns correct parts", async (glassLocation, glassName, selectedTint, expectedResults) => { // Arrange store.getters.pageData.mockReset(); store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [ { - name: "Stationary", - location: "Rear", + glassName: "Stationary", + glassLocation: "Rear", parts: [ { partNumber: "Glass1", color: "Green Tint"}, { partNumber: "Glass2", color: "Blue Tint"}, @@ -168,14 +168,14 @@ describe("glass-part-question.vue", () => { ] }, { - name: "Single", - location: "Windshield", + glassName: "Single", + glassLocation: "Windshield", parts: [{ partNumber: "Windshield1", color: "Green Tint"}, { partNumber: "Windshield2", color: "Green Tint"}] } ]}); const { wrapper } = setupMocks({ - locationProp: location, - nameProp: name, + glassLocationProp: glassLocation, + glassNameProp: glassName, colorAnswersProp: [], }); @@ -189,9 +189,9 @@ describe("glass-part-question.vue", () => { -function setupMocks({ nameProp, locationProp, colorAnswersProp, modelValueProp }) { +function setupMocks({ glassNameProp, glassLocationProp, colorAnswersProp, modelValueProp }) { //Mock store - store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{name: "Stationary", location: "Rear", parts: []}] }); + store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [{glassName: "Stationary", glassLocation: "Rear", parts: []}] }); store.getters.lineItems = { glassParts: {} } const mountOptions = getMountOptions({ @@ -206,8 +206,8 @@ function setupMocks({ nameProp, locationProp, colorAnswersProp, modelValueProp } }); mountOptions.propsData = { - name: nameProp, - location: locationProp, + glassName: glassNameProp, + glassLocation: glassLocationProp, colorAnswers: colorAnswersProp, modelValue: modelValueProp }; diff --git a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue index 8154f2ca4..10233d4d8 100644 --- a/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue +++ b/src/layouts/vehicle-parts/glass-part-question/glass-part-question.vue @@ -12,7 +12,7 @@ :isWide="true" altText="" isRequired - :groupName="`${location}-${name}`" + :groupName="`${glassLocation}-${glassName}`" @isCheckedChanged="ResetTintAndPartSelections" :validationRules="tintValidationRules" > @@ -27,7 +27,7 @@ textPosition="text-start" :loaderEnabled="false" isRequired - :groupName="`${location}-${name}-${selectedTint}`" + :groupName="`${glassLocation}-${glassName}-${selectedTint}`" :validationRules="partValidationRules" />
@@ -60,8 +60,8 @@ export default { }; }, props: { - name: String, - location: String, + glassName: String, + glassLocation: String, colorAnswers: Array, modelValue: Object, alreadyPopulatedPartsData: Array @@ -74,19 +74,19 @@ export default { }, computed: { tintValidationRules() { - const validationRuleName = `${this.location}-${this.name}-tint-required`; + const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`; defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED)); return validationRuleName; }, partValidationRules() { - const validationRuleName = `${this.location}-${this.name}-part-required`; + const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`; defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED)); return validationRuleName; }, colorQuestionText() { return getCustomTransformValue( this.glassColorQuestion, - `${this.location} ${this.name}` + `${this.glassLocation} ${this.glassName}` ); }, @@ -98,7 +98,7 @@ export default { Name: tintOption, Text: tintOption, AnswerImageUrl: require(`@/assets/img/tints/${this.getTintSourceImage( - this.location, + this.glassLocation, tintOption )}`), }); @@ -117,9 +117,9 @@ export default { }, partsForSelectedTint() { - const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(dataForlocationAndName => - dataForlocationAndName.name == this.name && - dataForlocationAndName.location == this.location); + const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(dataForGlassLocationAndName => + dataForGlassLocationAndName.glassName == this.glassName && + dataForGlassLocationAndName.glassLocation == this.glassLocation); const matchingGlassParts = matchingGlass?.length == 1 ? matchingGlass[0].parts : []; return matchingGlassParts.filter(part => part.color == this.selectedTint) ?? []; }, @@ -167,8 +167,8 @@ export default { // Gets tint images based on the glass type, and tint name. // Returns an empty string if the src or object is undefined. - getTintSourceImage(location, tintColor) { - const tintSourceObject = getTintImage(location, tintColor); + getTintSourceImage(glassLocation, tintColor) { + const tintSourceObject = getTintImage(glassLocation, tintColor); if ( tintSourceObject === undefined || diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 3f54b300c..2fce952c2 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -41,8 +41,8 @@ store.getters = { const basePartResponse = { partsOrQuestions: [ { - name: "Stationary", - location: "Rear", + glassName: "Stationary", + glassLocation: "Rear", parts: [ { partNumber: "DB12209GTYN", @@ -207,8 +207,8 @@ describe("vehicle-parts.vue", () => { return { partsOrQuestions: [ { - name: "Stationary", - location: "Rear", + glassName: "Stationary", + glassLocation: "Rear", parts: null, partQuestions: [{ testProperty: "some value" @@ -287,8 +287,8 @@ describe("vehicle-parts.vue", () => { store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [ { - name: "Single", - location: "Windshield", + glassName: "Single", + glassLocation: "Windshield", parts: [ { "partNumber": "FW03861GTYN", @@ -365,8 +365,8 @@ describe("vehicle-parts.vue", () => { store.getters.pageData.mockReturnValueOnce({ partsOrQuestions: [ { - name: "Single", - location: "Windshield", + glassName: "Single", + glassLocation: "Windshield", parts: [ { partNumber: "DB12209GTYN", diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue index 2c4583685..6116e5391 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.vue +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -29,10 +29,10 @@
@@ -125,8 +125,8 @@ export default { // Map API result data, to vehicle-parts data structure const mappedData = partsData.partsOrQuestions.map((g) => { return { - name: g.name, - location: g.location, + glassName: g.glassName, + glassLocation: g.glassLocation, colorAnswers: g.parts?.reduce((arr, p) => { arr.push({ ColorAnswerText: p.color, @@ -175,8 +175,8 @@ export default { if (isMatched) { matchedParts.push({ - location: value.location, - name: value.name, + glassLocation: value.glassLocation, + glassName: value.glassName, parts: [currentPart] }); } @@ -207,8 +207,8 @@ export default { const partNumber = alreadyPopulatedPartsData[key].partNumber; g.parts.forEach((p) => { if (p.partNumber === partNumber) { - this.selectedGlassParts[g.location + "-" + g.name] = { - [g.location]: [partNumber], + this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = { + [g.glassLocation]: [partNumber], }; } }); diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 5ac1c7758..9884117d7 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -65,20 +65,20 @@ export default { return this.comparePageIndices(currentPage, fmgPage) > 0; }, setupInitialData(glass, i, alreadyAnsweredQuestions, vm) { - glass.key = glass.location + "-" + glass.name; + glass.key = glass.glassLocation + "-" + glass.glassName; const self = vm ?? this; // clear answerData if no questions are already answered if (!alreadyAnsweredQuestions) { glass.answerData = null } alreadyAnsweredQuestions?.forEach((answeredGlass) => { // if answeredGlass lacks any of these properties then exit - if (!answeredGlass.location || - !answeredGlass.name || + if (!answeredGlass.glassLocation || + !answeredGlass.glassName || !answeredGlass.answeredQuestions || !answeredGlass.result && !answeredGlass.partNum) { return } // test if glass parts match - if (glass.location === answeredGlass.location && glass.name === answeredGlass.name) { + if (glass.glassLocation === answeredGlass.glassLocation && glass.glassName === answeredGlass.glassName) { let answerString = ""; // loop through answeredQuestions for matches @@ -118,7 +118,7 @@ export default { // Set up watch for each set of glass questions // (updated when all questions for a glass have been answered in question-chain) - self.$watch("selectedAnswers." + glass.location + '-' + glass.name, (newValue) => { + self.$watch("selectedAnswers." + glass.glassLocation + '-' + glass.glassName, (newValue) => { if (newValue) { self.handleAnswerUpdates(newValue); } diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index b2dab9645..e5a579f02 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -71,8 +71,8 @@ describe("vehicle-questions-mixin", () => { // Act const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ { - name: "Something", - location: "somewhere", + glassName: "Something", + glassLocation: "somewhere", parts: [{ partNumber: "1234567" }] @@ -90,22 +90,22 @@ describe("vehicle-questions-mixin", () => { // Act const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ { - name: "Something", - location: "somewhere", + glassName: "Something", + glassLocation: "somewhere", parts: [{ partNumber: "1234567" }] }, { - name: "Another glass", - location: "somewhere else", + glassName: "Another glass", + glassLocation: "somewhere else", parts: [{ partNumber: "1234568" }] }, { - name: "Special glass", - location: "Another where", + glassName: "Special glass", + glassLocation: "Another where", parts: [{ partNumber: "1234569" }] @@ -123,22 +123,22 @@ describe("vehicle-questions-mixin", () => { // Act const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ { - name: "Something", - location: "somewhere", + glassName: "Something", + glassLocation: "somewhere", parts: [{ partNumber: "1234567" }] }, { - name: "Another glass", - location: "somewhere else", + glassName: "Another glass", + glassLocation: "somewhere else", parts: [{ partNumber: "1234568" }] }, { - name: "Special glass", - location: "Another where", + glassName: "Special glass", + glassLocation: "Another where", parts: [ { partNumber: "1234569" @@ -321,8 +321,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const { wrapper } = setupMocks({}); const glass = { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", }; const i = 0; @@ -338,8 +338,8 @@ describe("vehicle-questions-mixin", () => { test("should return glass with answerData of null", async () => { // Arrange const glass = { - "name": "Single", - "location": "Windshield" + "glassName": "Single", + "glassLocation": "Windshield" }; const i = 0; const { wrapper } = setupMocks({}); @@ -356,8 +356,8 @@ describe("vehicle-questions-mixin", () => { test("should return glass with answerResult within answerData", async () => { // Arrange const glass = { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "questions": [ { "questionSequence": 1, @@ -380,8 +380,8 @@ describe("vehicle-questions-mixin", () => { const i = 0; const alreadyAnsweredQuestions = [ { - "location": "Windshield", - "name": "Single", + "glassLocation": "Windshield", + "glassName": "Single", "partNum": "WKT D1106 C", "answeredQuestions": [ { @@ -409,8 +409,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": null, "partQuestions": [ { @@ -449,8 +449,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": null, "partQuestions": [ { @@ -472,8 +472,8 @@ describe("vehicle-questions-mixin", () => { ] }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD08158GTYN", @@ -487,8 +487,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Quarter", - "location": "Driver", + "glassName": "Quarter", + "glassLocation": "Driver", "parts": [ { "partNumber": "DQ08162GTYN", @@ -502,8 +502,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "SideDoor", - "location": "Driver", + "glassName": "SideDoor", + "glassLocation": "Driver", "parts": null, "partQuestions": [ { @@ -525,8 +525,8 @@ describe("vehicle-questions-mixin", () => { ] }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "DB08165GTNN", @@ -557,8 +557,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": null, "partQuestions": [ { @@ -580,8 +580,8 @@ describe("vehicle-questions-mixin", () => { ] }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD08158GTYN", @@ -595,8 +595,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Quarter", - "location": "Driver", + "glassName": "Quarter", + "glassLocation": "Driver", "parts": [ { "partNumber": "DQ08162GTYN", @@ -610,8 +610,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "SideDoor", - "location": "Driver", + "glassName": "SideDoor", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD08160GTYN", @@ -625,8 +625,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "DB08165GTNN", @@ -657,8 +657,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": null, "partQuestions": [ { @@ -680,8 +680,8 @@ describe("vehicle-questions-mixin", () => { ] }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD08158GTYN", @@ -695,8 +695,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Quarter", - "location": "Driver", + "glassName": "Quarter", + "glassLocation": "Driver", "parts": [ { "partNumber": "DQ08162GTYN", @@ -718,8 +718,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "SideDoor", - "location": "Driver", + "glassName": "SideDoor", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD08160GTYN", @@ -741,8 +741,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "DB08165GTNN", @@ -807,8 +807,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "FB25724GTYN", @@ -847,8 +847,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": [ { "partNumber": "FW03647GTNN", @@ -868,8 +868,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Back", - "location": "Driver", + "glassName": "Back", + "glassLocation": "Driver", "parts": [ { "partNumber": "FD25747GTYN", @@ -883,8 +883,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "FD25719GTYN", @@ -898,8 +898,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Vent", - "location": "Driver", + "glassName": "Vent", + "glassLocation": "Driver", "parts": [ { "partNumber": "FV25749GTNN", @@ -913,8 +913,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "FB25724GTYN", @@ -953,8 +953,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": [ { "partNumber": "DW02101GTYN", @@ -968,8 +968,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Back", - "location": "Driver", + "glassName": "Back", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD12202GTYN", @@ -991,8 +991,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "DD12198GTYN", @@ -1014,8 +1014,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Quarter", - "location": "Driver", + "glassName": "Quarter", + "glassLocation": "Driver", "parts": [ { "partNumber": "DQ12204GTYNOEM", @@ -1085,8 +1085,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "DB12209GTYN", @@ -1127,8 +1127,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "FB25724GTYN", @@ -1180,8 +1180,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": [ { "partNumber": "FB25724GTYN", @@ -1216,8 +1216,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": [ { "partNumber": "FW04186GTYN", @@ -1253,8 +1253,8 @@ describe("vehicle-questions-mixin", () => { // Arrange const partsOrQuestions = [ { - "name": "Single", - "location": "Windshield", + "glassName": "Single", + "glassLocation": "Windshield", "parts": [ { "partNumber": "FW04186GTYN", @@ -1274,8 +1274,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Back", - "location": "Driver", + "glassName": "Back", + "glassLocation": "Driver", "parts": [ { "partNumber": "FD25457GTYN", @@ -1289,8 +1289,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Front", - "location": "Driver", + "glassName": "Front", + "glassLocation": "Driver", "parts": [ { "partNumber": "FD27090GTYN", @@ -1304,8 +1304,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Vent", - "location": "Driver", + "glassName": "Vent", + "glassLocation": "Driver", "parts": [ { "partNumber": "FV25459GTNN", @@ -1319,8 +1319,8 @@ describe("vehicle-questions-mixin", () => { "partQuestions": null }, { - "name": "Stationary", - "location": "Rear", + "glassName": "Stationary", + "glassLocation": "Rear", "parts": [ { "partNumber": "FB25460GTYN", diff --git a/src/store/index.js b/src/store/index.js index 250971bd9..6dcfd0162 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -712,24 +712,22 @@ export const actions = { const zipCode = order.serviceLocation.zipCode; const vin = vehicle.vin; + // create a new array to avoid mutating state + const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); + const response = await globalMethods.callHttpClient({ method: endpoints.GetPartsOrQuestions.method, endpoint: endpoints.GetPartsOrQuestions.url, payload: { carId: carId, - glassPieces: glassArray ?? [], + glassPieces: glassArrayForPayload, zip: zipCode, vin: vin }, }); // Flatten location and name properties - response.data.partsOrQuestions.map(glass => { - glass.location = glass.glassPiece.location; - glass.name = glass.glassPiece.name; - delete glass.glassPiece; - return glass; - }); + response.data.partsOrQuestions = convertGlassPieceNamingFromApi(response.data.partsOrQuestions); return response; }, @@ -746,25 +744,24 @@ export const actions = { const zipCode = order.serviceLocation.zipCode; const vin = vehicle.vin; - // Flatten location and name properties + // create a new array to avoid mutating state + const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); + const resultsArrayForPayload = convertResultsForApi(resultsArray); + const response = await globalMethods.callHttpClient({ method: endpoints.GetParts.method, endpoint: endpoints.GetParts.url, payload: { carId: carId, - glassPieces: glassArray, - answerResults: resultsArray, + glassPieces: glassArrayForPayload, + answerResults: resultsArrayForPayload, zip: zipCode, vin: vin }, }); - - response.data.glassPieceParts.map(glass => { - glass.location = glass.glassPiece.location; - glass.name = glass.glassPiece.name; - delete glass.glassPiece; - return glass; - }); + + // Flatten location and name properties + response.data.glassPieceParts = convertGlassPieceNamingFromApi(response.data.glassPieceParts); return response; }, @@ -776,12 +773,12 @@ export const actions = { }) }, - getPartFromCapabilityQuestionAnswer(context, location) { + getPartFromCapabilityQuestionAnswer(context, glassLocation) { const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); - const part = pageData.partsOrQuestions.find(x => x.location === location).parts[0]; + const part = pageData.partsOrQuestions.find(x => x.glassLocation === glassLocation).parts[0]; const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers; - const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(x => x.location === location); + const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(x => x.glassLocation === glassLocation); return globalMethods.callHttpClient({ method: endpoints.GetPartFromCapabilityAnswer.method, @@ -801,6 +798,9 @@ export const actions = { const applicationUser = context.getters.applicationUser; const lineItems = context.state.order.lineItems; + // create a new array to avoid mutating state + const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); + return globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, @@ -824,7 +824,7 @@ export const actions = { }, damage: { numberOfChips: damage.numberOfChips, - glassToReplace: damage.glassToReplace, + glassToReplace: newGlassToReplace, isRepair: damage.isRepair }, customer: { @@ -851,6 +851,7 @@ export const actions = { }); }, loadSession(context, { referralNumber, referralDate, referralCorrelationId, accountNumber }) { + return globalMethods.callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, @@ -861,6 +862,15 @@ export const actions = { accountNumber: accountNumber?.toString() }, }).then((response) => { + // Flatten location and name properties + response.data.damage?.glassToReplace?.map(glass => { + glass.glassLocation = glass.location; + glass.glassName = glass.name; + delete glass.location; + delete glass.name; + return glass; + }); + // clear the state if the existing EON does not equal what is returned from loadSession if (context.state.order.eon && context.state.order.eon != response.data.eon) { context.commit(storeMutations.RESET_STATE); @@ -1167,4 +1177,39 @@ function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) { else return 0; }) +} + +function convertGlassPieceNamingForApi(glassArray) { + if (!glassArray) return []; + const converted = []; + glassArray.forEach(glass => { + converted.push({ + location: glass.glassLocation, + name: glass.glassName + }) + }); + return converted; +} + +function convertResultsForApi(resultsArray) { + if (!resultsArray) return []; + const converted = []; + resultsArray.forEach(answer => { + converted.push({ + location: answer.glassLocation, + name: answer.glassName, + result: answer.result + }) + }); + return converted; +} + +function convertGlassPieceNamingFromApi(glassArray) { + glassArray.forEach(glass => { + glass.glassLocation = glass.glassPiece.location; + glass.glassName = glass.glassPiece.name; + delete glass.glassPiece; + return glass; + }); + return glassArray; } \ No newline at end of file From 5d9cbf9db4f6c8a1cede2c9a41de02ca072f4c8d Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Fri, 28 Oct 2022 09:16:18 -0400 Subject: [PATCH 11/27] Removing direct route --- src/router/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index c9e0a4a52..12a6aefe4 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -26,11 +26,6 @@ import quote from "@/layouts/quote/quote.vue"; import datePicker from "@/common-components/date-picker/date-picker.vue"; const routes = [ - { - path: "/quote", // This is a temporary route for testing. - name: "quote", - component: quote, - }, { path: "/date-picker", // This is a temporary route for testing. name: "date-picker", From 8fac778c54ad50d7690466a6e87fa127030806de Mon Sep 17 00:00:00 2001 From: Katie Date: Fri, 28 Oct 2022 09:19:37 -0400 Subject: [PATCH 12/27] CSR-909 Fix validation UI defect --- src/ux-components/list-button/list-button.vue | 1 - src/ux-components/list-card/list-card.vue | 41 +++++++++++-------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index 54ef98b35..64ae6d4af 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -34,7 +34,6 @@ export default { name: "listButton", mixins: [inputButtonWrapperMixin], props: { - selectingInitiatesLoad: Boolean, loaderColor: String, loaderPosition: { type: String, diff --git a/src/ux-components/list-card/list-card.vue b/src/ux-components/list-card/list-card.vue index 7e27a6476..90e575ffd 100644 --- a/src/ux-components/list-card/list-card.vue +++ b/src/ux-components/list-card/list-card.vue @@ -14,15 +14,10 @@ :class="!isWide ? 'order-1' : 'ms-auto order-3'" :src="buttonImage" :alt="altText" /> -

+

{{ buttonLabel }}

-

+

{{ buttonLabelSubCopy }}

@@ -62,12 +57,30 @@ export default { diff --git a/src/common-components/dropdown-question/dropdown-question.spec.js b/src/common-components/dropdown-question/dropdown-question.spec.js index 381f34890..249b00710 100644 --- a/src/common-components/dropdown-question/dropdown-question.spec.js +++ b/src/common-components/dropdown-question/dropdown-question.spec.js @@ -4,167 +4,156 @@ import dropdownQuestion from "./dropdown-question"; // Mock CMS content const questionText = "Question Text"; const mockMixin = { - methods: { - getCmsContent: jest.fn().mockImplementation(()=> { - return questionText; - }) - } -} + methods: { + getCmsContent: jest.fn().mockImplementation(() => { + return questionText; + }), + }, +}; // TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''" // It is not being used. describe("dropdownQuestion.vue", () => { + it("Should render a select input", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin], + }); - it("Should render a select input", async () => { + wrapper.getCmsContent = jest.fn(); - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - }, - mixins: [mockMixin] + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.exists()).toBe(true); }); - wrapper.getCmsContent = jest.fn(); + it("Should render the 'questionText' data value as the label text.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin], + }); - // Act - const select = wrapper.find("select"); + // Act + const label = wrapper.find("label"); - // Assert - expect(select.exists()).toBe(true); - - }); - - it("Should render the 'questionText' data value as the label text.", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - }, - mixins: [mockMixin] + // Assert + expect(label.text()).toContain(questionText); }); - // Act - const label = wrapper.find("label"); + it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + disableAutoFill: true, + }, + mixins: [mockMixin], + }); - // Assert - expect(label.text()).toContain(questionText); + // Mock CMS content ... + // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it + // Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools, + // you will see "Q⁠uestion T⁠ext" + const expectedQuestionText = "Q⁠uestion T⁠ext"; - }); + // Act + const label = wrapper.find("label"); - it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - disableAutoFill: true, - }, - mixins: [mockMixin] + // Assert + expect(label.text()).toContain(expectedQuestionText); }); - // Mock CMS content ... - // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it - // Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools, - // you will see "Q⁠uestion T⁠ext" - const expectedQuestionText = "Q⁠uestion T⁠ext"; + it("Should return input id as the id of the select field", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + inputId: "input ID", + options: {}, + }, + mixins: [mockMixin], + }); - // Act - const label = wrapper.find("label"); + // Act + const select = wrapper.find("select"); - // Assert - expect(label.text()).toContain(expectedQuestionText); - - }); - - it("Should return input id as the id of the select field", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - inputId: "input ID", - options: {}, - }, - mixins: [mockMixin] + // Assert + expect(select.attributes().id).toEqual("input ID"); }); - // Act - const select = wrapper.find("select"); + it("Should render the 'questionText' data value as the aria-label attribute.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin], + }); - // Assert - expect(select.attributes().id).toEqual("input ID"); + // Act + const label = wrapper.find("label"); - }); - - it("Should render the 'questionText' data value as the aria-label attribute.", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - }, - mixins: [mockMixin] + // Assert + expect(label.attributes("aria-label")).toContain(questionText); }); - // Act - const label = wrapper.find("label"); + it("Should return aria-disabled state as disabled", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + isDisabled: true, + }, + mixins: [mockMixin], + }); - // Assert - expect(label.attributes("aria-label")).toContain(questionText); + // Act + const select = wrapper.find("select"); - }); - - it("Should return aria-disabled state as disabled", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - isDisabled: true, - }, - mixins: [mockMixin] + // Assert + expect(select.attributes("aria-disabled")).toEqual("true"); }); - // Act - const select = wrapper.find("select"); + it("Should emit new value when modelValue is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: "val", + }, + mixins: [mockMixin], + }); - // Assert - expect(select.attributes("aria-disabled")).toEqual("true"); + // Act + await wrapper.find("select").setValue("val2"); - }); - - it("Should emit new value when modelValue is changed", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - modelValue: "val", - }, - mixins: [mockMixin] + // Assert + expect(wrapper.emitted()).toHaveProperty("change"); }); - // Act - await wrapper.find("select").setValue("val2"); + it("Should call this.handleChange with new value when selectedOption is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: 0, + }, + mixins: [mockMixin], + }); - // Assert - expect(wrapper.emitted()).toHaveProperty('change') + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); - }); + // Act + wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1); - it("Should call this.handleChange with new value when selectedOption is changed", async () => { - // Arrange - const wrapper = shallowMount(dropdownQuestion, { - propsData: { - options: {}, - modelValue: 0, - }, - mixins: [mockMixin] + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalled; }); - - wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); - - // Act - wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1); - - // Assert - expect(wrapper.vm.handleChange).toHaveBeenCalled; - - }); - }); diff --git a/src/common-components/dropdown-question/dropdown-question.vue b/src/common-components/dropdown-question/dropdown-question.vue index 8e6ae0faa..a940e1df8 100644 --- a/src/common-components/dropdown-question/dropdown-question.vue +++ b/src/common-components/dropdown-question/dropdown-question.vue @@ -1,152 +1,159 @@ - - diff --git a/src/common-components/funnel-footer/funnel-footer.spec.js b/src/common-components/funnel-footer/funnel-footer.spec.js index d246b602b..cd2a06663 100644 --- a/src/common-components/funnel-footer/funnel-footer.spec.js +++ b/src/common-components/funnel-footer/funnel-footer.spec.js @@ -2,43 +2,41 @@ import { mount } from "@vue/test-utils"; import funnelFooter from "./funnel-footer"; describe("funnel-footer.vue", () => { - - it("Should emit ForwardClicked on button click", async () => { - // Act - const wrapper = mount(funnelFooter, { - mixins: [mockMixin] + it("Should emit ForwardClicked on button click", async () => { + // Act + const wrapper = mount(funnelFooter, { + mixins: [mockMixin], + }); + wrapper.vm.buttonClick(); + // Assert + expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled; }); - wrapper.vm.buttonClick(); - // Assert - expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled; - }); - it("Should emit BackClicked on link click", async () => { - // Act - const wrapper = mount(funnelFooter, { - mixins: [mockMixin] + it("Should emit BackClicked on link click", async () => { + // Act + const wrapper = mount(funnelFooter, { + mixins: [mockMixin], + }); + wrapper.vm.linkClick(); + // Assert + expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled; }); - wrapper.vm.linkClick(); - // Assert - expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled; - }); - it("Should change button text when update button text is called", async () => { - // Act - const wrapper = mount(funnelFooter, { - mixins: [mockMixin] + it("Should change button text when update button text is called", async () => { + // Act + const wrapper = mount(funnelFooter, { + mixins: [mockMixin], + }); + wrapper.vm.updateButtonText("newText"); + + // Assert + expect(wrapper.componentVM.customButtontext).toBe("newText"); }); - wrapper.vm.updateButtonText('newText'); - - // Assert - expect(wrapper.componentVM.customButtontext).toBe('newText'); - }); - }); const mockMixin = { - methods: { - getCmsContent: jest.fn(), - getFooterInfoBoxHeight: jest.fn(()=>80) - } -} + methods: { + getCmsContent: jest.fn(), + getFooterInfoBoxHeight: jest.fn(() => 80), + }, +}; diff --git a/src/common-components/funnel-footer/funnel-footer.vue b/src/common-components/funnel-footer/funnel-footer.vue index 2c4152cfa..2a6119681 100644 --- a/src/common-components/funnel-footer/funnel-footer.vue +++ b/src/common-components/funnel-footer/funnel-footer.vue @@ -1,33 +1,31 @@ diff --git a/src/common-components/funnel-header/funnel-header.spec.js b/src/common-components/funnel-header/funnel-header.spec.js index a9b9535aa..380f5400c 100644 --- a/src/common-components/funnel-header/funnel-header.spec.js +++ b/src/common-components/funnel-header/funnel-header.spec.js @@ -2,25 +2,25 @@ import { shallowMount } from "@vue/test-utils"; import funnelHeader from "./funnel-header"; describe("funnelHeader", () => { - test("renders the logo image", () => { - // Arrange + test("renders the logo image", () => { + // Arrange - // Act - const wrapper = shallowMount(funnelHeader, { - setData: { - imageSrc: "image_url", - }, - mixins: [mockMixin] + // Act + const wrapper = shallowMount(funnelHeader, { + setData: { + imageSrc: "image_url", + }, + mixins: [mockMixin], + }); + + // Assert + expect(wrapper.find("img")).toBeTruthy(); + wrapper.unmount(); }); - - // Assert - expect(wrapper.find("img")).toBeTruthy(); - wrapper.unmount(); - }); }); const mockMixin = { - methods: { - getCmsContent: jest.fn() - } -} + methods: { + getCmsContent: jest.fn(), + }, +}; diff --git a/src/common-components/funnel-header/funnel-header.vue b/src/common-components/funnel-header/funnel-header.vue index dcc997c5f..f952b94a8 100644 --- a/src/common-components/funnel-header/funnel-header.vue +++ b/src/common-components/funnel-header/funnel-header.vue @@ -1,20 +1,18 @@ diff --git a/src/common-components/funnel-header/menu-modal/menu-modal.vue b/src/common-components/funnel-header/menu-modal/menu-modal.vue index 308f0cb0d..55ed98dd9 100644 --- a/src/common-components/funnel-header/menu-modal/menu-modal.vue +++ b/src/common-components/funnel-header/menu-modal/menu-modal.vue @@ -1,169 +1,206 @@ diff --git a/src/common-components/funnel-sub-header/button-back/button-back.spec.js b/src/common-components/funnel-sub-header/button-back/button-back.spec.js index c7bff87f0..403987233 100644 --- a/src/common-components/funnel-sub-header/button-back/button-back.spec.js +++ b/src/common-components/funnel-sub-header/button-back/button-back.spec.js @@ -2,20 +2,20 @@ import { shallowMount } from "@vue/test-utils"; import buttonBack from "./button-back"; describe("back button", () => { - test("renders a button", () => { - // Arrange - const myFunction = () => {}; + test("renders a button", () => { + // Arrange + const myFunction = () => {}; - // Act - const wrapper = shallowMount(buttonBack, { - propsData: { - backButtonAction: myFunction, - backButtonAccessibleText: "something", - }, + // Act + const wrapper = shallowMount(buttonBack, { + propsData: { + backButtonAction: myFunction, + backButtonAccessibleText: "something", + }, + }); + + // Assert + expect(wrapper.find("button").exists()).toBe(true); + wrapper.unmount(); }); - - // Assert - expect(wrapper.find("button").exists()).toBe(true); - wrapper.unmount(); - }); }); diff --git a/src/common-components/funnel-sub-header/button-back/button-back.vue b/src/common-components/funnel-sub-header/button-back/button-back.vue index cf3a630bf..75121a4e7 100644 --- a/src/common-components/funnel-sub-header/button-back/button-back.vue +++ b/src/common-components/funnel-sub-header/button-back/button-back.vue @@ -1,82 +1,71 @@ diff --git a/src/common-components/funnel-sub-header/funnel-sub-header.spec.js b/src/common-components/funnel-sub-header/funnel-sub-header.spec.js index ebcb9ca91..51e622bb6 100644 --- a/src/common-components/funnel-sub-header/funnel-sub-header.spec.js +++ b/src/common-components/funnel-sub-header/funnel-sub-header.spec.js @@ -2,20 +2,20 @@ import { shallowMount } from "@vue/test-utils"; import FunnelSubHeader from "./funnel-sub-header"; describe("FunnelSubHeader.vue", () => { - it("Should render the 'text' data value as a span value for the header span text value.", async () => { - // Act - const wrapper = shallowMount(FunnelSubHeader, { - mixins: [mockMixin] - }); - wrapper.vm.clickEvent(); + it("Should render the 'text' data value as a span value for the header span text value.", async () => { + // Act + const wrapper = shallowMount(FunnelSubHeader, { + mixins: [mockMixin], + }); + wrapper.vm.clickEvent(); - // Assert - expect(wrapper.emitted()).toEqual({"click-event": [[]]}); - }); + // Assert + expect(wrapper.emitted()).toEqual({ "click-event": [[]] }); + }); }); const mockMixin = { - methods: { - getCmsContent: jest.fn() - } -} + methods: { + getCmsContent: jest.fn(), + }, +}; diff --git a/src/common-components/funnel-sub-header/funnel-sub-header.vue b/src/common-components/funnel-sub-header/funnel-sub-header.vue index 3ad7c71d3..ba977c55a 100644 --- a/src/common-components/funnel-sub-header/funnel-sub-header.vue +++ b/src/common-components/funnel-sub-header/funnel-sub-header.vue @@ -1,79 +1,80 @@ diff --git a/src/common-components/loading-modal/loading-modal.spec.js b/src/common-components/loading-modal/loading-modal.spec.js index 7a500ce73..36a6d6e33 100644 --- a/src/common-components/loading-modal/loading-modal.spec.js +++ b/src/common-components/loading-modal/loading-modal.spec.js @@ -4,44 +4,42 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js"; import store from "@/store"; jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } + "@/store", + () => { + return {}; + }, + { virtual: true } ); -jest.mock('@/assets/img/loader.gif', () => 'loader.gif') -jest.mock('@/assets/img/windshield.png', () => 'windshield.png') +jest.mock("@/assets/img/loader.gif", () => "loader.gif"); +jest.mock("@/assets/img/windshield.png", () => "windshield.png"); describe("loadingModal", () => { - test("showModal sets modal visible", async () => { - // Arrange - const { wrapper } = setupMocks(); - wrapper.vm.isModalVisible = false; + test("showModal sets modal visible", async () => { + // Arrange + const { wrapper } = setupMocks(); + wrapper.vm.isModalVisible = false; - //Act - wrapper.vm.showModal(); - - // Assert - expect(wrapper.vm.isModalVisible).toEqual(true); - wrapper.unmount(); - }); + //Act + wrapper.vm.showModal(); + + // Assert + expect(wrapper.vm.isModalVisible).toEqual(true); + wrapper.unmount(); + }); }); - function setupMocks() { + //Mock store + store.dispatch = jest.fn(() => {}); + store.getters = {}; + const mountOptions = getMountOptions({ + store: { + dispatch: store.dispatch, + getters: store.getters, + }, + }); - //Mock store - store.dispatch = jest.fn(() => {}); - store.getters = { }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); - - const wrapper = shallowMount(loadingModal, mountOptions); - return { wrapper }; -} \ No newline at end of file + const wrapper = shallowMount(loadingModal, mountOptions); + return { wrapper }; +} diff --git a/src/common-components/loading-modal/loading-modal.vue b/src/common-components/loading-modal/loading-modal.vue index 2bcdc9c31..8e4d1d994 100644 --- a/src/common-components/loading-modal/loading-modal.vue +++ b/src/common-components/loading-modal/loading-modal.vue @@ -1,236 +1,250 @@ diff --git a/src/common-components/modal/modal.spec.js b/src/common-components/modal/modal.spec.js index 717b6f895..88d5daf58 100644 --- a/src/common-components/modal/modal.spec.js +++ b/src/common-components/modal/modal.spec.js @@ -1,61 +1,60 @@ import { shallowMount } from "@vue/test-utils"; import Modal from "./modal"; - describe("modal.vue", () => { - it("Should display header text when HeaderText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin] + it("Should display header text when HeaderText is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(Modal, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['HeaderText'])); - }); - it("Should display subheader text when SubheaderText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin] + it("Should display subheader text when SubheaderText is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(Modal, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['SubheaderText'])); - }); - it("Should insert image url when Image is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin] + it("Should insert image url when Image is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(Modal, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['Image'])); - }); - it("Should display body text when BodyText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin] + it("Should display body text when BodyText is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(Modal, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['BodyText'])); - }); - it("Should display footer text when FooterText is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(Modal, { - mixins: [mockMixin] + it("Should display footer text when FooterText is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(Modal, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["FooterText"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['FooterText'])); - }); }); const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }) - } -} + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return mockCmsContent[cmsFieldName]; + }), + }, +}; const mockCmsContent = { - 'HeaderText': "Sample header text here.", - 'SubheaderText': "Sample subheader text here.", - 'Image': "https://www.sampleImage.sample", - 'BodyText': "Sample body text here.", - 'FooterText': "Sample footer text here.", -} + HeaderText: "Sample header text here.", + SubheaderText: "Sample subheader text here.", + Image: "https://www.sampleImage.sample", + BodyText: "Sample body text here.", + FooterText: "Sample footer text here.", +}; diff --git a/src/common-components/modal/modal.vue b/src/common-components/modal/modal.vue index 04f99f0df..12055ed05 100644 --- a/src/common-components/modal/modal.vue +++ b/src/common-components/modal/modal.vue @@ -1,108 +1,120 @@ diff --git a/src/common-components/question-chain/question-chain.vue b/src/common-components/question-chain/question-chain.vue index 40d8be911..6121cbd25 100644 --- a/src/common-components/question-chain/question-chain.vue +++ b/src/common-components/question-chain/question-chain.vue @@ -2,17 +2,16 @@
+ :validationRules="validationRules" />
@@ -22,61 +21,65 @@ import buttonQuestion from "@/common-components/button-question/button-question" import { useValidateForm } from "vee-validate"; export default { - name: "questionChain", - data() { - return { - currentQuestionNum: 0, - questions: [], - }; - }, - props: { - questionData: Object, - validationRules: String, - modelValue: Array, - glassIndex: Number, - }, - async created() { - // do a test validation check upon create to prevent out of sync / incorrect valid states - await useValidateForm(); // NOTE: needs to have async/await here; tested and won't work without it - - this.questionData.map((q, i) => { - const question = { - questionText: q.questionText, - questionSequence: q.questionSequence, - answers: q.answers.map((a) => { - return { - buttonLabel: a.answerText, - // Name will either be nextQuestionSequence or answerResult - // Name will be used by list-button as the input value. - // It must be a single string or number, so concatenating together a string with - // 4 pieces of data separated by pipe characters: - // question number|type of answer|answer value|answer text - value: a.nextQuestionSequence ? - q.questionSequence + "|nextQuestion|" + a.nextQuestionSequence + "|" + a.answerText : - q.questionSequence + "|answer|" + a.answerResult + "|" + a.answerText, - nextQuestionSequence: a.nextQuestionSequence, - answerResult: a.answerResult, - questionSequence: q.questionSequence, - questionType: a.nextQuestionSequence ? "nextQuestion" : "answer", - } - }), - answerSelected: q.answerSelected || "", + name: "questionChain", + data() { + return { + currentQuestionNum: 0, + questions: [], }; - if (!q.suppressQuestion) { - this.questions.push(question); - } - }); + }, + props: { + questionData: Object, + validationRules: String, + modelValue: Array, + glassIndex: Number, + }, + async created() { + // do a test validation check upon create to prevent out of sync / incorrect valid states + await useValidateForm(); // NOTE: needs to have async/await here; tested and won't work without it - if (!this.modelValue?.length > 0 && this.questions.length > 0) { - // set this.currentQuestionNum to first valid question - this.currentQuestionNum = this.questions[0].questionSequence; - // scroll the next question into view - this.$nextTick(() => { - document.querySelector('.current-question')?.scrollIntoView({behavior: "smooth"}); - }) - } - }, - methods: { + this.questionData.map((q, i) => { + const question = { + questionText: q.questionText, + questionSequence: q.questionSequence, + answers: q.answers.map((a) => { + return { + buttonLabel: a.answerText, + // Name will either be nextQuestionSequence or answerResult + // Name will be used by list-button as the input value. + // It must be a single string or number, so concatenating together a string with + // 4 pieces of data separated by pipe characters: + // question number|type of answer|answer value|answer text + value: a.nextQuestionSequence + ? q.questionSequence + + "|nextQuestion|" + + a.nextQuestionSequence + + "|" + + a.answerText + : q.questionSequence + "|answer|" + a.answerResult + "|" + a.answerText, + nextQuestionSequence: a.nextQuestionSequence, + answerResult: a.answerResult, + questionSequence: q.questionSequence, + questionType: a.nextQuestionSequence ? "nextQuestion" : "answer", + }; + }), + answerSelected: q.answerSelected || "", + }; + if (!q.suppressQuestion) { + this.questions.push(question); + } + }); + + if (!this.modelValue?.length > 0 && this.questions.length > 0) { + // set this.currentQuestionNum to first valid question + this.currentQuestionNum = this.questions[0].questionSequence; + // scroll the next question into view + this.$nextTick(() => { + document.querySelector(".current-question")?.scrollIntoView({ behavior: "smooth" }); + }); + } + }, + methods: { handleAnswer(question, returnedAnswer) { question.answerSelected = returnedAnswer; /* @@ -93,8 +96,11 @@ export default { this.$emit("update:modelValue", isQuestionChainComplete); } }, - getQuestionChainAnswerIfComplete(returnedAnswer) { // this method will return either a final answer or Boolean false - if (!returnedAnswer) { return false } + getQuestionChainAnswerIfComplete(returnedAnswer) { + // this method will return either a final answer or Boolean false + if (!returnedAnswer) { + return false; + } // Example returnedAnswers: // "1|nextQuestion|3|No" @@ -116,7 +122,7 @@ export default { } // remove all answers AFTER this question... // (needed in case user is changing previously answered questions) - if ((q.questionSequence > questionNum)) { + if (q.questionSequence > questionNum) { delete q.answerSelected; } if (q.answerSelected) { @@ -130,27 +136,25 @@ export default { // return false if there's a nextQuestion... or return an object with final answers (truthy) if (questionType === "nextQuestion") { - // update to next question index this.currentQuestionNum = parseInt(questionAnswer); // update count to display next question // scroll the next question into view this.$nextTick(() => { - document.querySelector('.current-question').scrollIntoView({behavior: "smooth"}); - }) + document + .querySelector(".current-question") + .scrollIntoView({ behavior: "smooth" }); + }); return false; - } else { - // reset current question index (removes .current-question class) this.currentQuestionNum = 0; // reset count - + // return an object with the part answer, all the answered questions, and the part index return { answerResult: questionAnswer, answeredQuestions: answeredQuestions, glassIndex: this.glassIndex, }; - } }, }, diff --git a/src/common-components/text-block/text-block.spec.js b/src/common-components/text-block/text-block.spec.js index 138a0340b..3cd229449 100644 --- a/src/common-components/text-block/text-block.spec.js +++ b/src/common-components/text-block/text-block.spec.js @@ -1,60 +1,59 @@ import { shallowMount } from "@vue/test-utils"; import TextBlock from "./text-block"; - describe("modal.vue", () => { - it("Should display 'Text' when 'Text' is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin] + it("Should display 'Text' when 'Text' is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Text"])); }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['Text'])); - }); - it("Should contain the typeStyle class as defined by the prop", async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['typeStyle'])); - }); - it("Should contain the justifyText class as defined by the prop", async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['justifyText'])); - }); - it("Should contain the fontWeight class as defined by the prop", async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['fontWeight'])); - }); + it("Should contain the typeStyle class as defined by the prop", async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps, + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps["typeStyle"])); + }); + it("Should contain the justifyText class as defined by the prop", async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps, + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps["justifyText"])); + }); + it("Should contain the fontWeight class as defined by the prop", async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps, + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps["fontWeight"])); + }); }); - /////////////// - // Constants // - /////////////// +/////////////// +// Constants // +/////////////// const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }) - } -} + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return mockCmsContent[cmsFieldName]; + }), + }, +}; const mockProps = { - fontWeight: 'mockFontWeight', - typeStyle: 'mockTypeStyle', - justifyText: 'mockJustifyText' -} + fontWeight: "mockFontWeight", + typeStyle: "mockTypeStyle", + justifyText: "mockJustifyText", +}; const mockCmsContent = { - 'Text': "Sample text here.", -} + Text: "Sample text here.", +}; diff --git a/src/common-components/text-block/text-block.vue b/src/common-components/text-block/text-block.vue index 88f3bda2a..a12d3f398 100644 --- a/src/common-components/text-block/text-block.vue +++ b/src/common-components/text-block/text-block.vue @@ -1,38 +1,40 @@ diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index b830b9783..54e23e869 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -4,167 +4,157 @@ import textboxQuestion from "./textbox-question"; // Mock CMS content const questionText = "Question Text"; const mockMixin = { - methods: { - getCmsContent: jest.fn().mockImplementation(()=> { - return questionText; - }) - } -} + methods: { + getCmsContent: jest.fn().mockImplementation(() => { + return questionText; + }), + }, +}; const maska = jest.fn(); describe("textboxQuestion.vue", () => { + it("Should render a text input", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + mixins: [mockMixin], + }); - it("Should render a text input", async () => { - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - mixins: [mockMixin] + wrapper.getCmsContent = jest.fn(); + + // Act + const input = wrapper.find("input"); + + // Assert + expect(input.exists()).toBe(true); }); - wrapper.getCmsContent = jest.fn(); + it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + mixins: [mockMixin], + }); - // Act - const input = wrapper.find("input"); + // Act + const label = wrapper.find("label"); - // Assert - expect(input.exists()).toBe(true); - - }); - - it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => { - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - mixins: [mockMixin] + // Assert + expect(label.text()).toContain(questionText); }); - // Act - const label = wrapper.find("label"); + it("Should return input id as the id of the input field", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + inputId: "input ID", + }, + mixins: [mockMixin], + }); - // Assert - expect(label.text()).toContain(questionText); + // Act + const input = wrapper.find("input"); - }); - - it("Should return input id as the id of the input field", async () => { - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - inputId: "input ID", - }, - mixins: [mockMixin] + // Assert + expect(input.attributes().id).toEqual("input ID"); }); - // Act - const input = wrapper.find("input"); + it("Should render the 'questionText' data value as the aria-label attribute.", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + mixins: [mockMixin], + }); - // Assert - expect(input.attributes().id).toEqual("input ID"); + // Act + const label = wrapper.find("label"); - }); - - it("Should render the 'questionText' data value as the aria-label attribute.", async () => { - - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - mixins: [mockMixin] + // Assert + expect(label.attributes("aria-label")).toContain(questionText); }); - // Act - const label = wrapper.find("label"); + it("Should return aria-disabled state as disabled", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + isDisabled: true, + }, + mixins: [mockMixin], + }); - // Assert - expect(label.attributes("aria-label")).toContain(questionText); + // Assert + const input = wrapper.find("input"); - }); - - it("Should return aria-disabled state as disabled", async () => { - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - isDisabled: true, - }, - mixins: [mockMixin] + // Expect + expect(input.attributes("aria-disabled")).toEqual("true"); }); - // Assert - const input = wrapper.find("input"); + it("Should emit new value when modelValue is changed", async () => { + // Act + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: "val", + }, + mixins: [mockMixin], + }); - // Expect - expect(input.attributes("aria-disabled")).toEqual("true"); + await wrapper.find("input").setValue("val2"); - }); - - it("Should emit new value when modelValue is changed", async () => { - // Act - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - modelValue: "val", - }, - mixins: [mockMixin] + // Assert + expect(wrapper.emitted()).toHaveProperty("change"); }); - await wrapper.find("input").setValue("val2"); + it("Should call this.handleChange with new value when the value is changed and the new value is valid", async () => { + // Arrange + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + options: {}, + modelValue: "foo", + }, + mixins: [mockMixin], + }); - // Assert - expect(wrapper.emitted()).toHaveProperty('change') + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + wrapper.vm.validate = jest.fn().mockImplementation(() => { + return true; + }); - }); + // Act + wrapper.vm.$options.watch.value.call(wrapper.vm, "bar"); - it("Should call this.handleChange with new value when the value is changed and the new value is valid", async () => { - // Arrange - const wrapper = shallowMount(textboxQuestion, { - global: { - directives: { - maska: maska, - } - }, - propsData: { - options: {}, - modelValue: "foo", - }, - mixins: [mockMixin] + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalled; }); - - wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); - wrapper.vm.validate = jest.fn().mockImplementation(() => { - return true; - }); - - // Act - wrapper.vm.$options.watch.value.call(wrapper.vm, "bar"); - - // Assert - expect(wrapper.vm.handleChange).toHaveBeenCalled; - - }); - }); diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 34fc614e7..62b605b7b 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -1,189 +1,195 @@ diff --git a/src/common-components/vehicle-banner/vehicle-banner.spec.js b/src/common-components/vehicle-banner/vehicle-banner.spec.js index e97781fc3..b4d723e18 100644 --- a/src/common-components/vehicle-banner/vehicle-banner.spec.js +++ b/src/common-components/vehicle-banner/vehicle-banner.spec.js @@ -5,107 +5,121 @@ import store from "@/store"; import { vehicleCategories } from "@/constants/vehicle-categories.js"; jest.mock( - "@/store", - () => { - return {}; - }, - { virtual: true } + "@/store", + () => { + return {}; + }, + { virtual: true } ); describe("vehicleBanner", () => { - test("renders the blurrycar image", async () => { - // Arrange - const { wrapper } = setupMocks({ displayGenericVehicleImageProp: true, imageUrlValue: "NULL" }); - - // Assert - expect(wrapper.vm.vehicleImageToDisplay).toEqual(wrapper.vm.genericVehicleImage); - expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); - wrapper.unmount(); - }); + test("renders the blurrycar image", async () => { + // Arrange + const { wrapper } = setupMocks({ + displayGenericVehicleImageProp: true, + imageUrlValue: "NULL", + }); + + // Assert + expect(wrapper.vm.vehicleImageToDisplay).toEqual(wrapper.vm.genericVehicleImage); + expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); + wrapper.unmount(); + }); }); describe("vehicleBanner", () => { - test("renders expected vehicle image", async () => { - // Arrange - const { wrapper } = setupMocks({ displayGenericVehicleImageProp: false, imageUrlValue: "url_to_vehicle_image" }); + test("renders expected vehicle image", async () => { + // Arrange + const { wrapper } = setupMocks({ + displayGenericVehicleImageProp: false, + imageUrlValue: "url_to_vehicle_image", + }); - // Assert - expect(wrapper.vm.vehicleImageToDisplay).toEqual( "url_to_vehicle_image"); - expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); - wrapper.unmount(); - }); + // Assert + expect(wrapper.vm.vehicleImageToDisplay).toEqual("url_to_vehicle_image"); + expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); + wrapper.unmount(); + }); }); describe("vehicleBanner", () => { - test("should render car icon when imageUrl is null and category is default", async () => { - // Arrange - const { wrapper } = setupMocks({ displayGenericVehicleImageProp: false, imageUrlValue: "NULL" }); - - var iconUrl = wrapper.vm.vehicleImageToDisplay; + test("should render car icon when imageUrl is null and category is default", async () => { + // Arrange + const { wrapper } = setupMocks({ + displayGenericVehicleImageProp: false, + imageUrlValue: "NULL", + }); - // Assert - expect(iconUrl).toEqual(undefined); - wrapper.unmount(); - }); + var iconUrl = wrapper.vm.vehicleImageToDisplay; + + // Assert + expect(iconUrl).toEqual(undefined); + wrapper.unmount(); + }); }); -const params = [["CAR", "car_icon_url"], - ["TRUCK", "truck_icon_url"], - ["VAN", "van_icon_url"], - ["COMMERCIAL VAN", "commercial_van_icon_url"], - ["SUV", "suv_icon_url"], - ["OTHER", "car_icon_url"]]; +const params = [ + ["CAR", "car_icon_url"], + ["TRUCK", "truck_icon_url"], + ["VAN", "van_icon_url"], + ["COMMERCIAL VAN", "commercial_van_icon_url"], + ["SUV", "suv_icon_url"], + ["OTHER", "car_icon_url"], +]; describe("vehicleBanner", () => { - test.each(params)("renders an icon instead of an image for %s and %s", async (category, expectedIcon) => { - // Arrange - const { wrapper, cmsContent } = setupMocks({ displayGenericVehicleImageProp: false, imageUrlValue: expectedIcon, categoryValue: category }); - //Act - var vehicleIcon = wrapper.vm.getUnmatchedVehicleIcon(); - // Assert - expect(store.getters.vehicle.category).toEqual(category); - expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); - wrapper.unmount(); - }); + test.each(params)( + "renders an icon instead of an image for %s and %s", + async (category, expectedIcon) => { + // Arrange + const { wrapper, cmsContent } = setupMocks({ + displayGenericVehicleImageProp: false, + imageUrlValue: expectedIcon, + categoryValue: category, + }); + //Act + var vehicleIcon = wrapper.vm.getUnmatchedVehicleIcon(); + // Assert + expect(store.getters.vehicle.category).toEqual(category); + expect(wrapper.find("img").attributes("class")).toContain("vehicle-image"); + wrapper.unmount(); + } + ); }); -function setupMocks({ - displayGenericVehicleImageProp, - imageUrlValue, - categoryValue = "CAR" -}) { - const mockGetCmsContent = jest.fn(); - mockGetCmsContent((cmsWidget, field) => { - return field - }); - const mockMixin = { - methods: { - getCmsContent: mockGetCmsContent - } - } - //Mock store - store.dispatch = jest.fn(() => {}); - store.getters = { vehicle: { category: categoryValue, imageUrl: imageUrlValue } }; - const mountOptions = getMountOptions({ - store: { - dispatch: store.dispatch, - getters: store.getters, - }, - }); +function setupMocks({ displayGenericVehicleImageProp, imageUrlValue, categoryValue = "CAR" }) { + const mockGetCmsContent = jest.fn(); + mockGetCmsContent((cmsWidget, field) => { + return field; + }); + const mockMixin = { + methods: { + getCmsContent: mockGetCmsContent, + }, + }; + //Mock store + store.dispatch = jest.fn(() => {}); + store.getters = { vehicle: { category: categoryValue, imageUrl: imageUrlValue } }; + const mountOptions = getMountOptions({ + store: { + dispatch: store.dispatch, + getters: store.getters, + }, + }); - //Mock props - mountOptions.propsData = { displayGenericVehicleImage: displayGenericVehicleImageProp }; - mountOptions.mixins = [mockMixin]; - const wrapper = shallowMount(vehicleBanner, mountOptions); + //Mock props + mountOptions.propsData = { displayGenericVehicleImage: displayGenericVehicleImageProp }; + mountOptions.mixins = [mockMixin]; + const wrapper = shallowMount(vehicleBanner, mountOptions); - //Mock CMS content - const cmsContent = { - GenericVehicleImage: "image_url", - CarUnmatchedVehicleIcon: "car_icon_url", - TruckUnmatchedVehicleIcon: "truck_icon_url", - VanUnmatchedVehicleIcon: "van_icon_url", - CommercialVanUnmatchedVehicleIcon: "commercial_van_icon_url", - SuvUnmatchedVehicleIcon: "suv_icon_url", - }; - return { wrapper, cmsContent }; + //Mock CMS content + const cmsContent = { + GenericVehicleImage: "image_url", + CarUnmatchedVehicleIcon: "car_icon_url", + TruckUnmatchedVehicleIcon: "truck_icon_url", + VanUnmatchedVehicleIcon: "van_icon_url", + CommercialVanUnmatchedVehicleIcon: "commercial_van_icon_url", + SuvUnmatchedVehicleIcon: "suv_icon_url", + }; + return { wrapper, cmsContent }; } diff --git a/src/common-components/vehicle-banner/vehicle-banner.vue b/src/common-components/vehicle-banner/vehicle-banner.vue index 3435efab9..8f7be0179 100644 --- a/src/common-components/vehicle-banner/vehicle-banner.vue +++ b/src/common-components/vehicle-banner/vehicle-banner.vue @@ -1,80 +1,79 @@ diff --git a/src/constants/analytics.js b/src/constants/analytics.js index 7ba9ef78c..eed7da2fe 100644 --- a/src/constants/analytics.js +++ b/src/constants/analytics.js @@ -1,36 +1,36 @@ const analyticsPageEvents = { - ENTRY: "ENTRY", - EVENT: "EVENT" + ENTRY: "ENTRY", + EVENT: "EVENT", }; // GA Constants const GaEvents = { - GENERIC_EVENT: 'event', - PAGE_VIEW_EVENT : 'logPageview' + GENERIC_EVENT: "event", + PAGE_VIEW_EVENT: "logPageview", }; const GaCategories = { - API_RESPONSE: 'Api_Response', - EVOX: 'Evox' + API_RESPONSE: "Api_Response", + EVOX: "Evox", }; const GaActions = { - RESULT: 'Result', - CLICKED: 'Clicked', - VIF: 'vif', - SUBMITTED: 'Submitted', + RESULT: "Result", + CLICKED: "Clicked", + VIF: "vif", + SUBMITTED: "Submitted", }; const GaLabels = { - SUCCESS: 'Success', - ERROR: 'Error', - LICENSE_PLATE_LOOKUP: 'License_Plate_Look_Up', - VIN_LOOKUP: 'Vin_Look_Up', - ADDRESS_LOOKUP: 'Address_Look_up', + SUCCESS: "Success", + ERROR: "Error", + LICENSE_PLATE_LOOKUP: "License_Plate_Look_Up", + VIN_LOOKUP: "Vin_Look_Up", + ADDRESS_LOOKUP: "Address_Look_up", }; const ValueToLogTypes = { - LAST_5: "last_5", + LAST_5: "last_5", }; export { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes }; diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 0e185cff4..f4840a91a 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -1,14 +1,13 @@ - const applicationConfig = { - CONSUMER_CF_DISTRO: process.env.VUE_APP_CONSUMER_CF_DISTRO, - GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY, - ANALYTICS_SESSION_TIMEOUT_MINUTES: 30, - SAVED_SESSION_TIMEOUT_DAYS: 45, - COOKIE_PATH: "/", - CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" - APPLICATION_NAME: "FixMyGlass", - APPLICATION_ABBREVIATION: "fmg", - SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass" + CONSUMER_CF_DISTRO: process.env.VUE_APP_CONSUMER_CF_DISTRO, + GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY, + ANALYTICS_SESSION_TIMEOUT_MINUTES: 30, + SAVED_SESSION_TIMEOUT_DAYS: 45, + COOKIE_PATH: "/", + CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" + APPLICATION_NAME: "FixMyGlass", + APPLICATION_ABBREVIATION: "fmg", + SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass", }; -export { applicationConfig }; \ No newline at end of file +export { applicationConfig }; diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js index f4b4aaa9d..5fab52899 100644 --- a/src/constants/cookie-names.js +++ b/src/constants/cookie-names.js @@ -1,13 +1,12 @@ -import { applicationConfig } from "@/constants/application-config.js" +import { applicationConfig } from "@/constants/application-config.js"; const cookieNames = { FUNNEL_SESSION_INFO: `FunnelSessionInfo-${applicationConfig.CURRENT_ENVIRONMENT}`, - + // Existing Safelite.com cookies DXDEV: "dxdev", SESSION_ID: "sid", - SESSION_KEY: "skey" + SESSION_KEY: "skey", }; - + export { cookieNames }; - \ No newline at end of file diff --git a/src/constants/damage-locations-cms.js b/src/constants/damage-locations-cms.js index c4787a598..82a431756 100644 --- a/src/constants/damage-locations-cms.js +++ b/src/constants/damage-locations-cms.js @@ -4,6 +4,6 @@ const damageLocationsCms = { REARWINDOW: "REARWINDOW", DRIVERSIDE: "DRIVERSIDE", PASSENGERSIDE: "PASSENGERSIDE", - }; - - export { damageLocationsCms }; \ No newline at end of file +}; + +export { damageLocationsCms }; diff --git a/src/constants/damage-locations-selected.js b/src/constants/damage-locations-selected.js index 905d9c8c5..7ede615cb 100644 --- a/src/constants/damage-locations-selected.js +++ b/src/constants/damage-locations-selected.js @@ -15,7 +15,7 @@ const damageLocationsSelected = { DRIVERSIDE: "DriverSide", PASSENGERSIDE: "PassengerSide", STATIONARY: "Stationary", - SLIDER: "Slider" - }; - - export { damageLocationsSelected }; \ No newline at end of file + SLIDER: "Slider", +}; + +export { damageLocationsSelected }; diff --git a/src/constants/dynamic-strings.js b/src/constants/dynamic-strings.js index c526e45a9..ff62dfaa3 100644 --- a/src/constants/dynamic-strings.js +++ b/src/constants/dynamic-strings.js @@ -1,7 +1,7 @@ const dynamicStrings = { GLOBAL_STATE: "globalState", CUSTOM: "custom", - ROUTER_LINK: "routerLink:" - }; - - export { dynamicStrings }; \ No newline at end of file + ROUTER_LINK: "routerLink:", +}; + +export { dynamicStrings }; diff --git a/src/constants/dynamictext-mapper.js b/src/constants/dynamictext-mapper.js index d47ef9d02..9191c8781 100644 --- a/src/constants/dynamictext-mapper.js +++ b/src/constants/dynamictext-mapper.js @@ -4,29 +4,28 @@ const customMappings = { formattedglassname: [ - { key: 'Windshield Single', transformedValue: 'windshield' }, - { key: 'Windshield Driver', transformedValue: 'driver side split windshield' }, - { key: 'Windshield Passenger', transformedValue: 'passenger side split windshield' }, - { key: 'Rear Stationary', transformedValue: 'rear window' }, - { key: 'Rear Slider', transformedValue: 'rear window' }, - { key: 'Driver Front', transformedValue: 'driver side front door' }, - { key: 'Driver Back', transformedValue: 'driver side back door' }, - { key: 'Driver Vent', transformedValue: 'driver side vent glass' }, - { key: 'Driver Quarter', transformedValue: 'driver side quarter panel' }, - { key: 'Driver SideDoor', transformedValue: 'driver side sliding door' }, - { key: 'Passenger Front', transformedValue: 'passenger side front door' }, - { key: 'Passenger Back', transformedValue: 'passenger side back door' }, - { key: 'Passenger Vent', transformedValue: 'passenger side vent glass' }, - { key: 'Passenger Quarter', transformedValue: 'passenger side quarter panel' }, - { key: 'Passenger SlideDoor', transformedValue: 'passenger side sliding door' }, - ] -} + { key: "Windshield Single", transformedValue: "windshield" }, + { key: "Windshield Driver", transformedValue: "driver side split windshield" }, + { key: "Windshield Passenger", transformedValue: "passenger side split windshield" }, + { key: "Rear Stationary", transformedValue: "rear window" }, + { key: "Rear Slider", transformedValue: "rear window" }, + { key: "Driver Front", transformedValue: "driver side front door" }, + { key: "Driver Back", transformedValue: "driver side back door" }, + { key: "Driver Vent", transformedValue: "driver side vent glass" }, + { key: "Driver Quarter", transformedValue: "driver side quarter panel" }, + { key: "Driver SideDoor", transformedValue: "driver side sliding door" }, + { key: "Passenger Front", transformedValue: "passenger side front door" }, + { key: "Passenger Back", transformedValue: "passenger side back door" }, + { key: "Passenger Vent", transformedValue: "passenger side vent glass" }, + { key: "Passenger Quarter", transformedValue: "passenger side quarter panel" }, + { key: "Passenger SlideDoor", transformedValue: "passenger side sliding door" }, + ], +}; // Gets an instance of a string where the dynamic portion of the text {custom:KeyName} -// is replaced by a value from the above map. +// is replaced by a value from the above map. // If the value isn't found, return the original dynamic string without replacement export function getCustomTransformValue(dynamicString, key) { - // Get array key from the dynamic string const regexExp = new RegExp("{(.*?):(.*?)}", "g"); const matches = [...dynamicString.matchAll(regexExp)]; @@ -39,19 +38,19 @@ export function getCustomTransformValue(dynamicString, key) { // Get the array of possible values based on the key name. const transformArray = customMappings[arrayKey.toLowerCase()]; - - if(transformArray === undefined) { + + if (transformArray === undefined) { return dynamicString; } // Get the value where the name matches the key name, there should only be one so find() is used. - const mapObject = transformArray.find(map => map.key.toLowerCase() === key.toLowerCase()); + const mapObject = transformArray.find((map) => map.key.toLowerCase() === key.toLowerCase()); - if(mapObject === undefined){ + if (mapObject === undefined) { return dynamicString; } const finalString = dynamicString.replace(`{custom:${arrayKey}}`, mapObject.transformedValue); - return finalString -} \ No newline at end of file + return finalString; +} diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 26be43031..0fade12fd 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,108 +1,111 @@ const endpoints = { - GetRouteInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, - method: "POST", - }, - GetHomepageInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, - method: "GET", - }, - GetPageData: { - url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, - method: "GET", - }, - GetVehicleYears: { - url: "/vehicle/api/v1/vehicle/years", - method: "GET", - }, - GetVehicleMakes: { - url: "/vehicle/api/v1/vehicle/Makes", - method: "GET", - }, - GetVehicleModels: { - url: "/vehicle/api/v1/vehicle/Models", - method: "GET", - }, - GetVehicleStyles: { - url: "/vehicle/api/v1/vehicle/Styles", - method: "GET", - }, - GetVehicle: { - url: "/vehicle/api/v1/vehicle/lookup", - method: "GET", - }, - GetDamageOptions: { - url: "/parts/api/v1/parts/damage-options", - method: "GET", - }, - LookupVehicleByYmms: { - url: "/vehicle/api/v1/vehicle/Lookup", - method: "GET", - }, - LookupVehicleByVin: { - url: "/vehicle/api/v1/vehicle/Lookup", - method: "POST", - }, - LookupVinByPlate: { - url: "/vehicle/api/v1/vehicle/lookup-vin-by-plate", - method: "POST", - }, - LookupVinByAddress: { - url: "/vehicle/api/v1/vehicle/lookup-vin-by-address", - method: "POST", - }, - GetPartsOrQuestions: { - url: "/parts/api/v1/parts/parts-or-questions", - method: "POST", - }, - GetParts: { - url: "/parts/api/v1/parts/parts", - method: "POST", - }, - GetCapabilityQuestions: { - url: "/parts/api/v1/parts/capability-questions", - method: "GET" - }, - GetPartFromCapabilityAnswer: { - url: "/parts/api/v1/parts/part-from-capability-answer", - method: "POST" - }, - SaveSession: { - url: "/order/api/v1/order/save-session", - method: "POST", - }, - LoadSession: { - url: "/order/api/v1/order/load-session", - method: "POST", - }, - ValidateZip: { - url: "/location/api/v1/location/zip", - method: "GET", - }, - LogExperimentExposureIfAssigned:{ - url: "/experiments/api/v1/experiments/log-exposure", - method: "POST", - }, - LogPageView:{ - url: "/analytics/api/v1/analytics/log-page-view", - method: "POST", - }, - LogCustomEvent:{ - url: "/analytics/api/v1/analytics/log-custom-event", - method: "POST", - }, - InitializeSession:{ - url: "/analytics/api/v1/analytics/initialize", - method: "POST", - }, - GetExperimentsByUser: { - url: "/analytics/api/v1/analytics/get-experiments", - method: "GET", - }, - RunExperimentsForTrigger: { - url: "/experiments/api/v1/experiments/run", - method: "POST" - } + GetRouteInfo: { + url: (applicationAbbreviation) => + `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, + method: "POST", + }, + GetHomepageInfo: { + url: (applicationAbbreviation) => + `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + method: "GET", + }, + GetPageData: { + url: (applicationAbbreviation, pageName) => + `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, + method: "GET", + }, + GetVehicleYears: { + url: "/vehicle/api/v1/vehicle/years", + method: "GET", + }, + GetVehicleMakes: { + url: "/vehicle/api/v1/vehicle/Makes", + method: "GET", + }, + GetVehicleModels: { + url: "/vehicle/api/v1/vehicle/Models", + method: "GET", + }, + GetVehicleStyles: { + url: "/vehicle/api/v1/vehicle/Styles", + method: "GET", + }, + GetVehicle: { + url: "/vehicle/api/v1/vehicle/lookup", + method: "GET", + }, + GetDamageOptions: { + url: "/parts/api/v1/parts/damage-options", + method: "GET", + }, + LookupVehicleByYmms: { + url: "/vehicle/api/v1/vehicle/Lookup", + method: "GET", + }, + LookupVehicleByVin: { + url: "/vehicle/api/v1/vehicle/Lookup", + method: "POST", + }, + LookupVinByPlate: { + url: "/vehicle/api/v1/vehicle/lookup-vin-by-plate", + method: "POST", + }, + LookupVinByAddress: { + url: "/vehicle/api/v1/vehicle/lookup-vin-by-address", + method: "POST", + }, + GetPartsOrQuestions: { + url: "/parts/api/v1/parts/parts-or-questions", + method: "POST", + }, + GetParts: { + url: "/parts/api/v1/parts/parts", + method: "POST", + }, + GetCapabilityQuestions: { + url: "/parts/api/v1/parts/capability-questions", + method: "GET", + }, + GetPartFromCapabilityAnswer: { + url: "/parts/api/v1/parts/part-from-capability-answer", + method: "POST", + }, + SaveSession: { + url: "/order/api/v1/order/save-session", + method: "POST", + }, + LoadSession: { + url: "/order/api/v1/order/load-session", + method: "POST", + }, + ValidateZip: { + url: "/location/api/v1/location/zip", + method: "GET", + }, + LogExperimentExposureIfAssigned: { + url: "/experiments/api/v1/experiments/log-exposure", + method: "POST", + }, + LogPageView: { + url: "/analytics/api/v1/analytics/log-page-view", + method: "POST", + }, + LogCustomEvent: { + url: "/analytics/api/v1/analytics/log-custom-event", + method: "POST", + }, + InitializeSession: { + url: "/analytics/api/v1/analytics/initialize", + method: "POST", + }, + GetExperimentsByUser: { + url: "/analytics/api/v1/analytics/get-experiments", + method: "GET", + }, + RunExperimentsForTrigger: { + url: "/experiments/api/v1/experiments/run", + method: "POST", + }, }; export { endpoints }; diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index b4d073496..5631b44c7 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -21,7 +21,8 @@ const errorMessages = { SERVICE_ZIP_REQUIRED: "Please enter your service ZIP", SERVICE_ZIP_FORMAT: "Please enter a valid service ZIP", VIN_REQUIRED: "Please enter your VIN", - VIN_FORMAT: "Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q", + VIN_FORMAT: + "Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q", OPTION_REQUIRED: "Please select an option", VEHICLE_REQUIRED: "Please select a vehicle", }; diff --git a/src/constants/events.js b/src/constants/events.js index 066ef6dcd..f416eeff1 100644 --- a/src/constants/events.js +++ b/src/constants/events.js @@ -1,17 +1,17 @@ const globalEvents = { - Categories: { - GLOBAL_ALERT: "GLOBAL_ALERT", - }, - SubCategories: { - PAGE_NOT_FOUND: "PAGE_NOT_FOUND", - }, + Categories: { + GLOBAL_ALERT: "GLOBAL_ALERT", + }, + SubCategories: { + PAGE_NOT_FOUND: "PAGE_NOT_FOUND", + }, }; const globalEventTypes = { - Success: "alert-success", - Warning: "alert-warning", - Info: "alert-info", - Danger: "alert-danger", + Success: "alert-success", + Warning: "alert-warning", + Info: "alert-info", + Danger: "alert-danger", }; export { globalEvents, globalEventTypes }; diff --git a/src/constants/experiments.js b/src/constants/experiments.js index fdfa7acac..f2e5d4928 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -1,15 +1,14 @@ const experimentUniverses = { - CONCEPT_FUNNEL: 'ConceptFunnel' + CONCEPT_FUNNEL: "ConceptFunnel", }; const experimentSettings = { - GOOGLE_CUSTOM_DIMENSION_INDEX: 'Google Custom Dimension Index' -} + GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index", +}; const experimentTriggers = { SITE_ENTRY: "SiteEntry", - PAGE_ENTRY: "PageEntry" + PAGE_ENTRY: "PageEntry", }; - + export { experimentUniverses, experimentSettings, experimentTriggers }; - \ No newline at end of file diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js index 895058e48..2cfbba367 100644 --- a/src/constants/header-keys.js +++ b/src/constants/header-keys.js @@ -1,3 +1,3 @@ export const headerKeys = { - EXPERIMENT: "X-Experiment-Data" -} \ No newline at end of file + EXPERIMENT: "X-Experiment-Data", +}; diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 6655f9378..f75e526d6 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,7 +1,6 @@ const queryStrings = { - FMG_PAGE: 'fmgPage', - START_TYPE: 'start_type' - }; - - export { queryStrings }; - \ No newline at end of file + FMG_PAGE: "fmgPage", + START_TYPE: "start_type", +}; + +export { queryStrings }; diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 8c498feda..78053b567 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -1,67 +1,66 @@ const storeActions = { - // Content Actions - GET_ROUTE_INFO_ACTION: "getRouteInfo", - GET_HOMEPAGE_NAME: "getHomepageName", - GET_PAGE_DATA: "getPageData", + // Content Actions + GET_ROUTE_INFO_ACTION: "getRouteInfo", + GET_HOMEPAGE_NAME: "getHomepageName", + GET_PAGE_DATA: "getPageData", - // Vehicle Actions - GET_VEHICLE_YEARS: "getVehicleYears", - GET_VEHICLE_MAKES: "getVehicleMakes", - GET_VEHICLE_MODELS: "getVehicleModels", - GET_VEHICLE_STYLES: "getVehicleStyles", - SET_VEHICLE: "setVehicle", - GET_DAMAGE_OPTIONS: "getDamageOptions", - GET_EVOX_IMAGE: "getEvoxImage", + // Vehicle Actions + GET_VEHICLE_YEARS: "getVehicleYears", + GET_VEHICLE_MAKES: "getVehicleMakes", + GET_VEHICLE_MODELS: "getVehicleModels", + GET_VEHICLE_STYLES: "getVehicleStyles", + SET_VEHICLE: "setVehicle", + GET_DAMAGE_OPTIONS: "getDamageOptions", + GET_EVOX_IMAGE: "getEvoxImage", - // Lookup Actions - LOOKUP_VEHICLE_BY_YMMS: "lookupVehicleByYmms", - LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin", - LOOKUP_VIN_BY_PLATE: "lookupVinByPlate", - LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress", - GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions", - GET_PARTS: "getParts", - GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions", - GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: - "getPartFromCapabilityQuestionAnswer", - GET_MOLDING_QUESTIONS: "getMoldingQuestions", - SAVE_SESSION: "saveSession", - LOAD_SESSION: "loadSession", - UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse", - VALIDATE_ZIP: "validateZip", - LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure", - LOG_PAGE_VIEW: "logPageView", - LOG_CUSTOM_EVENT: "logCustomEvent", - INITIALIZE_SESSION: "initializeSession", - GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser", - RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger", - CLEAR_VIN: "clearVin", - RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise", + // Lookup Actions + LOOKUP_VEHICLE_BY_YMMS: "lookupVehicleByYmms", + LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin", + LOOKUP_VIN_BY_PLATE: "lookupVinByPlate", + LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress", + GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions", + GET_PARTS: "getParts", + GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions", + GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer", + GET_MOLDING_QUESTIONS: "getMoldingQuestions", + SAVE_SESSION: "saveSession", + LOAD_SESSION: "loadSession", + UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse", + VALIDATE_ZIP: "validateZip", + LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure", + LOG_PAGE_VIEW: "logPageView", + LOG_CUSTOM_EVENT: "logCustomEvent", + INITIALIZE_SESSION: "initializeSession", + GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser", + RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger", + CLEAR_VIN: "clearVin", + RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise", - // DEPENDENCY MUTATIONS - RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies", - RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies", - RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies", - RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies", - RESET_STATE: "resetState", + // DEPENDENCY MUTATIONS + RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies", + RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies", + RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies", + RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies", + RESET_STATE: "resetState", - // SAVE COMPONENT STATE - SAVE_VEHICLE_YEAR: "saveVehicleYear", - SAVE_VEHICLE_MAKE: "saveVehicleMake", - SAVE_VEHICLE_MODEL: "saveVehicleModel", - SAVE_VEHICLE_STYLE: "saveVehicleStyle", - SAVE_VEHICLE_DAMAGE: "saveVehicleDamage", - SAVE_VIN_LOOKUP: "saveVinLookup", - SAVE_SERVICE_LOCATION: "saveServiceLocation", - SAVE_EMAIL: "saveEmail", - SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP: "saveRegistrationLicensePlateLookup", - SAVE_VIN: "saveVin", - SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup", - SAVE_GLASS_PARTS: "saveGlassParts", - SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers", - RESET_MOLDING_AND_CAPABILITY_QUESTIONS_IF_NEEDED: - "resetMoldingAndCapabilityQuestionAnswersIfNeeded", - SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers", - SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers", + // SAVE COMPONENT STATE + SAVE_VEHICLE_YEAR: "saveVehicleYear", + SAVE_VEHICLE_MAKE: "saveVehicleMake", + SAVE_VEHICLE_MODEL: "saveVehicleModel", + SAVE_VEHICLE_STYLE: "saveVehicleStyle", + SAVE_VEHICLE_DAMAGE: "saveVehicleDamage", + SAVE_VIN_LOOKUP: "saveVinLookup", + SAVE_SERVICE_LOCATION: "saveServiceLocation", + SAVE_EMAIL: "saveEmail", + SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP: "saveRegistrationLicensePlateLookup", + SAVE_VIN: "saveVin", + SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup", + SAVE_GLASS_PARTS: "saveGlassParts", + SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers", + RESET_MOLDING_AND_CAPABILITY_QUESTIONS_IF_NEEDED: + "resetMoldingAndCapabilityQuestionAnswersIfNeeded", + SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers", + SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers", }; export { storeActions }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index d3de68853..dc165eecf 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -1,71 +1,71 @@ const storeMutations = { - // VEHICLE MUTATIONS - UPDATE_YEAR: "updateYear", - UPDATE_MAKE: "updateMake", - UPDATE_MODEL: "updateModel", - UPDATE_STYLE: "updateStyle", - UPDATE_CAR_ID: "updateCarId", - UPDATE_VEHICLE_CATEGORY: "updateVehicleCategory", - UPDATE_VEHICLE_IMAGE_URL: "updateVehicleImageUrl", - UPDATE_VEHICLE_IMAGE_VIF_NUMBER: "updateVehicleImageVifNumber", - UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor", - UPDATE_VEHICLE_VIN: "updateVehicleVin", - UPDATE_VEHICLE: "updateVehicle", + // VEHICLE MUTATIONS + UPDATE_YEAR: "updateYear", + UPDATE_MAKE: "updateMake", + UPDATE_MODEL: "updateModel", + UPDATE_STYLE: "updateStyle", + UPDATE_CAR_ID: "updateCarId", + UPDATE_VEHICLE_CATEGORY: "updateVehicleCategory", + UPDATE_VEHICLE_IMAGE_URL: "updateVehicleImageUrl", + UPDATE_VEHICLE_IMAGE_VIF_NUMBER: "updateVehicleImageVifNumber", + UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor", + UPDATE_VEHICLE_VIN: "updateVehicleVin", + UPDATE_VEHICLE: "updateVehicle", - UPDATE_IS_REPAIR: "updateIsRepair", - UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips", - UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace", - UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers", - UPDATE_MOLDING_QUESTION_ANSWERS: "updateMoldingQuestionAnswers", - UPDATE_CAPABILITY_QUESTION_ANSWERS: "updateCapabilityQuestionAnswers", - UPDATE_GLASS_PARTS: "updateGlassParts", - UPDATE_OTHER_PARTS: "updateOtherParts", + UPDATE_IS_REPAIR: "updateIsRepair", + UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips", + UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace", + UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers", + UPDATE_MOLDING_QUESTION_ANSWERS: "updateMoldingQuestionAnswers", + UPDATE_CAPABILITY_QUESTION_ANSWERS: "updateCapabilityQuestionAnswers", + UPDATE_GLASS_PARTS: "updateGlassParts", + UPDATE_OTHER_PARTS: "updateOtherParts", - UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate", - UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress", - UPDATE_REGISTRATION_CITY: "updateRegistrationCity", - UPDATE_REGISTRATION_STATE: "updateRegistrationState", - UPDATE_REGISTRATION_ZIP_CODE: "updateRegistrationZipCode", - UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName", - UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName", - UPDATE_REGISTRATION: "updateRegistration", + UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate", + UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress", + UPDATE_REGISTRATION_CITY: "updateRegistrationCity", + UPDATE_REGISTRATION_STATE: "updateRegistrationState", + UPDATE_REGISTRATION_ZIP_CODE: "updateRegistrationZipCode", + UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName", + UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName", + UPDATE_REGISTRATION: "updateRegistration", - UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode", - UPDATE_SERVICE_LOCATION_STATE: "updateServiceLocationState", - UPDATE_SERVICE_LOCATION: "updateServiceLocation", + UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode", + UPDATE_SERVICE_LOCATION_STATE: "updateServiceLocationState", + UPDATE_SERVICE_LOCATION: "updateServiceLocation", - UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress", + UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress", - // ORDER MUTATIONS - UPDATE_REFERRAL_NUMBER: "updateReferralNumber", - UPDATE_REFERRAL_DATE: "updateReferralDate", - UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", - UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", - UPDATE_EON: "updateEON", - UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", - UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId", + // ORDER MUTATIONS + UPDATE_REFERRAL_NUMBER: "updateReferralNumber", + UPDATE_REFERRAL_DATE: "updateReferralDate", + UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", + UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", + UPDATE_EON: "updateEON", + UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", + UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId", - // EVENT BUS MUTATIONS - ADD_EVENT_TO_BUS: "addEventToBus", - REMOVE_EVENT_FROM_BUS: "removeEventFromBus", + // EVENT BUS MUTATIONS + ADD_EVENT_TO_BUS: "addEventToBus", + REMOVE_EVENT_FROM_BUS: "removeEventFromBus", - // DEPENDENCY MUTATIONS - RESET_VEHICLE_STATE: "resetVehicleState", - RESET_DAMAGE_STATE: "resetDamageState", - RESET_REGISTRATION_STATE: "resetRegistrationState", - RESET_GLASS_PARTS_STATE: "resetGlassPartsState", - RESET_STATE: "resetState", - RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise", + // DEPENDENCY MUTATIONS + RESET_VEHICLE_STATE: "resetVehicleState", + RESET_DAMAGE_STATE: "resetDamageState", + RESET_REGISTRATION_STATE: "resetRegistrationState", + RESET_GLASS_PARTS_STATE: "resetGlassPartsState", + RESET_STATE: "resetState", + RESET_SAVE_SESSION_PROMISE: "resetSaveSessionPromise", - // OTHER MUTATIONS - UPDATE_PAGE_DATA: "updatePageData", - UPDATE_STATE_WITH_ORDER_INFORMATION: "updateStateWithOrderInformation", - UPDATE_SAVE_SESSION_PROMISE: "updateSaveSessionPromise", - UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited", + // OTHER MUTATIONS + UPDATE_PAGE_DATA: "updatePageData", + UPDATE_STATE_WITH_ORDER_INFORMATION: "updateStateWithOrderInformation", + UPDATE_SAVE_SESSION_PROMISE: "updateSaveSessionPromise", + UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited", - // EXPERIMENT MUTATIONS - UPDATE_EXPERIMENTS: "updateExperiments", - UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry", + // EXPERIMENT MUTATIONS + UPDATE_EXPERIMENTS: "updateExperiments", + UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry", }; -export { storeMutations }; \ No newline at end of file +export { storeMutations }; diff --git a/src/constants/tint-mapper.js b/src/constants/tint-mapper.js index 32dae95fc..308b9a92d 100644 --- a/src/constants/tint-mapper.js +++ b/src/constants/tint-mapper.js @@ -1,7 +1,6 @@ - // TintMap with array keys by location, lowercase to avoid as much string mismatching as possible. // Src assumes you have a @/assets/img/tints/, making the final value @/assets/img/tints/{Src} in the markup. -// See vehicle-parts for implementation example. +// See vehicle-parts for implementation example. const tintMap = { other: [ // Blue Shade @@ -35,7 +34,7 @@ const tintMap = { { name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" }, // No shade or tint - { name: "clear", src: "Glass-NoShade-NoTint.svg" } + { name: "clear", src: "Glass-NoShade-NoTint.svg" }, ], windshield: [ @@ -71,25 +70,25 @@ const tintMap = { // No shade or tint { name: "clear", src: "Windshield-NoShade-NoTint.svg" }, - - ] -} + ], +}; // Gets the tint image source string given the glass location, and the tint description (like 'Green Tint') // Use lowered strings here to try to avoid mismatch. Returns an empty string if array key doesn't exist. // Returns undefined if no items are found. export function getTintImage(glassLocation, colorString) { - // Windshield glass has special images, all other glass uses the same though. - if(glassLocation.toLowerCase() !== 'windshield'){ - glassLocation = 'other'; + if (glassLocation.toLowerCase() !== "windshield") { + glassLocation = "other"; } if (tintMap[glassLocation.toLowerCase()] === undefined) { - return ''; + return ""; } - const tintImageSource = tintMap[glassLocation.toLowerCase()].find(item => item.name.toLowerCase() == colorString.toLowerCase()) + const tintImageSource = tintMap[glassLocation.toLowerCase()].find( + (item) => item.name.toLowerCase() == colorString.toLowerCase() + ); return tintImageSource; -} \ No newline at end of file +} diff --git a/src/constants/vehicle-categories.js b/src/constants/vehicle-categories.js index 4fab279d8..37ffcf5e1 100644 --- a/src/constants/vehicle-categories.js +++ b/src/constants/vehicle-categories.js @@ -6,6 +6,6 @@ const vehicleCategories = { SUV: "SUV", MOTORHOME: "MOTOR HOME", SEMI: "SEMI", - }; - - export { vehicleCategories }; \ No newline at end of file +}; + +export { vehicleCategories }; diff --git a/src/constants/vin-lookup-method-selections.js b/src/constants/vin-lookup-method-selections.js index 46f1e2044..8f78ecf68 100644 --- a/src/constants/vin-lookup-method-selections.js +++ b/src/constants/vin-lookup-method-selections.js @@ -1,7 +1,7 @@ const vinLookupMethodSelections = { - MANUALVIN: "ManualVin", - LICENSEPLATE: "LicensePlate", - HOMEADDRESS: "HomeAddress", -}; + MANUALVIN: "ManualVin", + LICENSEPLATE: "LicensePlate", + HOMEADDRESS: "HomeAddress", +}; -export { vinLookupMethodSelections }; \ No newline at end of file +export { vinLookupMethodSelections }; diff --git a/src/global-methods.js b/src/global-methods.js index ffda1e77f..14e5cca0e 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -7,53 +7,69 @@ import { GaCategories, GaActions, GaLabels } from "@/constants/analytics"; import { headerKeys } from "@/constants/header-keys"; export default { - callHttpClient({ method, endpoint, payload, logApiCall = true }) { - return new Promise((resolve, reject) => { - const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; - const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); - const headers = { - [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings) - } + callHttpClient({ method, endpoint, payload, logApiCall = true }) { + return new Promise((resolve, reject) => { + const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; + const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); + const headers = { + [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), + }; - axios({ method: method, url: cfDistroUrl + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: {}, headers: headers }) - .then((response) => { + axios({ + method: method, + url: cfDistroUrl + endpoint, + data: payloadAndAnalyticsData, + crossDomain: true, + responseType: {}, + headers: headers, + }).then( + (response) => { + if (logApiCall) { + analyticsMixIn.methods.pushEventToGA( + GaCategories.API_RESPONSE, + GaActions.RESULT, + `${GaLabels.SUCCESS}_${endpoint}`, + true + ); + } - if (logApiCall) { - analyticsMixIn.methods.pushEventToGA(GaCategories.API_RESPONSE, GaActions.RESULT, `${GaLabels.SUCCESS}_${endpoint}`, true); - } + return resolve(response); + }, + (error) => { + console.error(error); - return resolve(response); - }, - error => { - console.error(error); + if (logApiCall) { + analyticsMixIn.methods.pushEventToGA( + GaCategories.API_RESPONSE, + GaActions.RESULT, + `${GaLabels.ERROR}_${endpoint}`, + true + ); + } - if (logApiCall) { - analyticsMixIn.methods.pushEventToGA(GaCategories.API_RESPONSE, GaActions.RESULT, `${GaLabels.ERROR}_${endpoint}`, true); - } + return reject(error.response); + } + ); + }); + }, - return reject(error.response); - } - ); - }); - }, - - /* istanbul ignore next */ - callMockHttpClient({ method, endpoint }) { - // For Mock use only! - return new Promise((resolve, reject) => { - axios({ - method: method, - url: endpoint, - crossDomain: true, - responseType: {}, - }).then( - (response) => { - resolve(response); - }, - (error) => { - return reject(error.response); - } - ); - }); - }, + /* istanbul ignore next */ + callMockHttpClient({ method, endpoint }) { + // For Mock use only! + return new Promise((resolve, reject) => { + axios({ + method: method, + url: endpoint, + crossDomain: true, + responseType: {}, + }).then( + (response) => { + resolve(response); + }, + (error) => { + return reject(error.response); + } + ); + }); + }, }; diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index 5dcba0ccd..b74b97a8a 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -7,75 +7,71 @@ jest.mock("axios"); jest.mock("@/mixins/analytics-mixin"); it("Global Methods - Call Http Client - Should Resolve Promise", () => { - //Arrange - const endpoint = "https://mock.safelite.com"; - const httpArgs = setupMocksForHttpClient({ endpoint: endpoint }); - analyticsMixIn.methods.pushEventToGA = jest.fn(); + //Arrange + const endpoint = "https://mock.safelite.com"; + const httpArgs = setupMocksForHttpClient({ endpoint: endpoint }); + analyticsMixIn.methods.pushEventToGA = jest.fn(); - //Act - globalMethods.callHttpClient(httpArgs).then((response) => { - //Assert - expect(axios.mock.calls[0][0].url).toContain(endpoint); - expect(response.data.message).toContain("Success"); - expect(response.status).toEqual(200); - }); + //Act + globalMethods.callHttpClient(httpArgs).then((response) => { + //Assert + expect(axios.mock.calls[0][0].url).toContain(endpoint); + expect(response.data.message).toContain("Success"); + expect(response.status).toEqual(200); + }); }); it("Global Methods - Call Http Client - Should Reject Promise", () => { - //Arrange - const endpoint = "https://mock.safelite.com"; - const httpArgs = setupMocksForHttpClient({ - endpoint: endpoint, - isError: true, - }); - analyticsMixIn.methods.pushEventToGA = jest.fn(); + //Arrange + const endpoint = "https://mock.safelite.com"; + const httpArgs = setupMocksForHttpClient({ + endpoint: endpoint, + isError: true, + }); + analyticsMixIn.methods.pushEventToGA = jest.fn(); - //Act - globalMethods.callHttpClient(httpArgs).catch((err) => { - //Assert - expect(axios.mock.calls[0][0].url).toContain(endpoint); - expect(err.data.message).toContain("Error"); - expect(err.status).toEqual(500); - }); + //Act + globalMethods.callHttpClient(httpArgs).catch((err) => { + //Assert + expect(axios.mock.calls[0][0].url).toContain(endpoint); + expect(err.data.message).toContain("Error"); + expect(err.status).toEqual(500); + }); }); -function setupMocksForHttpClient({ - endpoint = null, - isError = false, - additionalData = null, -}) { - //Clear node module - axios.mockClear(); +function setupMocksForHttpClient({ endpoint = null, isError = false, additionalData = null }) { + //Clear node module + axios.mockClear(); - // Success Response - const response = { - status: 200, - data: { - message: "Success", - additionalData: additionalData, - }, - }; + // Success Response + const response = { + status: 200, + data: { + message: "Success", + additionalData: additionalData, + }, + }; - // Error Response - const error = { - response: { - status: 500, - data: { - message: "Error", - additionalData: additionalData, - }, - }, - }; + // Error Response + const error = { + response: { + status: 500, + data: { + message: "Error", + additionalData: additionalData, + }, + }, + }; - // Error interceptor on Axios returns a different object, so we need to mimic that. - if (isError) { - axios.mockRejectedValue(error); - } else { - axios.mockResolvedValue(response); - } + // Error interceptor on Axios returns a different object, so we need to mimic that. + if (isError) { + axios.mockRejectedValue(error); + } else { + axios.mockResolvedValue(response); + } - return { - endpoint: endpoint, - logApiCall: true - }; + return { + endpoint: endpoint, + logApiCall: true, + }; } diff --git a/src/helpers/button-question-focus-helper.js b/src/helpers/button-question-focus-helper.js index f2aac0ba5..52e12aa8c 100644 --- a/src/helpers/button-question-focus-helper.js +++ b/src/helpers/button-question-focus-helper.js @@ -34,8 +34,4 @@ const invokeButtonQuestionLostFocusCallback = () => { } }; -export { - handleAnyComponentFocus, - handleButtonComponentFocus, - handleInputComponentBlur, -}; +export { handleAnyComponentFocus, handleButtonComponentFocus, handleInputComponentBlur }; diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 73912835a..f60e45721 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -3,154 +3,138 @@ import store from "@/store"; import { dynamicStrings } from "../constants/dynamic-strings"; export function fetchCmsContentForPage(fmgPage) { - return store - .dispatch(storeActions.GET_PAGE_DATA, { pageName: fmgPage }) - .then((response) => { - const pageDataFromCms = {}; + return store.dispatch(storeActions.GET_PAGE_DATA, { pageName: fmgPage }).then((response) => { + const pageDataFromCms = {}; - response.data.Result.forEach((widget) => { - let widgetWithReplacements = findAndReplaceGlobalStateValues( - widget.Model, - widget.Name - ); + response.data.Result.forEach((widget) => { + let widgetWithReplacements = findAndReplaceGlobalStateValues(widget.Model, widget.Name); - // If we already have this widget, push it on the collection - if (widgetWithReplacements.Name in pageDataFromCms) { - pageDataFromCms[widgetWithReplacements.Name].push( - widgetWithReplacements.Model - ); - return; - } + // If we already have this widget, push it on the collection + if (widgetWithReplacements.Name in pageDataFromCms) { + pageDataFromCms[widgetWithReplacements.Name].push(widgetWithReplacements.Model); + return; + } - pageDataFromCms[widgetWithReplacements.Name] = [ - widgetWithReplacements.Model, - ]; - }); + pageDataFromCms[widgetWithReplacements.Name] = [widgetWithReplacements.Model]; + }); - Object.keys(pageDataFromCms).forEach((key) => { - if (pageDataFromCms[key].length === 1) { - pageDataFromCms[key] = pageDataFromCms[key][0]; - } - }); + Object.keys(pageDataFromCms).forEach((key) => { + if (pageDataFromCms[key].length === 1) { + pageDataFromCms[key] = pageDataFromCms[key][0]; + } + }); - return pageDataFromCms; + return pageDataFromCms; }); } // Function to convert a string, into a matching global state item. function mapStringToState(str) { - // Pull all matches out of the string. - const regexExp = new RegExp("{(.*?):(.*?)}", "g"); - const regexMatches = [...str.matchAll(regexExp)]; - const globalStateMatches = regexMatches.filter(match => { - return match[1] === dynamicStrings.GLOBAL_STATE; - }) + // Pull all matches out of the string. + const regexExp = new RegExp("{(.*?):(.*?)}", "g"); + const regexMatches = [...str.matchAll(regexExp)]; + const globalStateMatches = regexMatches.filter((match) => { + return match[1] === dynamicStrings.GLOBAL_STATE; + }); - // Our final string value that will be built from the matches. - let stringBuilder = ""; + // Our final string value that will be built from the matches. + let stringBuilder = ""; - for (const match of globalStateMatches) { - // Reset store state for each match. - let storeState = store.state; + for (const match of globalStateMatches) { + // Reset store state for each match. + let storeState = store.state; - for (const s of match[2].split(".")) { - if (storeState[s] != undefined) { - storeState = storeState[s]; - } else { - return ""; // if we can't map our string to state data, return an empty string. - } + for (const s of match[2].split(".")) { + if (storeState[s] != undefined) { + storeState = storeState[s]; + } else { + return ""; // if we can't map our string to state data, return an empty string. + } + } + + const stringWithReplacement = str.replace(match[0], storeState); + + // If we still have values we need to substitute, call this function again. + if (stringWithReplacement.includes(dynamicStrings.GLOBAL_STATE)) { + return mapStringToState(stringWithReplacement); + } + + // Concatenate the string. + stringBuilder = `${stringBuilder} ${stringWithReplacement}`; } - const stringWithReplacement = str.replace(match[0], storeState); - - // If we still have values we need to substitute, call this function again. - if (stringWithReplacement.includes(dynamicStrings.GLOBAL_STATE)) { - return mapStringToState(stringWithReplacement); - } - - // Concatenate the string. - stringBuilder = `${stringBuilder} ${stringWithReplacement}`; - } - - return stringBuilder.trimStart(); + return stringBuilder.trimStart(); } // Parent function for processWidgetItemForReplacement. This will loop through the parent // object and pass any objects that need additional processing to the processWidgetItemForReplacement function. function findAndReplaceGlobalStateValues(widgetModel, widgetName) { - const objWithReplacements = { - Name: widgetName, - Model: {}, - }; + const objWithReplacements = { + Name: widgetName, + Model: {}, + }; - Object.keys(widgetModel).forEach((key) => { - let modelWithReplacements = processWidgetItemForReplacement( - widgetModel, - key - ); + Object.keys(widgetModel).forEach((key) => { + let modelWithReplacements = processWidgetItemForReplacement(widgetModel, key); - objWithReplacements.Model[key] = modelWithReplacements; - }); + objWithReplacements.Model[key] = modelWithReplacements; + }); - return objWithReplacements; + return objWithReplacements; } // This function will process the widget item and replace any global state variables with their values. // This is a recursive function, it will call itself until it runs out of items to iterate on given the object. function processWidgetItemForReplacement(widgetModel, key) { - // If we have a string, and it needs to be replaced. - if (typeof widgetModel[key] === "string") { - if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) { - widgetModel[key] = mapStringToState(widgetModel[key]); + // If we have a string, and it needs to be replaced. + if (typeof widgetModel[key] === "string") { + if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) { + widgetModel[key] = mapStringToState(widgetModel[key]); + } + return widgetModel[key]; } + + // If we have an object. array, etc + if (typeof widgetModel[key] === "object" && Object.keys(widgetModel[key]).length) { + Object.keys(widgetModel[key]).forEach((item) => { + processWidgetItemForReplacement(widgetModel[key], item); + }); + + return widgetModel[key]; + } + + // If we have something else like a number, boolean, etc. just return it return widgetModel[key]; - } - - // If we have an object. array, etc - if ( - typeof widgetModel[key] === "object" && - Object.keys(widgetModel[key]).length - ) { - Object.keys(widgetModel[key]).forEach((item) => { - processWidgetItemForReplacement(widgetModel[key], item); - }); - - return widgetModel[key]; - } - - // If we have something else like a number, boolean, etc. just return it - return widgetModel[key]; } - export function doesCopyContainRouterLink(copy) { - return copy.includes(this.dynamicStrings.ROUTER_LINK); + return copy.includes(this.dynamicStrings.ROUTER_LINK); } -export function splitCopyOnCMSPlaceHolder(copy){ - // splits copy on { ... } such as {routerlink: ...} - return copy.split(/{(.*?)}/g); +export function splitCopyOnCMSPlaceHolder(copy) { + // splits copy on { ... } such as {routerlink: ...} + return copy.split(/{(.*?)}/g); } -export function getRouterLinkRouteFromCopy(copy){ - // sample input: {routerLink:estimate,provide your VIN} - // first split would return 'estimate,provide your VIN' - // second split would return 'estimate' - return copy.split(':')[1].split(',')[0]; +export function getRouterLinkRouteFromCopy(copy) { + // sample input: {routerLink:estimate,provide your VIN} + // first split would return 'estimate,provide your VIN' + // second split would return 'estimate' + return copy.split(":")[1].split(",")[0]; } -export function getRouterLinkDisplayTextFromCopy(copy){ - // sample input: {routerLink:estimate,provide your VIN} - // first split would return 'estimate,provide your VIN' - // second split would return 'provide your VIN' - return copy.split(':')[1].split(',')[1]; +export function getRouterLinkDisplayTextFromCopy(copy) { + // sample input: {routerLink:estimate,provide your VIN} + // first split would return 'estimate,provide your VIN' + // second split would return 'provide your VIN' + return copy.split(":")[1].split(",")[1]; } // Copy returned from the CMS that has newlines will return blocks wrapped in //

...

-// This function returns an array of each paragraph, works with or without html +// This function returns an array of each paragraph, works with or without html // attributes present export function splitCMSCopyOnParagraphTag(copy) { - // filter removes empty strings that are a result of string.split with regex - return copy.split(/(?:)|(?:<\/p>)/g).filter(paragraph => paragraph !== ""); + // filter removes empty strings that are a result of string.split with regex + return copy.split(/(?:)|(?:<\/p>)/g).filter((paragraph) => paragraph !== ""); } diff --git a/src/helpers/cms-helper.spec.js b/src/helpers/cms-helper.spec.js index d7aeb8bf4..3f57b999c 100644 --- a/src/helpers/cms-helper.spec.js +++ b/src/helpers/cms-helper.spec.js @@ -2,135 +2,129 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { dispatch } from "@/store"; jest.mock("@/store", () => ({ - dispatch: jest.fn(), - state: { - order: { vehicle: { year: "2019", make: "Acura" } }, - }, + dispatch: jest.fn(), + state: { + order: { vehicle: { year: "2019", make: "Acura" } }, + }, })); describe("cms-content-helper.js", () => { - it("Should return data from CMS", () => { - // Arrange - const cmsMockData = { - Result: [ - { - Name: "FunnelHeaderWidget", - Model: { - HeaderText: "Select a year to get started", - }, - }, - { - Name: "FunnelSubHeaderWidget", - Model: { - HeaderText: "Select a model", - }, - }, - { - Name: "VehicleYearQuestion", - Model: { - QuestionText: "What year is your vehicle?", - }, - }, - ], - }; + it("Should return data from CMS", () => { + // Arrange + const cmsMockData = { + Result: [ + { + Name: "FunnelHeaderWidget", + Model: { + HeaderText: "Select a year to get started", + }, + }, + { + Name: "FunnelSubHeaderWidget", + Model: { + HeaderText: "Select a model", + }, + }, + { + Name: "VehicleYearQuestion", + Model: { + QuestionText: "What year is your vehicle?", + }, + }, + ], + }; - dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - // Act - fetchCmsContentForPage("testPage").then((response) => { - // Assert - expect(response.FunnelHeaderWidget.HeaderText).toEqual( - "Select a year to get started" - ); + // Act + fetchCmsContentForPage("testPage").then((response) => { + // Assert + expect(response.FunnelHeaderWidget.HeaderText).toEqual("Select a year to get started"); + }); }); - }); }); describe("cms-content-helper.js", () => { - it("Should replace strings for global state", () => { - const cmsMockData = { - Result: [ - { - Name: "FunnelSubHeaderWidget", - Model: { - HeaderText: "{globalState:order.vehicle.year}", - }, - }, - ], - }; + it("Should replace strings for global state", () => { + const cmsMockData = { + Result: [ + { + Name: "FunnelSubHeaderWidget", + Model: { + HeaderText: "{globalState:order.vehicle.year}", + }, + }, + ], + }; - dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - fetchCmsContentForPage("testPage").then((response) => { - // Assert - expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); + fetchCmsContentForPage("testPage").then((response) => { + // Assert + expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); + }); }); - }); }); describe("cms-content-helper.js", () => { - it("Should replace strings for global state, and leave others the same", () => { - const cmsMockData = { - Result: [ - { - Name: "FunnelSubHeaderWidget", - Model: { - HeaderText: "{globalState:order.vehicle.year}", - }, - }, - { - Name: "VehicleYearQuestion", - Model: { - ExampleText: "My widget value!", - }, - }, - ], - }; + it("Should replace strings for global state, and leave others the same", () => { + const cmsMockData = { + Result: [ + { + Name: "FunnelSubHeaderWidget", + Model: { + HeaderText: "{globalState:order.vehicle.year}", + }, + }, + { + Name: "VehicleYearQuestion", + Model: { + ExampleText: "My widget value!", + }, + }, + ], + }; - dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - fetchCmsContentForPage("testPage").then((response) => { - // Assert - expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); - expect(response.VehicleYearQuestion.ExampleText).toEqual( - "My widget value!" - ); + fetchCmsContentForPage("testPage").then((response) => { + // Assert + expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); + expect(response.VehicleYearQuestion.ExampleText).toEqual("My widget value!"); + }); }); - }); }); describe("cms-content-helper.js", () => { - it("Should replace strings for global state in nested objects", () => { - const cmsMockData = { - Result: [ - { - Name: "FunnelSubHeaderWidget", - Model: { - HeaderText: "{globalState:order.vehicle.year}", - }, - }, - { - Name: "VehicleMakeQuestion", - Model: { - OtherObjectInside: { - ExampleText: "{globalState:order.vehicle.make}", - }, - }, - }, - ], - }; + it("Should replace strings for global state in nested objects", () => { + const cmsMockData = { + Result: [ + { + Name: "FunnelSubHeaderWidget", + Model: { + HeaderText: "{globalState:order.vehicle.year}", + }, + }, + { + Name: "VehicleMakeQuestion", + Model: { + OtherObjectInside: { + ExampleText: "{globalState:order.vehicle.make}", + }, + }, + }, + ], + }; - dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - fetchCmsContentForPage("testPage").then((response) => { - // Assert + fetchCmsContentForPage("testPage").then((response) => { + // Assert - expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); - expect( - response.VehicleMakeQuestion.OtherObjectInside.ExampleText - ).toEqual("Acura"); + expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); + expect(response.VehicleMakeQuestion.OtherObjectInside.ExampleText).toEqual("Acura"); + }); }); - }); }); test.todo("String cannot be mapped to global state"); diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index ed353e51b..85cadca60 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -5,61 +5,68 @@ import { storeActions } from "@/constants/store-actions"; export function getDamageString() { // If it's a repair it's always a windshield. const isRepair = store.getters.damage.isRepair; - if(isRepair){ - return "windshield" + if (isRepair) { + return "windshield"; } const damageLocations = store.getters.damage.glassToReplace; let returnString; if (!damageLocations) { - return; + return; } if (damageLocations.length > 1) { - returnString = "match" + returnString = "match"; } else { - switch(damageLocations[0]?.glassLocation) { - case "Windshield": - returnString = "windshield" - break; - case "Driver": - case "Passenger": - returnString = "side window" - break; - case "Rear": - returnString = "rear window" - } + switch (damageLocations[0]?.glassLocation) { + case "Windshield": + returnString = "windshield"; + break; + case "Driver": + case "Passenger": + returnString = "side window"; + break; + case "Rear": + returnString = "rear window"; + } } return returnString; } - export function getIsWindshieldOnly () { +export function getIsWindshieldOnly() { const damageLocations = store.getters.damage.glassToReplace; - const returnString = damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield" ? "windshield" : "glass"; + const returnString = + damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield" + ? "windshield" + : "glass"; return returnString; - } +} -export async function isGlassAvailableForCarId(carId){ +export async function isGlassAvailableForCarId(carId) { const newGlassOptions = await baseMixin.methods.dispatchStoreAction( - storeActions.GET_DAMAGE_OPTIONS, - { carId: carId } + storeActions.GET_DAMAGE_OPTIONS, + { carId: carId } ); const currentGlassOptions = store.getters.damage.glassToReplace; const optionsMap = { - Windshield: "windshieldOptions", - Driver: "driverSideOptions", - Passenger: "passengerSideOptions", - Rear: "backGlassOptions" - } + Windshield: "windshieldOptions", + Driver: "driverSideOptions", + Passenger: "passengerSideOptions", + Rear: "backGlassOptions", + }; - for(const option of currentGlassOptions){ - if(!newGlassOptions.data[optionsMap[option.glassLocation]].availableReplacementOptions.includes(option.glassName)){ - return false; - } + for (const option of currentGlassOptions) { + if ( + !newGlassOptions.data[ + optionsMap[option.glassLocation] + ].availableReplacementOptions.includes(option.glassName) + ) { + return false; + } } return true; - } +} diff --git a/src/helpers/damage-helper.spec.js b/src/helpers/damage-helper.spec.js index 210bf96cc..73215b9c7 100644 --- a/src/helpers/damage-helper.spec.js +++ b/src/helpers/damage-helper.spec.js @@ -1,91 +1,99 @@ -import {getDamageString, isGlassAvailableForCarId} from "./damage-helper"; +import { getDamageString, isGlassAvailableForCarId } from "./damage-helper"; import store from "@/store"; // Mock basemixin. jest.mock("@/mixins/base-mixin.js", () => ({ - methods: { - dispatchStoreAction: jest.fn().mockImplementation(() => { return { - data: { - windshieldOptions: {availableReplacementOptions: ["windshield"]} - } - } }), - }, + methods: { + dispatchStoreAction: jest.fn().mockImplementation(() => { + return { + data: { + windshieldOptions: { availableReplacementOptions: ["windshield"] }, + }, + }; + }), + }, })); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return match when multiple selected damage options are in the store", () => { + // Arrange / Act + store.getters.damage.glassToReplace = [ + { glassLocation: "Windshield", glassName: "windshield" }, + { glassLocation: "Passenger", glassName: "sideWindow" }, + ]; - // Arrange / Act - store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}, {glassLocation: "Passenger", glassName: "sideWindow"}]; + const damage = getDamageString(); - const damage = getDamageString(); - - // Assert - expect(damage).toEqual("match"); + // Assert + expect(damage).toEqual("match"); }); - }); +}); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return windshield when Windshield is the only selected damage option in the store", () => { + // Arrange / Act + store.getters.damage.glassToReplace = [ + { glassLocation: "Windshield", glassName: "windshield" }, + ]; - // Arrange / Act - store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}]; + const damage = getDamageString(); - const damage = getDamageString(); - - // Assert - expect(damage).toEqual("windshield"); + // Assert + expect(damage).toEqual("windshield"); }); - }); +}); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => { + // Arrange / Act + store.getters.damage.glassToReplace = [ + { glassLocation: "Passenger", glassName: "sideWindow" }, + ]; - // Arrange / Act - store.getters.damage.glassToReplace = [{glassLocation: "Passenger", glassName: "sideWindow"}]; + const damage = getDamageString(); - const damage = getDamageString(); - - // Assert - expect(damage).toEqual("side window"); + // Assert + expect(damage).toEqual("side window"); }); - }); +}); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return rear window when Rear is the only selected damage option in the store", () => { + // Arrange / Act + store.getters.damage.glassToReplace = [{ glassLocation: "Rear", glassName: "rear" }]; - // Arrange / Act - store.getters.damage.glassToReplace = [{glassLocation: "Rear", glassName: "rear"}]; + const damage = getDamageString(); - const damage = getDamageString(); - - // Assert - expect(damage).toEqual("rear window"); + // Assert + expect(damage).toEqual("rear window"); }); - }); +}); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return true if no mismatches between each array exist", async () => { - // Arrange - store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}]; + // Arrange + store.getters.damage.glassToReplace = [ + { glassLocation: "Windshield", glassName: "windshield" }, + ]; - // Act - const isGlassAvailable = await isGlassAvailableForCarId(); + // Act + const isGlassAvailable = await isGlassAvailableForCarId(); - // Assert - expect(isGlassAvailable).toEqual(true); + // Assert + expect(isGlassAvailable).toEqual(true); }); - }); +}); - describe("damage-helper.js", () => { +describe("damage-helper.js", () => { it("Should return false if any mismatches between each array exist", async () => { - // Arrange - store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "sideWindow"}]; + // Arrange + store.getters.damage.glassToReplace = [ + { glassLocation: "Windshield", glassName: "sideWindow" }, + ]; - const isGlassAvailable = await isGlassAvailableForCarId(); + const isGlassAvailable = await isGlassAvailableForCarId(); - // Assert - expect(isGlassAvailable).toEqual(false); + // Assert + expect(isGlassAvailable).toEqual(false); }); - }); - +}); diff --git a/src/helpers/event-bus/event-bus.js b/src/helpers/event-bus/event-bus.js index 19b30870c..2b199a699 100644 --- a/src/helpers/event-bus/event-bus.js +++ b/src/helpers/event-bus/event-bus.js @@ -2,31 +2,31 @@ import store from "@/store"; import { storeMutations } from "@/constants/store-mutations.js"; export default { - // Adds event to the bus given its category, subcategory, and eventValue; - addEventToBus(category, subCategory, eventValue) { - store.commit(storeMutations.ADD_EVENT_TO_BUS, { - category: category, - subCategory: subCategory, - eventValue: eventValue, - }); - }, + // Adds event to the bus given its category, subcategory, and eventValue; + addEventToBus(category, subCategory, eventValue) { + store.commit(storeMutations.ADD_EVENT_TO_BUS, { + category: category, + subCategory: subCategory, + eventValue: eventValue, + }); + }, - // Finds event on the bus, removes the item, and returns its value to the caller. - readAndPopEventFromBus(category, subCategory) { - const event = store.getters.eventBusItem(category, subCategory); + // Finds event on the bus, removes the item, and returns its value to the caller. + readAndPopEventFromBus(category, subCategory) { + const event = store.getters.eventBusItem(category, subCategory); - store.commit(storeMutations.REMOVE_EVENT_FROM_BUS, { - category: category, - subCategory: subCategory, - }); + store.commit(storeMutations.REMOVE_EVENT_FROM_BUS, { + category: category, + subCategory: subCategory, + }); - return event; - }, + return event; + }, - // Finds the event on the bus and returns its value to the caller, does not remove it. - readEventFromBus(category, subCategory) { - const event = store.getters.eventBusItem(category, subCategory); + // Finds the event on the bus and returns its value to the caller, does not remove it. + readEventFromBus(category, subCategory) { + const event = store.getters.eventBusItem(category, subCategory); - return event; - }, + return event; + }, }; diff --git a/src/helpers/event-bus/event-bus.spec.js b/src/helpers/event-bus/event-bus.spec.js index fece3fee2..e21212adc 100644 --- a/src/helpers/event-bus/event-bus.spec.js +++ b/src/helpers/event-bus/event-bus.spec.js @@ -3,57 +3,57 @@ import eventBus from "@/helpers/event-bus/event-bus"; import store from "@/store"; describe("event-bus.js", () => { - let event = { - isDismissible: true, - messageCopy: "You can get a quote by starting on this page.", - messageHeadline: "We're sorry, something went wrong.", - type: globalEventTypes.Danger, - }; + let event = { + isDismissible: true, + messageCopy: "You can get a quote by starting on this page.", + messageHeadline: "We're sorry, something went wrong.", + type: globalEventTypes.Danger, + }; - it("Puts item on bus and then take it off", () => { - // Arrange / Act - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND, - event - ); + it("Puts item on bus and then take it off", () => { + // Arrange / Act + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND, + event + ); - // Assert - expect( - store.getters.eventBusItem( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ) - ).toEqual(event); + // Assert + expect( + store.getters.eventBusItem( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ) + ).toEqual(event); - expect(store.state.applicationUser.eventBus.length).toEqual(1); + expect(store.state.applicationUser.eventBus.length).toEqual(1); - // Arrange / Act - const eventValue = eventBus.readAndPopEventFromBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ); + // Arrange / Act + const eventValue = eventBus.readAndPopEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); - // Assert - expect(eventValue).toEqual(event); + // Assert + expect(eventValue).toEqual(event); - expect(store.state.applicationUser.eventBus.length).toEqual(0); - }); + expect(store.state.applicationUser.eventBus.length).toEqual(0); + }); - it("Reads event from bus, should have event value.", () => { - // Arrange / Act - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND, - event - ); + it("Reads event from bus, should have event value.", () => { + // Arrange / Act + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND, + event + ); - // Assert - expect( - eventBus.readEventFromBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ) - ).toEqual(event); - }); + // Assert + expect( + eventBus.readEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ) + ).toEqual(event); + }); }); diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js index 3eed5950b..5b6800c86 100644 --- a/src/helpers/heritage-integration/cookie-helper.js +++ b/src/helpers/heritage-integration/cookie-helper.js @@ -8,7 +8,7 @@ import { applicationConfig } from "@/constants/application-config"; export function updateOrCreateFunnelCookie() { const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration; const shouldSuppressConceptFunnel = getFunnelCookie()?.SuppressConceptFunnel; - + // Set up cookie with all the props. setFunnelCookieProperties({ LastTouched: new Date().toUTCString(), @@ -20,7 +20,7 @@ export function updateOrCreateFunnelCookie() { ReferralCorrelationId: store.getters.order.referralCorrelationId, ReferralParentAccountNumber: store.getters.order.accountNumber, HasDelayedClaimRegistration: wasClaimRegistrationDelayed, - SuppressConceptFunnel: shouldSuppressConceptFunnel + SuppressConceptFunnel: shouldSuppressConceptFunnel, }); } @@ -31,7 +31,7 @@ export function updateOrCreateFunnelCookie() { export function getFunnelCookie() { const cookieJson = document.cookie ?.split("; ") - ?.find(row => row.startsWith(`${cookieNames.FUNNEL_SESSION_INFO}=`)) + ?.find((row) => row.startsWith(`${cookieNames.FUNNEL_SESSION_INFO}=`)) ?.split("=")[1]; try { @@ -59,31 +59,31 @@ export function getCookieDomainValue() { Gets value of dxdev cookie, and then extracts "did" value from it. Returns empty string if cookie not found or "did" string not present. */ -export function getDeviceIdValue(){ +export function getDeviceIdValue() { // Sometimes these cookie contains more than the device ID. const cookieValue = getCookieValueByName(cookieNames.DXDEV); - const cookieValuesSplit = cookieValue.split('='); + const cookieValuesSplit = cookieValue.split("="); // If this is the only value, just use that. - if(cookieValuesSplit.length === 2 && cookieValuesSplit[0] === 'did'){ + if (cookieValuesSplit.length === 2 && cookieValuesSplit[0] === "did") { return cookieValuesSplit[1]; } const cookieValueMatch = cookieValue.match("^did=[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}"); - if(cookieValueMatch){ - return cookieValueMatch[0].split('=')[1]; + if (cookieValueMatch) { + return cookieValueMatch[0].split("=")[1]; } - return '00000000-0000-0000-0000-000000000000'; + return "00000000-0000-0000-0000-000000000000"; } /* Gets value of skey cookie, returns 0 if not found. */ -export function getSessionKeyValue(){ +export function getSessionKeyValue() { const cookieValue = getCookieValueByName(cookieNames.SESSION_KEY); - if(cookieValue){ + if (cookieValue) { return cookieValue; } @@ -93,14 +93,14 @@ export function getSessionKeyValue(){ /* Gets value of skey cookie, returns 0 if not found. */ -export function getSessionIdValue(){ +export function getSessionIdValue() { const cookieValue = getCookieValueByName(cookieNames.SESSION_ID); - if(cookieValue){ + if (cookieValue) { return cookieValue; } - return '00000000-0000-0000-0000-000000000000'; + return "00000000-0000-0000-0000-000000000000"; } /* @@ -110,10 +110,17 @@ export function updateSessionIdCookie() { createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 }); } -export function setCookieProperties(properties, { useDefaultFunnelCookieAttributes = true, maxAge, isSecure }) { +export function setCookieProperties( + properties, + { useDefaultFunnelCookieAttributes = true, maxAge, isSecure } +) { if (typeof properties == "object") { - Object.keys(properties).forEach(key => { - createOrUpdateCookie(key, properties[key], { useDefaultFunnelCookieAttributes, maxAge, isSecure }); + Object.keys(properties).forEach((key) => { + createOrUpdateCookie(key, properties[key], { + useDefaultFunnelCookieAttributes, + maxAge, + isSecure, + }); }); } } @@ -124,7 +131,6 @@ export function setCookieProperties(properties, { useDefaultFunnelCookieAttribut =========================== */ - /* Used to set properties on the funnel cookie. Takes an object with properties to set. Will overwrite existing properties. @@ -134,12 +140,12 @@ function setFunnelCookieProperties(properties) { let cookie = getFunnelCookie(); if (cookie !== null) { - Object.keys(properties).forEach(key => { + Object.keys(properties).forEach((key) => { cookie[key] = properties[key]; }); } - const cookieValueJson = JSON.stringify(cookie ?? {}); + const cookieValueJson = JSON.stringify(cookie ?? {}); createOrUpdateCookie(cookieNames.FUNNEL_SESSION_INFO, cookieValueJson, {}); } } @@ -148,7 +154,11 @@ function setFunnelCookieProperties(properties) { Used to create a cookie. `useDefaultFunnelCookieAttributes` will set the path and domain to our defaults */ -function createOrUpdateCookie(key, value = "", { useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true }) { +function createOrUpdateCookie( + key, + value = "", + { useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true } +) { let cookieToAdd = `${key}=${value}; `; if (useDefaultFunnelCookieAttributes) { @@ -173,12 +183,12 @@ function getDomainWithoutSubdomain() { return "localhost"; } - const urlParts = url.split('.'); + const urlParts = url.split("."); return `.${urlParts .slice(0) .slice(-(urlParts.length === 4 ? 3 : 2)) - .join('.')}`; + .join(".")}`; } /* @@ -196,4 +206,4 @@ function getCookieValueByName(name) { function isLocalhost() { return location.hostname.includes("localhost"); -} \ No newline at end of file +} diff --git a/src/helpers/heritage-integration/cookie-helper.spec.js b/src/helpers/heritage-integration/cookie-helper.spec.js index a5857fd74..5df2ae925 100644 --- a/src/helpers/heritage-integration/cookie-helper.spec.js +++ b/src/helpers/heritage-integration/cookie-helper.spec.js @@ -1,145 +1,145 @@ -import {getFunnelCookie, getDeviceIdValue, getSessionKeyValue, getSessionIdValue} from "@/helpers/heritage-integration/cookie-helper.js"; +import { + getFunnelCookie, + getDeviceIdValue, + getSessionKeyValue, + getSessionIdValue, +} from "@/helpers/heritage-integration/cookie-helper.js"; import { removeAllTestCookies, setupCookies } from "@/helpers/unit-test-helper"; describe("cookies", () => { - afterEach(() => { - removeAllTestCookies(); - }) - - describe("getFunnelCookie method", () => { - test("gets correct value when cookie is present", () => { - // Arrange - const testReferralNumber = 1566818; - const testReferralDate = "2022-03-15T10:56:24.597"; - const testReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; - const testShouldResetState = false; - const testDidHeritageFunnelUpdateLast = true; - - const testCookieValue = { - ReferralNumber: testReferralNumber, - ReferralDate: testReferralDate, - ReferralCorrelationId: testReferralCorrelationId, - ShouldResetState: testShouldResetState, - DidHeritageFunnelUpdateLast: testDidHeritageFunnelUpdateLast, - SuppressConceptFunnel: true - } + removeAllTestCookies(); + }); - setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); - - // Act - var result = getFunnelCookie(); - - // Assert - expect(result).toEqual(testCookieValue); - expect(typeof result).toEqual("object"); - expect(result.ReferralNumber).toEqual(testReferralNumber); - expect(result.ReferralDate).toEqual(testReferralDate); - expect(result.ReferralCorrelationId).toEqual(testReferralCorrelationId); - expect(result.ShouldResetState).toEqual(testShouldResetState); - expect(result.DidHeritageFunnelUpdateLast).toEqual(testDidHeritageFunnelUpdateLast); - }); - - test("returns empty object when value is empty object", () => { - // Arrange - const testCookieValue = {}; - setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); - - // Act - var result = getFunnelCookie(); - - // Assert - expect(result).toEqual(testCookieValue); - expect(typeof result).toEqual("object"); - expect(Object.keys(result)).toHaveLength(0); - }); - - test("returns null when value is empty string", () => { - // Arrange - const testCookieValue = ""; - setupCookies({ funnelCookieValue: testCookieValue }); - - // Act - var result = getFunnelCookie(); - - // Assert - expect(result).toEqual(null); - }); - - test("returns null when funnel cookie doesn't exist", () => { - // Arrange - setupCookies({ includeHeritageCookie: false }); - - // Act - var result = getFunnelCookie(); - - // Assert - expect(result).toEqual(null); - }); - - test("gets correct cookie value", () => { - // Arrange - const testCookieValue = { test: "testValue" }; - - setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); - - // Act - const actualCookieValue = getFunnelCookie(); - - // Assert - expect(actualCookieValue).toEqual(testCookieValue); - }); - - test("getCookieValue: Gets null cookie value", () => { - // Arrange - setupCookies({ includeHeritageCookie: false }); - - // Act - const actualCookieValue = getFunnelCookie(); - - // Assert - expect(actualCookieValue).toBeNull(); - }); - }) + describe("getFunnelCookie method", () => { + test("gets correct value when cookie is present", () => { + // Arrange + const testReferralNumber = 1566818; + const testReferralDate = "2022-03-15T10:56:24.597"; + const testReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; + const testShouldResetState = false; + const testDidHeritageFunnelUpdateLast = true; + + const testCookieValue = { + ReferralNumber: testReferralNumber, + ReferralDate: testReferralDate, + ReferralCorrelationId: testReferralCorrelationId, + ShouldResetState: testShouldResetState, + DidHeritageFunnelUpdateLast: testDidHeritageFunnelUpdateLast, + SuppressConceptFunnel: true, + }; + + setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); + + // Act + var result = getFunnelCookie(); + + // Assert + expect(result).toEqual(testCookieValue); + expect(typeof result).toEqual("object"); + expect(result.ReferralNumber).toEqual(testReferralNumber); + expect(result.ReferralDate).toEqual(testReferralDate); + expect(result.ReferralCorrelationId).toEqual(testReferralCorrelationId); + expect(result.ShouldResetState).toEqual(testShouldResetState); + expect(result.DidHeritageFunnelUpdateLast).toEqual(testDidHeritageFunnelUpdateLast); + }); + + test("returns empty object when value is empty object", () => { + // Arrange + const testCookieValue = {}; + setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); + + // Act + var result = getFunnelCookie(); + + // Assert + expect(result).toEqual(testCookieValue); + expect(typeof result).toEqual("object"); + expect(Object.keys(result)).toHaveLength(0); + }); + + test("returns null when value is empty string", () => { + // Arrange + const testCookieValue = ""; + setupCookies({ funnelCookieValue: testCookieValue }); + + // Act + var result = getFunnelCookie(); + + // Assert + expect(result).toEqual(null); + }); + + test("returns null when funnel cookie doesn't exist", () => { + // Arrange + setupCookies({ includeHeritageCookie: false }); + + // Act + var result = getFunnelCookie(); + + // Assert + expect(result).toEqual(null); + }); + + test("gets correct cookie value", () => { + // Arrange + const testCookieValue = { test: "testValue" }; + + setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); + + // Act + const actualCookieValue = getFunnelCookie(); + + // Assert + expect(actualCookieValue).toEqual(testCookieValue); + }); + + test("getCookieValue: Gets null cookie value", () => { + // Arrange + setupCookies({ includeHeritageCookie: false }); + + // Act + const actualCookieValue = getFunnelCookie(); + + // Assert + expect(actualCookieValue).toBeNull(); + }); + }); describe("getDeviceIdValue", () => { - test("getDeviceIdValue, should return GUID", () => { - // Arrange - setupCookies({}); + test("getDeviceIdValue, should return GUID", () => { + // Arrange + setupCookies({}); - // Act - const result = getDeviceIdValue(); + // Act + const result = getDeviceIdValue(); - //Assert - expect(result).toBe('21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe'); + //Assert + expect(result).toBe("21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe"); + }); - }); + test("getSessionKeyValue, should return session key int", () => { + // Arrange + setupCookies({}); - test("getSessionKeyValue, should return session key int", () => { - // Arrange - setupCookies({}); + // Act + const result = getSessionKeyValue(); - // Act - const result = getSessionKeyValue(); - - //Assert - expect(result).toBe('12345'); - - }); + //Assert + expect(result).toBe("12345"); + }); }); describe("getSessionIdValue", () => { - test("getSessionIdValue, should return GUID", () => { - // Arrange - setupCookies({}); + test("getSessionIdValue, should return GUID", () => { + // Arrange + setupCookies({}); - // Act - const result = getSessionIdValue(); + // Act + const result = getSessionIdValue(); - //Assert - expect(result).toBe('cba0c3d1-3c1b-4305-bb56-31aa50f58e27'); - - }); - }); - }) - \ No newline at end of file + //Assert + expect(result).toBe("cba0c3d1-3c1b-4305-bb56-31aa50f58e27"); + }); + }); +}); diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index bd7c3dcf4..e51331779 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -13,7 +13,7 @@ import router from "@/router"; */ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHeritageOrder = false) { // If the user is coming in via the Safelite.Com CTA - if (toRoute.query[queryStrings.START_TYPE] === 'fmg') { + if (toRoute.query[queryStrings.START_TYPE] === "fmg") { // If they have an existing order, return 'heritage' for the page name. if (existingHeritageOrder) { return fmgPageValues.HERITAGE; @@ -45,14 +45,11 @@ export async function navigateToHeritageFunnel(shouldSaveSession = true) { await saveSession(); } - router.navigateToExternalUrl( - externalUrls.HERITAGE_FUNNEL, - { - corid: store.getters.order.referralCorrelationId, - src: "concept-funnel", - conceptsqid: store.getters.applicationUser.savedSessionId - } - ); + router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, { + corid: store.getters.order.referralCorrelationId, + src: "concept-funnel", + conceptsqid: store.getters.applicationUser.savedSessionId, + }); } /* @@ -71,7 +68,9 @@ async function getLatestPageForRedirection() { const partQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.PART_QUESTIONS); const vehiclePartsComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_PARTS); const moldingQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.MOLDING_QUESTIONS); - const capabilityQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.CAPABILITY_QUESTIONS); + const capabilityQuestionsComponent = await getLazyLoadedComponent( + fmgPageValues.CAPABILITY_QUESTIONS + ); if (!vehicleMakeComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_YEAR; @@ -86,23 +85,21 @@ async function getLatestPageForRedirection() { } else { if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.CAPABILITY_QUESTIONS; - } - else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) { + } else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.MOLDING_QUESTIONS; - } - else if (vehiclePartsComponent.methods.arePagePrerequisitesValid()) { + } else if (vehiclePartsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.VEHICLE_PARTS; - } - else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) { + } else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) { return fmgPageValues.PART_QUESTIONS; - } - else if (vinLookupComponent.methods.arePagePrerequisitesValid() && !store.getters.damage.isRepair) { + } else if ( + vinLookupComponent.methods.arePagePrerequisitesValid() && + !store.getters.damage.isRepair + ) { return fmgPageValues.VIN_LOOKUP; - } - else { + } else { return fmgPageValues.ESTIMATE; } - } + } } /* @@ -119,10 +116,9 @@ function overrideYmmsDirectionIfNeeded(toRoute) { case fmgPageValues.VEHICLE_YEAR: case fmgPageValues.VEHICLE_MAKE: case fmgPageValues.VEHICLE_MODEL: - case fmgPageValues.VEHICLE_STYLE: - { - return fmgPageValues.VEHICLE_DAMAGE; - } + case fmgPageValues.VEHICLE_STYLE: { + return fmgPageValues.VEHICLE_DAMAGE; + } default: { return fmgPageValue; } @@ -140,13 +136,15 @@ function overrideYmmsDirectionIfNeeded(toRoute) { function isVinRelatedPage(toRoute) { const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE]; - return fmgPageValue === fmgPageValues.VIN_LOOKUP || + return ( + fmgPageValue === fmgPageValues.VIN_LOOKUP || fmgPageValue === fmgPageValues.LICENSE_PLATE_LOOKUP || fmgPageValue === fmgPageValues.ADDRESS_LOOKUP || fmgPageValue === fmgPageValues.ADDRESS_VEHICLES || - fmgPageValue === fmgPageValues.ESTIMATE; + fmgPageValue === fmgPageValues.ESTIMATE + ); } async function getLazyLoadedComponent(pageName) { return (await lazyLoadComponent(pageName)()).default; -} \ No newline at end of file +} diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index 3281f53c2..7e26f4a54 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -1,4 +1,7 @@ -import { getPageToRouteExistingOrderTo, navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; +import { + getPageToRouteExistingOrderTo, + navigateToHeritageFunnel, +} from "@/helpers/heritage-integration/navigation-helper"; import * as orderHelper from "@/helpers/heritage-integration/order-helper"; import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"; import { storeActions } from "@/constants/store-actions"; @@ -19,13 +22,13 @@ describe("getPageToRouteExistingOrderTo", () => { test("should return vehicle-year", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ - [fmgPageValues.VEHICLE_MAKE]: false - }) + [fmgPageValues.VEHICLE_MAKE]: false, + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -37,14 +40,14 @@ describe("getPageToRouteExistingOrderTo", () => { test("should return vehicle-make", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. mockLazyLoadComponentReturnValues({ [fmgPageValues.VEHICLE_MAKE]: true, - [fmgPageValues.VEHICLE_MODEL]: false - }) + [fmgPageValues.VEHICLE_MODEL]: false, + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -56,7 +59,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("should return vehicle-model", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -64,7 +67,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_MAKE]: true, [fmgPageValues.VEHICLE_MODEL]: true, [fmgPageValues.VEHICLE_STYLE]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -76,7 +79,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("should return vehicle-style", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -85,7 +88,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_MODEL]: true, [fmgPageValues.VEHICLE_STYLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -97,7 +100,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("should return vehicle-damage", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -106,8 +109,8 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_MODEL]: true, [fmgPageValues.VEHICLE_STYLE]: true, [fmgPageValues.VEHICLE_DAMAGE]: true, - [fmgPageValues.ESTIMATE]: false - }) + [fmgPageValues.ESTIMATE]: false, + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -119,7 +122,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has YMMS and no vehicle questions > should return vin-lookup", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -134,7 +137,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: false, [fmgPageValues.PART_QUESTIONS]: false, [fmgPageValues.VIN_LOOKUP]: true, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -146,7 +149,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has YMMS but no questions or carId > should return estimate", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -161,7 +164,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: false, [fmgPageValues.PART_QUESTIONS]: false, [fmgPageValues.VIN_LOOKUP]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -173,7 +176,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has capability questions and molding questions > should return capability questions", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -188,7 +191,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: false, [fmgPageValues.PART_QUESTIONS]: false, [fmgPageValues.VIN_LOOKUP]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -200,7 +203,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has molding questions and part questions > should return molding questions", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -215,7 +218,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: false, [fmgPageValues.PART_QUESTIONS]: true, [fmgPageValues.VIN_LOOKUP]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -227,7 +230,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has vehicle parts questions > should return vehicle-parts", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -242,7 +245,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: true, [fmgPageValues.PART_QUESTIONS]: true, [fmgPageValues.VIN_LOOKUP]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -254,7 +257,7 @@ describe("getPageToRouteExistingOrderTo", () => { test("user has part questions > should return part-questions", async () => { // Arrange const toRoute = { - query: {} + query: {}, }; // Mock out the lazy load calls for all components. @@ -269,7 +272,7 @@ describe("getPageToRouteExistingOrderTo", () => { [fmgPageValues.VEHICLE_PARTS]: false, [fmgPageValues.PART_QUESTIONS]: true, [fmgPageValues.VIN_LOOKUP]: false, - }) + }); // Act const result = await getPageToRouteExistingOrderTo(toRoute, false); @@ -282,16 +285,16 @@ describe("getPageToRouteExistingOrderTo", () => { // Arrange const toRoute = { query: { - [queryStrings.START_TYPE]: 'fmg' - } - } + [queryStrings.START_TYPE]: "fmg", + }, + }; // Act const result = await getPageToRouteExistingOrderTo(toRoute, true); // Assert expect(result).toBe(fmgPageValues.HERITAGE); - }) + }); }); describe("navigateToHeritageFunnel", () => { @@ -302,16 +305,25 @@ describe("navigateToHeritageFunnel", () => { const mockReferralDate = "2022"; const mockAccountNumber = "167132"; const mockSavedSessionId = "xxx-xxx-xxx"; - const mockCrmCustomerId = "xxx-xxx-xxx" + const mockCrmCustomerId = "xxx-xxx-xxx"; - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo( + mockReferralNumber, + mockCorrelationId, + mockReferralDate, + mockAccountNumber, + mockSavedSessionId, + mockCrmCustomerId + ); const mockData = { - actionList: [{ - actionName: storeActions.SAVE_SESSION, - data: mockOrderInfo, - }] - } + actionList: [ + { + actionName: storeActions.SAVE_SESSION, + data: mockOrderInfo, + }, + ], + }; setupMocksForJsFiles(mockData); const saveSessionFunction = jest.spyOn(orderHelper, "saveSession"); @@ -325,7 +337,8 @@ describe("navigateToHeritageFunnel", () => { // Should save before we navigate to heritage by default const saveSessionFunctionCallOrder = saveSessionFunction.mock.invocationCallOrder[0]; - const routerNavigateFunctionCallOrder = router.navigateToExternalUrl.mock.invocationCallOrder[0]; + const routerNavigateFunctionCallOrder = + router.navigateToExternalUrl.mock.invocationCallOrder[0]; expect(saveSessionFunctionCallOrder).toBeLessThan(routerNavigateFunctionCallOrder); saveSessionFunction.mockRestore(); }); @@ -337,20 +350,29 @@ describe("navigateToHeritageFunnel", () => { const mockReferralDate = "2022"; const mockAccountNumber = "167132"; const mockSavedSessionId = "xxx-xxx-xxx"; - const mockCrmCustomerId = "xxx-xxx-xxx" + const mockCrmCustomerId = "xxx-xxx-xxx"; - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo( + mockReferralNumber, + mockCorrelationId, + mockReferralDate, + mockAccountNumber, + mockSavedSessionId, + mockCrmCustomerId + ); const mockData = { - actionList: [{ - actionName: storeActions.SAVE_SESSION, - data: mockOrderInfo, - }] - } + actionList: [ + { + actionName: storeActions.SAVE_SESSION, + data: mockOrderInfo, + }, + ], + }; setupMocksForJsFiles(mockData); - store.getters.order.referralCorrelationId = mockCorrelationId + store.getters.order.referralCorrelationId = mockCorrelationId; router.navigateToExternalUrl = jest.fn(); @@ -359,9 +381,10 @@ describe("navigateToHeritageFunnel", () => { // Assert expect(router.navigateToExternalUrl).toHaveBeenCalled(); - expect(router.navigateToExternalUrl).toHaveBeenCalledWith(externalUrls.HERITAGE_FUNNEL, + expect(router.navigateToExternalUrl).toHaveBeenCalledWith( + externalUrls.HERITAGE_FUNNEL, expect.objectContaining({ - corid: mockCorrelationId + corid: mockCorrelationId, }) ); }); @@ -372,14 +395,20 @@ describe("navigateToHeritageFunnel", () => { const mockCorrelationId = "55"; const mockReferralDate = "2022"; - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate); + const mockOrderInfo = getMockOrderInfo( + mockReferralNumber, + mockCorrelationId, + mockReferralDate + ); const mockData = { - actionList: [{ - actionName: storeActions.SAVE_SESSION, - data: mockOrderInfo, - }] - } + actionList: [ + { + actionName: storeActions.SAVE_SESSION, + data: mockOrderInfo, + }, + ], + }; setupMocksForJsFiles(mockData); const saveSessionFunction = jest.spyOn(orderHelper, "saveSession"); @@ -395,7 +424,7 @@ describe("navigateToHeritageFunnel", () => { }); }); -/** +/** * `arePagePrerequisitesValidObject` is an object where the keys are fmgPageValue names and the values are booleans that indicate * whether arePagePrerequisitesValid is true or false */ @@ -405,10 +434,12 @@ function mockLazyLoadComponentReturnValues(arePagePrerequisitesValidObject = {}) return Promise.resolve({ default: { methods: { - arePagePrerequisitesValid: jest.fn().mockReturnValueOnce(arePagePrerequisitesValidObject[pageName]) - } - } - }) - } - }) + arePagePrerequisitesValid: jest + .fn() + .mockReturnValueOnce(arePagePrerequisitesValidObject[pageName]), + }, + }, + }); + }; + }); } diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 733402cdd..db95e0703 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -1,5 +1,9 @@ import { storeActions } from "@/constants/store-actions.js"; -import { getFunnelCookie, updateOrCreateFunnelCookie, deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; +import { + getFunnelCookie, + updateOrCreateFunnelCookie, + deleteFunnelCookie, +} from "@/helpers/heritage-integration/cookie-helper.js"; import baseMixin from "@/mixins/base-mixin"; import store from "@/store"; import { storeMutations } from "@/constants/store-mutations"; @@ -12,9 +16,13 @@ import { storeMutations } from "@/constants/store-mutations"; */ export async function loadSessionIfPresent() { const funnelCookie = getFunnelCookie(); - + // Do nothing if there is no cookie, correlation id, or referral number. - if (funnelCookie == null || funnelCookie.ReferralCorrelationId == null || !funnelCookie.ReferralNumber) { + if ( + funnelCookie == null || + funnelCookie.ReferralCorrelationId == null || + !funnelCookie.ReferralNumber + ) { return null; } @@ -26,7 +34,14 @@ export async function loadSessionIfPresent() { } // Load referral if there is a cookie, and it doesn't indicate it needs a state reset. - return (await loadSession(funnelCookie.ReferralNumber, funnelCookie.ReferralDate, funnelCookie.ReferralCorrelationId, funnelCookie.ReferralParentAccountNumber)).data; + return ( + await loadSession( + funnelCookie.ReferralNumber, + funnelCookie.ReferralDate, + funnelCookie.ReferralCorrelationId, + funnelCookie.ReferralParentAccountNumber + ) + ).data; } /* @@ -37,7 +52,7 @@ export async function loadSessionIfPresent() { export async function saveSession() { var saveSessionPromise; if (store.getters.applicationUser.saveSessionPromise) { - // queue newest request after current saveSessionPromise resolves + // queue newest request after current saveSessionPromise resolves saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => { // get a new saveSessionPromise return saveSessionHelper(); @@ -51,7 +66,6 @@ export async function saveSession() { await saveSessionPromise; } - // PRIVATE FUNCTIONS // /* @@ -61,13 +75,16 @@ export async function saveSession() { async function loadSession(referralNumber, referralDate, referralCorrelationId, accountNumber) { // await the saveSessionPromise in the store to make sure we're loading up to date information await store.getters.applicationUser.saveSessionPromise; - const response = await baseMixin.methods.dispatchStoreAction(storeActions.LOAD_SESSION, + const response = await baseMixin.methods.dispatchStoreAction( + storeActions.LOAD_SESSION, { referralNumber: referralNumber.toString(), referralDate: referralDate, referralCorrelationId: referralCorrelationId, - accountNumber: accountNumber?.toString() - }, false); + accountNumber: accountNumber?.toString(), + }, + false + ); return response; } @@ -78,15 +95,19 @@ async function loadSession(referralNumber, referralDate, referralCorrelationId, async function saveSessionHelper() { const savedSessionInfo = await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_SESSION); // Update the store with information received from the saveSession response - await baseMixin.methods.dispatchStoreAction(storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE, { - referralNumber: savedSessionInfo.data.referralNumber.toString(), - referralCorrelationId: savedSessionInfo.data.referralCorrelationId, - referralDate: savedSessionInfo.data.referralDate, - accountNumber: savedSessionInfo.data.accountNumber.toString(), - savedSessionId: savedSessionInfo.data.savedSessionId, - crmCustomerId: savedSessionInfo.data.crmCustomerId.toString(), - }, false); + await baseMixin.methods.dispatchStoreAction( + storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE, + { + referralNumber: savedSessionInfo.data.referralNumber.toString(), + referralCorrelationId: savedSessionInfo.data.referralCorrelationId, + referralDate: savedSessionInfo.data.referralDate, + accountNumber: savedSessionInfo.data.accountNumber.toString(), + savedSessionId: savedSessionInfo.data.savedSessionId, + crmCustomerId: savedSessionInfo.data.crmCustomerId.toString(), + }, + false + ); // Update the cookie with the referral information when saved. updateOrCreateFunnelCookie(); -} \ No newline at end of file +} diff --git a/src/helpers/heritage-integration/order-helper.spec.js b/src/helpers/heritage-integration/order-helper.spec.js index 5e181a402..5ec0f4f69 100644 --- a/src/helpers/heritage-integration/order-helper.spec.js +++ b/src/helpers/heritage-integration/order-helper.spec.js @@ -1,12 +1,16 @@ import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper"; import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper"; import { cookieNames } from "@/constants/cookie-names"; -import { setupMocksForJsFiles, removeAllTestCookies, getMockOrderInfo, setupCookies } from "@/helpers/unit-test-helper.js"; +import { + setupMocksForJsFiles, + removeAllTestCookies, + getMockOrderInfo, + setupCookies, +} from "@/helpers/unit-test-helper.js"; import { storeActions } from "@/constants/store-actions"; import router from "@/router"; describe("loadSessionIfPresent", () => { - afterEach(() => { removeAllTestCookies(); }); @@ -19,10 +23,12 @@ describe("loadSessionIfPresent", () => { const testCookieValue = { ShouldResetState: testShouldResetState, ReferralCorrelationId: "xxx", - ReferralNumber: "12345" - } + ReferralNumber: "12345", + }; - document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify(testCookieValue)}; path=/; ${cookieHelper.getCookieDomainValue()}`; + document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify( + testCookieValue + )}; path=/; ${cookieHelper.getCookieDomainValue()}`; // Act loadSessionIfPresent(); @@ -34,17 +40,21 @@ describe("loadSessionIfPresent", () => { test("ShouldResetState == true => reset store", () => { // Arrange - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce({ - ShouldResetState: true, - ReferralCorrelationId: "xxx-xxx-xxx", - ReferralNumber: "12345" - }); + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") + .mockReturnValueOnce({ + ShouldResetState: true, + ReferralCorrelationId: "xxx-xxx-xxx", + ReferralNumber: "12345", + }); const mockData = { - actionList: [{ - actionName: storeActions.RESET_STATE - }], - } + actionList: [ + { + actionName: storeActions.RESET_STATE, + }, + ], + }; var mocks = setupMocksForJsFiles(mockData); @@ -53,18 +63,24 @@ describe("loadSessionIfPresent", () => { // Assert expect(cookieHelper.getFunnelCookie).toHaveBeenCalled(); - expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.RESET_STATE); + expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( + storeActions.RESET_STATE + ); }); test("Funnel cookie is null => store is unchanged", () => { // Arrange - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce(null); + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") + .mockReturnValueOnce(null); const mockData = { - actionList: [{ - actionName: storeActions.RESET_STATE - }], - } + actionList: [ + { + actionName: storeActions.RESET_STATE, + }, + ], + }; var mocks = setupMocksForJsFiles(mockData); @@ -73,20 +89,30 @@ describe("loadSessionIfPresent", () => { // Assert expect(cookieHelper.getFunnelCookie).toHaveBeenCalled(); - expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.RESET_STATE); + expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith( + storeActions.RESET_STATE + ); }); test("Funnel cookie valid, should call loadSession", async () => { // Arrange - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") - .mockReturnValueOnce({ ShouldResetState: false, ReferralNumber: 123456, ReferralCorrelationId: "yyy-yyy-yyyy", ReferralDate: new Date()}); + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") + .mockReturnValueOnce({ + ShouldResetState: false, + ReferralNumber: 123456, + ReferralCorrelationId: "yyy-yyy-yyyy", + ReferralDate: new Date(), + }); const mockData = { - actionList: [{ - actionName: storeActions.LOAD_SESSION, - data: { ReferralNumber: 123456, vehicle: { year: 2010 } } - }], - } + actionList: [ + { + actionName: storeActions.LOAD_SESSION, + data: { ReferralNumber: 123456, vehicle: { year: 2010 } }, + }, + ], + }; var mocks = setupMocksForJsFiles(mockData); @@ -95,7 +121,9 @@ describe("loadSessionIfPresent", () => { // Assert expect(cookieHelper.getFunnelCookie).toHaveBeenCalled(); - expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.LOAD_SESSION); + expect(mocks.baseMixin.methods.dispatchStoreAction).not.toHaveBeenCalledWith( + storeActions.LOAD_SESSION + ); expect(result.ReferralNumber).toBe(123456); expect(result.vehicle.year).toBe(2010); }); @@ -113,9 +141,16 @@ describe("saveSession", () => { const mockReferralDate = "2022"; const mockAccountNumber = "167132"; const mockSavedSessionId = "xxx-xxx-xxx"; - const mockCrmCustomerId = "xxx-xxx-xxx" + const mockCrmCustomerId = "xxx-xxx-xxx"; - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo( + mockReferralNumber, + mockCorrelationId, + mockReferralDate, + mockAccountNumber, + mockSavedSessionId, + mockCrmCustomerId + ); const mockData = { actionList: [ @@ -124,10 +159,10 @@ describe("saveSession", () => { data: mockOrderInfo, }, { - actionName: storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE - } - ] - } + actionName: storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE, + }, + ], + }; const mocks = setupMocksForJsFiles(mockData); @@ -135,15 +170,21 @@ describe("saveSession", () => { await saveSession(); // Assert - expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SAVE_SESSION); - expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE, { - referralNumber: mockReferralNumber, - referralDate: mockReferralDate, - referralCorrelationId: mockCorrelationId, - accountNumber: mockAccountNumber, - savedSessionId: mockSavedSessionId, - crmCustomerId: mockCrmCustomerId, - }, false); + expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( + storeActions.SAVE_SESSION + ); + expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( + storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE, + { + referralNumber: mockReferralNumber, + referralDate: mockReferralDate, + referralCorrelationId: mockCorrelationId, + accountNumber: mockAccountNumber, + savedSessionId: mockSavedSessionId, + crmCustomerId: mockCrmCustomerId, + }, + false + ); }); test("saveSession => should update DidHeritageFunnelUpdateLast cookie value to false", async () => { @@ -153,16 +194,25 @@ describe("saveSession", () => { const mockReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; const mockAccountNumber = "167132"; const mockSavedSessionId = "xxx-xxx-xxx"; - const mockCrmCustomerId = "xxx-xxx-xxx" + const mockCrmCustomerId = "xxx-xxx-xxx"; - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockReferralCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo( + mockReferralNumber, + mockReferralCorrelationId, + mockReferralDate, + mockAccountNumber, + mockSavedSessionId, + mockCrmCustomerId + ); const mockData = { - actionList: [{ - actionName: storeActions.SAVE_SESSION, - data: mockOrderInfo, - }], - router: router + actionList: [ + { + actionName: storeActions.SAVE_SESSION, + data: mockOrderInfo, + }, + ], + router: router, }; setupMocksForJsFiles(mockData); @@ -172,8 +222,8 @@ describe("saveSession", () => { ReferralDate: mockReferralDate, ReferralCorrelationId: mockReferralCorrelationId, ShouldResetState: false, - DidHeritageFunnelUpdateLast: true - } + DidHeritageFunnelUpdateLast: true, + }; setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); diff --git a/src/helpers/heritage-integration/session-helper.js b/src/helpers/heritage-integration/session-helper.js index b71602f3c..291ebfaf8 100644 --- a/src/helpers/heritage-integration/session-helper.js +++ b/src/helpers/heritage-integration/session-helper.js @@ -1,5 +1,5 @@ import { applicationConfig } from "@/constants/application-config"; -import { getFunnelCookie} from "@/helpers/heritage-integration/cookie-helper.js"; +import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; /* Method to determine if our analytics session has timed out or not. @@ -9,7 +9,8 @@ export function isAnalyticsSessionStillActive() { if (getFunnelCookie() !== null) { const lastTouchedValue = getFunnelCookie().LastTouched; const timeoutAmount = applicationConfig.ANALYTICS_SESSION_TIMEOUT_MINUTES; - const isMoreThanHalfHourAgo = ((new Date() - new Date(lastTouchedValue)) / 60000) > timeoutAmount; + const isMoreThanHalfHourAgo = + (new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount; if (isMoreThanHalfHourAgo) { return false; @@ -29,7 +30,7 @@ export function isAnalyticsSessionStillActive() { export function isSavedSessionStillActive() { if (getFunnelCookie() !== null) { const savedSessionTimeStamp = new Date(getFunnelCookie().SavedSessionTimeoutDate); - const isSavedSessionTimedOut = (new Date(new Date().toUTCString()) > savedSessionTimeStamp); + const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp; return !isSavedSessionTimedOut; } @@ -40,7 +41,7 @@ Function to calculate the date for the saved session timeout. */ export function getDateForSavedSessionTimeout() { - const currentDate = new Date(new Date().toUTCString()) - currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS) + const currentDate = new Date(new Date().toUTCString()); + currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS); return currentDate.toUTCString(); -} \ No newline at end of file +} diff --git a/src/helpers/heritage-integration/session-helper.spec.js b/src/helpers/heritage-integration/session-helper.spec.js index b41827bf7..fe3e308da 100644 --- a/src/helpers/heritage-integration/session-helper.spec.js +++ b/src/helpers/heritage-integration/session-helper.spec.js @@ -1,14 +1,19 @@ import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper"; -import { isAnalyticsSessionStillActive, isSavedSessionStillActive, getDateForSavedSessionTimeout} from "@/helpers/heritage-integration/session-helper"; +import { + isAnalyticsSessionStillActive, + isSavedSessionStillActive, + getDateForSavedSessionTimeout, +} from "@/helpers/heritage-integration/session-helper"; import { applicationConfig } from "@/constants/application-config"; describe("isAnalyticsSessionStillActive", () => { test("isAnalyticsSessionStillActive, should return true", () => { // Arrange - const mockDate = new Date(new Date().toUTCString()) - mockDate.setDate(mockDate.getDate() + 1) + const mockDate = new Date(new Date().toUTCString()); + mockDate.setDate(mockDate.getDate() + 1); - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") .mockReturnValue({ LastTouched: mockDate }); // Act @@ -20,10 +25,11 @@ describe("isAnalyticsSessionStillActive", () => { test("isAnalyticsSessionStillActive, should return false", () => { // Arrange - const mockDate = new Date(new Date().toUTCString()) - mockDate.setDate(mockDate.getDate() - 1) + const mockDate = new Date(new Date().toUTCString()); + mockDate.setDate(mockDate.getDate() - 1); - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") .mockReturnValue({ LastTouched: mockDate }); // Act @@ -37,10 +43,11 @@ describe("isAnalyticsSessionStillActive", () => { describe("isSavedSessionStillActive", () => { test("isSavedSessionStillActive, should return true", () => { // Arrange - const mockDate = new Date(new Date().toUTCString()) + const mockDate = new Date(new Date().toUTCString()); mockDate.setDate(mockDate.getDate() + 1); - - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") + + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") .mockReturnValue({ SavedSessionTimeoutDate: mockDate }); // Act @@ -52,10 +59,11 @@ describe("isSavedSessionStillActive", () => { test("isSavedSessionStillActive, should return false", () => { // Arrange - const mockDate = new Date(new Date().toUTCString()) - mockDate.setDate(mockDate.getDate() - 1) + const mockDate = new Date(new Date().toUTCString()); + mockDate.setDate(mockDate.getDate() - 1); - cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") + cookieHelper.getFunnelCookie = jest + .spyOn(cookieHelper, "getFunnelCookie") .mockReturnValue({ SavedSessionTimeoutDate: mockDate }); // Act @@ -63,20 +71,19 @@ describe("isSavedSessionStillActive", () => { // Assert expect(result).toBe(false); - }); }); describe("getDateForSavedSessionTimeout", () => { - test("getDateForSavedSessionTimeout, should equal application config setting", () =>{ + test("getDateForSavedSessionTimeout, should equal application config setting", () => { // Arrange - const currentDate = new Date(new Date().toUTCString()) - currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS) - + const currentDate = new Date(new Date().toUTCString()); + currentDate.setDate(currentDate.getDate() + applicationConfig.SAVED_SESSION_TIMEOUT_DAYS); + // Act const result = getDateForSavedSessionTimeout(); // Assert expect(result).toEqual(currentDate.toUTCString()); }); -}) \ No newline at end of file +}); diff --git a/src/helpers/layout-helper.js b/src/helpers/layout-helper.js index 0a8177e25..a07da4ff6 100644 --- a/src/helpers/layout-helper.js +++ b/src/helpers/layout-helper.js @@ -1,27 +1,27 @@ export function settleAllPromises(promiseResultMap) { - // Pull our keys out of the promise 'table' - const promiseNames = Object.entries(promiseResultMap); + // Pull our keys out of the promise 'table' + const promiseNames = Object.entries(promiseResultMap); - return Promise.allSettled( - promiseNames.map((e) => e[1]).map((n) => n.promise) - ).then((results) => { - const resultMap = {}; + return Promise.allSettled(promiseNames.map((e) => e[1]).map((n) => n.promise)).then( + (results) => { + const resultMap = {}; - // Build a map of the results - for (let i = 0; i < results.length; ++i) { - const promiseName = promiseNames[i][1].resultKey; + // Build a map of the results + for (let i = 0; i < results.length; ++i) { + const promiseName = promiseNames[i][1].resultKey; - // Some Promises like the cms content call don't have a 'data' field - // when returned, so other promises do. Map the results to the object - // so that the object is the return data. + // Some Promises like the cms content call don't have a 'data' field + // when returned, so other promises do. Map the results to the object + // so that the object is the return data. - if (results[i]?.value?.data === undefined) { - resultMap[promiseName] = results[i]?.value; - } else { - resultMap[promiseName] = results[i]?.value?.data; - } - } + if (results[i]?.value?.data === undefined) { + resultMap[promiseName] = results[i]?.value; + } else { + resultMap[promiseName] = results[i]?.value?.data; + } + } - return resultMap; - }); + return resultMap; + } + ); } diff --git a/src/helpers/layout-helper.spec.js b/src/helpers/layout-helper.spec.js index d71810756..696a5d907 100644 --- a/src/helpers/layout-helper.spec.js +++ b/src/helpers/layout-helper.spec.js @@ -1,25 +1,25 @@ import { settleAllPromises } from "@/helpers/layout-helper"; it("layout-helper: Should settle all promises and return mapped promise results", () => { - // Arrange - const mockPromiseOne = Promise.resolve({ data: "test-data" }); - const mockPromiseTwo = Promise.resolve({ data: "test-data-two" }); + // Arrange + const mockPromiseOne = Promise.resolve({ data: "test-data" }); + const mockPromiseTwo = Promise.resolve({ data: "test-data-two" }); - const promiseResultMap = [ - { - resultKey: "MockResultOne", - promise: mockPromiseOne, - }, - { - resultKey: "MockResultTwo", - promise: mockPromiseTwo, - }, - ]; + const promiseResultMap = [ + { + resultKey: "MockResultOne", + promise: mockPromiseOne, + }, + { + resultKey: "MockResultTwo", + promise: mockPromiseTwo, + }, + ]; - // Act - settleAllPromises(promiseResultMap).then((results) => { - // Assert - expect(results.MockResultOne).toEqual("test-data"); - expect(results.MockResultTwo).toEqual("test-data-two"); - }); + // Act + settleAllPromises(promiseResultMap).then((results) => { + // Assert + expect(results.MockResultOne).toEqual("test-data"); + expect(results.MockResultTwo).toEqual("test-data-two"); + }); }); diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index cc00e49d9..5e03d4c99 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -6,124 +6,138 @@ import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { cookieNames } from "@/constants/cookie-names"; import { Form } from "vee-validate"; import baseMixin from "@/mixins/base-mixin"; -import { getCookieDomainValue, setCookieProperties } from "@/helpers/heritage-integration/cookie-helper"; -import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes } from "@/constants/analytics"; +import { + getCookieDomainValue, + setCookieProperties, +} from "@/helpers/heritage-integration/cookie-helper"; +import { + analyticsPageEvents, + GaCategories, + GaActions, + GaLabels, + GaEvents, + ValueToLogTypes, +} from "@/constants/analytics"; import { queryStrings } from "@/constants/query-strings"; import { routerParams } from "@/router/router-constants/router-params"; // Common methods export function getMountOptions(mockData) { - // Define our mocks to attached to the 'global' object for Vue/Jest. - const mocks = {}; + // Define our mocks to attached to the 'global' object for Vue/Jest. + const mocks = {}; - //this is mocking if you use the mixin directly(baseMixin.methods.dispatchStoreAction) vs this.dispatchStoreAction - setupBaseMixinDispatchStoreAction(mockData); + //this is mocking if you use the mixin directly(baseMixin.methods.dispatchStoreAction) vs this.dispatchStoreAction + setupBaseMixinDispatchStoreAction(mockData); - mocks.pushEventToGA = jest.fn(); - mocks.pushPageViewToGA = jest.fn(); - mocks.logEvent = jest.fn(); - mocks.pushExperimentsToDataLayer = jest.fn(); - mocks.prependActionToMethod = jest.fn(); - mocks.dispatchStoreAction = jest.fn(); - mocks.dispatchStoreAction.mockImplementation((actionName) => { - let actionFilterResult = mockData.actionList?.filter( - (x) => x.actionName == actionName - ); + mocks.pushEventToGA = jest.fn(); + mocks.pushPageViewToGA = jest.fn(); + mocks.logEvent = jest.fn(); + mocks.pushExperimentsToDataLayer = jest.fn(); + mocks.prependActionToMethod = jest.fn(); + mocks.dispatchStoreAction = jest.fn(); + mocks.dispatchStoreAction.mockImplementation((actionName) => { + let actionFilterResult = mockData.actionList?.filter((x) => x.actionName == actionName); - if (actionFilterResult?.length === 1) { - return Promise.resolve({ - data: actionFilterResult[0].data, - }); - } - }); + if (actionFilterResult?.length === 1) { + return Promise.resolve({ + data: actionFilterResult[0].data, + }); + } + }); - // Mock const files - mocks.storeActions = storeActions; - mocks.storeMutations = storeMutations; - mocks.navigationScenarios = navigationScenarios; - mocks.vehicleCategories = vehicleCategories; - mocks.fmgPageValues = fmgPageValues; - mocks.analyticsPageEvents = analyticsPageEvents; - mocks.GaCategories = GaCategories; - mocks.GaActions = GaActions; - mocks.GaLabels = GaLabels; - mocks.GaEvents = GaEvents; - mocks.ValueToLogTypes = ValueToLogTypes; - mocks.queryStrings = queryStrings; - mocks.routerParams = routerParams; + // Mock const files + mocks.storeActions = storeActions; + mocks.storeMutations = storeMutations; + mocks.navigationScenarios = navigationScenarios; + mocks.vehicleCategories = vehicleCategories; + mocks.fmgPageValues = fmgPageValues; + mocks.analyticsPageEvents = analyticsPageEvents; + mocks.GaCategories = GaCategories; + mocks.GaActions = GaActions; + mocks.GaLabels = GaLabels; + mocks.GaEvents = GaEvents; + mocks.ValueToLogTypes = ValueToLogTypes; + mocks.queryStrings = queryStrings; + mocks.routerParams = routerParams; - // Mock $store and $router when accessing this.$store/$router - mocks.$store = mockData.store; - mocks.$router = mockData.router; - mocks.$route = mockData.route; - mocks.$loadScript = mockData.loadScript; + // Mock $store and $router when accessing this.$store/$router + mocks.$store = mockData.store; + mocks.$router = mockData.router; + mocks.$route = mockData.route; + mocks.$loadScript = mockData.loadScript; - const global = { - mocks: mocks, - mixins: mockData.mixins, - stubs: { Form } - }; + const global = { + mocks: mocks, + mixins: mockData.mixins, + stubs: { Form }, + }; - return { global }; + return { global }; } export function setupMocksForJsFiles(mockData = {}) { - setupBaseMixinDispatchStoreAction(mockData); + setupBaseMixinDispatchStoreAction(mockData); - return { baseMixin }; + return { baseMixin }; } // Heritage integration common methods export const cookies = { - [cookieNames.FUNNEL_SESSION_INFO]: `{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false,"DidHeritageFunnelUpdateLast":true}`, - "UNIQUE_SESSION_ID": "33756020-b58e-4ec7-b8b8-3f1576719c40", - "anotherCookie": "{}", - "someOtherCookie": "{}", - "dxdev": "did=21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe", - "sid": "cba0c3d1-3c1b-4305-bb56-31aa50f58e27", - "skey": "12345" + [cookieNames.FUNNEL_SESSION_INFO]: `{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false,"DidHeritageFunnelUpdateLast":true}`, + UNIQUE_SESSION_ID: "33756020-b58e-4ec7-b8b8-3f1576719c40", + anotherCookie: "{}", + someOtherCookie: "{}", + dxdev: "did=21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe", + sid: "cba0c3d1-3c1b-4305-bb56-31aa50f58e27", + skey: "12345", }; export function removeAllTestCookies() { - Object.keys(cookies).forEach(key => { - document.cookie = `${key}=;Max-Age=0;`; - document.cookie = `${key}=;Max-Age=0;path=/;${getCookieDomainValue()}`; - }); + Object.keys(cookies).forEach((key) => { + document.cookie = `${key}=;Max-Age=0;`; + document.cookie = `${key}=;Max-Age=0;path=/;${getCookieDomainValue()}`; + }); } -export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0", savedSessionId, crmCustomerId) { - return { - referralNumber: mockReferralNumber, - referralCorrelationId: mockCorrelationId, - referralDate: mockReferralDate, - accountNumber: accountNumber, - savedSessionId: savedSessionId, - crmCustomerId: crmCustomerId, - } +export function getMockOrderInfo( + mockReferralNumber, + mockCorrelationId, + mockReferralDate, + accountNumber = "0", + savedSessionId, + crmCustomerId +) { + return { + referralNumber: mockReferralNumber, + referralCorrelationId: mockCorrelationId, + referralDate: mockReferralDate, + accountNumber: accountNumber, + savedSessionId: savedSessionId, + crmCustomerId: crmCustomerId, + }; } export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = true }) { - Object.keys(cookies).forEach(key => { - const cookieValue = key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key]; - if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO) - setCookieProperties({ [key]: cookieValue }, { isSecure: false }); - }); + Object.keys(cookies).forEach((key) => { + const cookieValue = + key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key]; + if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO) + setCookieProperties({ [key]: cookieValue }, { isSecure: false }); + }); } // Private methods function setupBaseMixinDispatchStoreAction(mockData) { - if (mockData.actionList !== undefined) { - baseMixin.methods.dispatchStoreAction = jest.fn(); - baseMixin.methods.dispatchStoreAction.mockImplementation((actionName) => { - let actionFilterResult = mockData.actionList.filter( - (x) => x.actionName == actionName - ); + if (mockData.actionList !== undefined) { + baseMixin.methods.dispatchStoreAction = jest.fn(); + baseMixin.methods.dispatchStoreAction.mockImplementation((actionName) => { + let actionFilterResult = mockData.actionList.filter((x) => x.actionName == actionName); - if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { - return Promise.resolve({ - data: actionFilterResult[0].data, + if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { + return Promise.resolve({ + data: actionFilterResult[0].data, + }); + } }); - } - }); - } -} \ No newline at end of file + } +} diff --git a/src/helpers/validation-rules.js b/src/helpers/validation-rules.js index 9b2e14d58..0ef03cbe3 100644 --- a/src/helpers/validation-rules.js +++ b/src/helpers/validation-rules.js @@ -4,7 +4,7 @@ export function required(errorMessage) { return errorMessage; } return true; - }; + }; } export function regex(expression, errorMessage) { @@ -20,6 +20,5 @@ export function regex(expression, errorMessage) { } return true; - } - -} \ No newline at end of file + }; +} diff --git a/src/helpers/validation-rules.spec.js b/src/helpers/validation-rules.spec.js index 7e0c6304e..223727d37 100644 --- a/src/helpers/validation-rules.spec.js +++ b/src/helpers/validation-rules.spec.js @@ -2,71 +2,66 @@ import { required } from "@/helpers/validation-rules"; import { regex } from "@/helpers/validation-rules"; describe("validation-rules.vue", () => { - test("required rules should return error if value missing", () => { + test("required rules should return error if value missing", () => { + //Arrange + const testFn = required("an error"); - //Arrange - const testFn = required("an error"); - - //Act - const testResponse = testFn(); + //Act + const testResponse = testFn(); - //Assert - expect(testResponse).toBe("an error"); - }); + //Assert + expect(testResponse).toBe("an error"); + }); }); describe("validation-rules.vue", () => { - test("required rules should return true if value present", () => { + test("required rules should return true if value present", () => { + //Arrange + const testFn = required("an error"); - //Arrange - const testFn = required("an error"); - - //Act - const testResponse = testFn('some value'); - - //Assert - expect(testResponse).toBe(true); - }); + //Act + const testResponse = testFn("some value"); + + //Assert + expect(testResponse).toBe(true); + }); }); describe("validation-rules.vue", () => { - test("regex rules should return true if value is not present", () => { + test("regex rules should return true if value is not present", () => { + //Arrange + const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - //Arrange - const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - - //Act - const testResponse = testFn(); - - //Assert - expect(testResponse).toBe(true); - }); + //Act + const testResponse = testFn(); + + //Assert + expect(testResponse).toBe(true); + }); }); describe("validation-rules.vue", () => { - test("regex rules should return false if value is present but does not match regular expression", () => { + test("regex rules should return false if value is present but does not match regular expression", () => { + //Arrange + const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - //Arrange - const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - - //Act - const testResponse = testFn('4321'); // needs to be 5 numbers - - //Assert - expect(testResponse).toBe("an error"); - }); + //Act + const testResponse = testFn("4321"); // needs to be 5 numbers + + //Assert + expect(testResponse).toBe("an error"); + }); }); describe("validation-rules.vue", () => { - test("regex rules should return true if value is present and does match regular expression", () => { + test("regex rules should return true if value is present and does match regular expression", () => { + //Arrange + const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - //Arrange - const testFn = regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, "an error"); // Using Zip regex - - //Act - const testResponse = testFn('43213'); // needs to be 5 numbers - - //Assert - expect(testResponse).toBe(true); - }); -}); \ No newline at end of file + //Act + const testResponse = testFn("43213"); // needs to be 5 numbers + + //Assert + expect(testResponse).toBe(true); + }); +}); diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index 2f17cd220..bd8689298 100644 --- a/src/layouts/address-lookup/address-lookup.spec.js +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -11,665 +11,720 @@ import { navigationScenarios } from "@/router/router-constants/navigation-scenar import store from "@/store"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; - jest.mock("@/helpers/damage-helper", () => ({ - isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), - getDamageString: jest.fn() + isGlassAvailableForCarId: jest.fn().mockImplementation(() => true), + getDamageString: jest.fn(), })); jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({ - navigateToHeritageFunnel: jest.fn() + navigateToHeritageFunnel: jest.fn(), })); // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), + settleAllPromises: jest.fn(), })); describe("address-lookup.vue", () => { - describe("page level alerts", () => { - test("if the address is not serviceable display the Non-Serviceable Zip Alert", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipValid: true, - isZipServiceable: false, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "C0000" - } - }] - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true); - - }); - - test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - vinVehicles: [ - { - vehicle: { - carId: "C00000" - } - } - ] - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID2"); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(true); - }); - - test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - isStatePermissible: false, - lookupVinbyAddressResponse: { - isStatePermissible: false, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }, - { - vin: "TEST_VIN2", - vehicle: { - carId: "CARID2" - } - }] - } - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()).toBe(true); - - }); - - test("if no vehicles found, display Vin Not Found alert", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - lookupVinbyAddressResponse: { - isStatePermissible: true, - vinVehicles: [] // Return no vehicles - } - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - wrapper.vm.navigateForward = jest.fn(); - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true); - - }); - }); - - describe("navigation", () => { - - test("if the back button is clicked, navigate back", async () => { - // Arrange - const { wrapper } = setupMocks({ - isZipServiceable: true - }); - - // Act - await wrapper.vm.backButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - - }); - - test("if the car entered matches one of the vehicles found and the zip is serviceable, navigate forward", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - vinVehicles: [ - { - vehicle: { - carId: "C11111" - } - } - ] - }); - - await wrapper.setData({ - previouslyEnteredCarId: "C11111", - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - wrapper.vm.navigateForward = jest.fn(); - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); - }); - - test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - isStatePermissible: true, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }, - { - vin: "TEST_VIN2", - vehicle: { - carId: "CARID2" - } - }] - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A"); - - const carsFound = [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }, - { - vin: "TEST_VIN2", - vehicle: { - carId: "CARID2" - } - }] - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - wrapper.vm.updateVehicleInfo = jest.fn(); - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, carsFound); - }); - - test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: false, - isStatePermissible: true, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }, - { - vin: "TEST_VIN2", - vehicle: { - carId: "CARID2" - } - }] - }); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - }) - - wrapper.vm.navigateForward = jest.fn(); - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0); - - }); - - test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true, - isStatePermissible: true - }); - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - }, - isCarIdDifferent: true, - isSelectedGlassAvailableForVehicle: false, - }) - - let carsFound = [{ - vin: "TEST_VIN2", - vehicle: { - carId: "C0000" - } - }]; - - // Act - await wrapper.vm.navigateForward(carsFound); - - // Assert - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, undefined, {}, { "displayVehicleChangeAlert": true }); - - }); - - test("single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch", async () => { - // Arrange - - const carsFound = [ - { - vin: "TEST_VIN_2", - vehicle: { - carId: "C0000" - } - } - ]; - - const { wrapper } = setupMocks({}, {}); - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - - // Act - wrapper.vm.navigateForward(carsFound); - - // Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); - }); - - test("multiple cars were found and one matches entered vehicle => navigateForwardWithSingleCarMatch", async () => { - // Arrange - const carsFound = [ - { - vin: "TEST_VIN_1", - vehicle: { - carId: "C0000" - } - }, - { - vin: "TEST_VIN_2", - vehicle: { - carId: "CARID2" - } - }, - { - vin: "TEST_VIN_3", - vehicle: { - carId: "CARID3" - } - } - ]; - - const { wrapper } = setupMocks({}); - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - - // Act - wrapper.vm.navigateForward(carsFound); - - // Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); - }); - }); - - describe("registration and service zips", () => { - describe("if registration zip is serviceable", () => { - test("if registration address is provided => update service address on successful continue", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipServiceable: true + describe("page level alerts", () => { + test("if the address is not serviceable display the Non-Serviceable Zip Alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipValid: true, + isZipServiceable: false, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "C0000", + }, + }, + ], + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true); }); - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - } - }) + const { wrapper } = setupMocks({ + isZipServiceable: true, + vinVehicles: [ + { + vehicle: { + carId: "C00000", + }, + }, + ], + }); - // Act - await wrapper.vm.forwardButtonAction(); + store.commit(storeMutations.UPDATE_CAR_ID, "CARID2"); - // Assert - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith("lookupVinByAddress", {"licenseLastName": undefined, "licenseState": "OH", "licenseStreetAddress": "1234 Main St", "licenseZip": "43215"}, false); + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); - expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith("validateZip", {"zip": "43215"}); - }); - }); + // Act + await wrapper.vm.forwardButtonAction(); - describe("if registration zip is not serviceable", () => { - test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } - - const { wrapper } = setupMocks({ - isZipValid: true, - isZipServiceable: false, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "C0000" - } - }] + // Assert + expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe( + true + ); }); - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - } - }) + const { wrapper } = setupMocks({ + isZipServiceable: true, + isStatePermissible: false, + lookupVinbyAddressResponse: { + isStatePermissible: false, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + { + vin: "TEST_VIN2", + vehicle: { + carId: "CARID2", + }, + }, + ], + }, + }); - expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(false); + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - // Act - await wrapper.vm.forwardButtonAction(); + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); - // Assert - expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true); - expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(true); - expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true); - }); + // Act + await wrapper.vm.forwardButtonAction(); - test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } + // Assert + expect( + wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible() + ).toBe(true); + }); - const { wrapper } = setupMocks({ - isZipServiceable: false - } - ); + test("if no vehicles found, display Vin Not Found alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + const { wrapper } = setupMocks({ + isZipServiceable: true, + lookupVinbyAddressResponse: { + isStatePermissible: true, + vinVehicles: [], // Return no vehicles + }, + }); - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - } - }) + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - // Act - await wrapper.vm.forwardButtonAction(); + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); - // Assert - expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION); - }); + wrapper.vm.navigateForward = jest.fn(); - test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => { - // Arrange - const mockRegistrationAddress = { - streetAddress: "1234 Main St", - city: "Columbus", - state: "OH", - zipCode: "43215" - } + // Act + await wrapper.vm.forwardButtonAction(); - const { wrapper } = setupMocks({}); - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - - store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); - - wrapper.vm.dispatchStoreAction = jest.fn(); - wrapper.vm.dispatchStoreAction.mockImplementation((actionName, value) => { - let data = {}; - if (actionName == storeActions.VALIDATE_ZIP) { - if (value == "43215") { - data = { - isServiceable: false - }; - } - else { - data = { - isServiceable: true - } - } - } - else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) { - data = { - isStatePermissible: true, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }] - } - } - - return Promise.resolve({ data }); - }) - - await wrapper.setData({ - customerQuestions: { - addressQuestions: mockRegistrationAddress - } - }) - - await wrapper.vm.forwardButtonAction(); - await wrapper.setData({ - serviceZipCode: "12345" - }) - - // // Act - await wrapper.vm.forwardButtonAction(); - - // // Assert - expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).not.toEqual(wrapper.vm.$store.getters.vehicle.registration.zipCode); - expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345"); - expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("11111"); - }); + // Assert + expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true); + }); + }); + + describe("navigation", () => { + test("if the back button is clicked, navigate back", async () => { + // Arrange + const { wrapper } = setupMocks({ + isZipServiceable: true, + }); + + // Act + await wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); + }); + + test("if the car entered matches one of the vehicles found and the zip is serviceable, navigate forward", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: true, + vinVehicles: [ + { + vehicle: { + carId: "C11111", + }, + }, + ], + }); + + await wrapper.setData({ + previouslyEnteredCarId: "C11111", + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); + + test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: true, + isStatePermissible: true, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + { + vin: "TEST_VIN2", + vehicle: { + carId: "CARID2", + }, + }, + ], + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A"); + + const carsFound = [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + { + vin: "TEST_VIN2", + vehicle: { + carId: "CARID2", + }, + }, + ]; + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + wrapper.vm.updateVehicleInfo = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( + navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, + undefined, + {}, + {}, + carsFound + ); + }); + + test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: false, + isStatePermissible: true, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + { + vin: "TEST_VIN2", + vehicle: { + carId: "CARID2", + }, + }, + ], + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + wrapper.vm.navigateForward = jest.fn(); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0); + }); + + test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: true, + isStatePermissible: true, + }); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + isCarIdDifferent: true, + isSelectedGlassAvailableForVehicle: false, + }); + + let carsFound = [ + { + vin: "TEST_VIN2", + vehicle: { + carId: "C0000", + }, + }, + ]; + + // Act + await wrapper.vm.navigateForward(carsFound); + + // Assert + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( + navigationScenarios.SELECTED_VIN_HAS_MISMATCHED_GLASS, + undefined, + {}, + { displayVehicleChangeAlert: true } + ); + }); + + test("single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch", async () => { + // Arrange + + const carsFound = [ + { + vin: "TEST_VIN_2", + vehicle: { + carId: "C0000", + }, + }, + ]; + + const { wrapper } = setupMocks({}, {}); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + // Act + wrapper.vm.navigateForward(carsFound); + + // Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); + }); + + test("multiple cars were found and one matches entered vehicle => navigateForwardWithSingleCarMatch", async () => { + // Arrange + const carsFound = [ + { + vin: "TEST_VIN_1", + vehicle: { + carId: "C0000", + }, + }, + { + vin: "TEST_VIN_2", + vehicle: { + carId: "CARID2", + }, + }, + { + vin: "TEST_VIN_3", + vehicle: { + carId: "CARID3", + }, + }, + ]; + + const { wrapper } = setupMocks({}); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + // Act + wrapper.vm.navigateForward(carsFound); + + // Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); + }); + }); + + describe("registration and service zips", () => { + describe("if registration zip is serviceable", () => { + test("if registration address is provided => update service address on successful continue", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: true, + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith( + "lookupVinByAddress", + { + licenseLastName: undefined, + licenseState: "OH", + licenseStreetAddress: "1234 Main St", + licenseZip: "43215", + }, + false + ); + + expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith("validateZip", { + zip: "43215", + }); + }); + }); + + describe("if registration zip is not serviceable", () => { + test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipValid: true, + isZipServiceable: false, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "C0000", + }, + }, + ], + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe( + false + ); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe( + true + ); + expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe( + true + ); + }); + + test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({ + isZipServiceable: false, + }); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalledWith( + storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION + ); + }); + + test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => { + // Arrange + const mockRegistrationAddress = { + streetAddress: "1234 Main St", + city: "Columbus", + state: "OH", + zipCode: "43215", + }; + + const { wrapper } = setupMocks({}); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + store.commit(storeMutations.UPDATE_CAR_ID, "CARID"); + + wrapper.vm.dispatchStoreAction = jest.fn(); + wrapper.vm.dispatchStoreAction.mockImplementation((actionName, value) => { + let data = {}; + if (actionName == storeActions.VALIDATE_ZIP) { + if (value == "43215") { + data = { + isServiceable: false, + }; + } else { + data = { + isServiceable: true, + }; + } + } else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) { + data = { + isStatePermissible: true, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + ], + }; + } + + return Promise.resolve({ data }); + }); + + await wrapper.setData({ + customerQuestions: { + addressQuestions: mockRegistrationAddress, + }, + }); + + await wrapper.vm.forwardButtonAction(); + await wrapper.setData({ + serviceZipCode: "12345", + }); + + // // Act + await wrapper.vm.forwardButtonAction(); + + // // Assert + expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).not.toEqual( + wrapper.vm.$store.getters.vehicle.registration.zipCode + ); + expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345"); + expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("11111"); + }); + }); }); - }); }); -function setupMocks({ isZipValid = true, isZipServiceable = true, lookupVinbyAddressResponse, partsOrQuestions = [], isStatePermissible = true, vinVehicles =[], carId = 'C0000' }) { - store.commit(storeMutations.RESET_STATE); - const wrapper = shallowMount(addressLookup, getMountOptions({ - actionList: [ - { - actionName: storeActions.VALIDATE_ZIP, - data: { - isValid: isZipValid, - isServiceable: isZipServiceable - } - }, - { - actionName: storeActions.LOOKUP_VIN_BY_ADDRESS, - data: lookupVinbyAddressResponse ? lookupVinbyAddressResponse : { - isStatePermissible: true, - vinVehicles: [{ - vin: "TEST_VIN", - vehicle: { - carId: "CARID" - } - }] - } - }, - { - actionName: storeActions.GET_PARTS_OR_QUESTIONS, - data: { - partsOrQuestions: partsOrQuestions - } - }, - ], - router: { - navigate: jest.fn(), - navigate: jest.fn(), - navigateWithSaving: jest.fn(), - navigateWithoutSaving: jest.fn(), - }, - store: { - getters: { - vehicle: { - carId: carId, - registration: { - licensePlate: "TESTPLATE", - zipCode: "12345" - } +function setupMocks({ + isZipValid = true, + isZipServiceable = true, + lookupVinbyAddressResponse, + partsOrQuestions = [], + isStatePermissible = true, + vinVehicles = [], + carId = "C0000", +}) { + store.commit(storeMutations.RESET_STATE); + const wrapper = shallowMount( + addressLookup, + getMountOptions({ + actionList: [ + { + actionName: storeActions.VALIDATE_ZIP, + data: { + isValid: isZipValid, + isServiceable: isZipServiceable, + }, + }, + { + actionName: storeActions.LOOKUP_VIN_BY_ADDRESS, + data: lookupVinbyAddressResponse + ? lookupVinbyAddressResponse + : { + isStatePermissible: true, + vinVehicles: [ + { + vin: "TEST_VIN", + vehicle: { + carId: "CARID", + }, + }, + ], + }, + }, + { + actionName: storeActions.GET_PARTS_OR_QUESTIONS, + data: { + partsOrQuestions: partsOrQuestions, + }, + }, + ], + router: { + navigate: jest.fn(), + navigate: jest.fn(), + navigateWithSaving: jest.fn(), + navigateWithoutSaving: jest.fn(), + }, + store: { + getters: { + vehicle: { + carId: carId, + registration: { + licensePlate: "TESTPLATE", + zipCode: "12345", + }, + }, + order: { + customer: { + emailAddress: "test@test.com", + }, + serviceLocation: { + zipCode: "11111", + }, + }, + }, + }, + }) + ); + + const apiResponses = { + serviceZipValidationResponse: { + isValid: isZipValid, + isServiceable: isZipServiceable, }, - order: { - customer: { - emailAddress: "test@test.com" - }, - serviceLocation: { - zipCode: "11111" - } - } - } - }, - })); + vinLookupResponse: { + isStatePermissible: isStatePermissible, + vinVehicles: vinVehicles, + }, + }; - const apiResponses = { - serviceZipValidationResponse: { - isValid: isZipValid, - isServiceable: isZipServiceable - }, - vinLookupResponse: { - isStatePermissible: isStatePermissible, - vinVehicles: vinVehicles - }, - }; + settleAllPromises.mockImplementation(() => apiResponses); - settleAllPromises.mockImplementation(() => apiResponses); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); - wrapper.vm.setCmsContent = jest.fn(); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.$refs.loadingModal.showModal = jest.fn(); - - return { wrapper }; + return { wrapper }; } - diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index a68012e17..f04797d08 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -1,61 +1,83 @@ diff --git a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js index 5802adf6e..4a8e87feb 100644 --- a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js +++ b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.spec.js @@ -11,620 +11,649 @@ import store from "@/store"; let autocompleteElement; describe("address-questions.vue", () => { - beforeEach(() => { - // Create the `addressField1` element (autocomplete's input) - autocompleteElement = document.createElement("input") - autocompleteElement.getPlace = jest.fn(); - document.getElementById = jest.fn().mockReturnValue(autocompleteElement); - }) - - describe("initial state", () => { - test("only street address field is shown", () => { - // Arrange - const { wrapper } = setupMocks({}); - - // Assert - const streetAddressField = wrapper.findComponent({ ref: "autocomplete" }); - const cityField = wrapper.findComponent({ ref: "city" }); - const stateField = wrapper.findComponent({ ref: "state" }); - const zipCodeField = wrapper.findComponent({ ref: "zipCode" }); - - expect(streetAddressField.exists()).toBe(true); - expect(streetAddressField.isVisible()).toBe(true); - expect(cityField.exists()).toBe(true); - expect(cityField.isVisible()).toBe(false); - expect(stateField.exists()).toBe(true); - expect(stateField.isVisible()).toBe(false); - expect(zipCodeField.exists()).toBe(true); - expect(zipCodeField.isVisible()).toBe(false); - - const alerts = wrapper.findAllComponents(alert); - expect(alerts.length).toEqual(0); - }) - - test("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => { - // Arrange - const { wrapper } = setupMocks({}); - - // Act - const streetAddress = wrapper.findComponent({ ref: 'autocomplete' }); - const city = wrapper.findComponent({ ref: 'city' }); - const state = wrapper.findComponent({ ref: 'state' }); - const zipCode = wrapper.findComponent({ ref: 'zipCode' }); - - // Assert - expect(streetAddress.exists()).toBe(true); - expect(city.exists()).toBe(true); - expect(state.exists()).toBe(true); - expect(zipCode.exists()).toBe(true); + beforeEach(() => { + // Create the `addressField1` element (autocomplete's input) + autocompleteElement = document.createElement("input"); + autocompleteElement.getPlace = jest.fn(); + document.getElementById = jest.fn().mockReturnValue(autocompleteElement); }); - test("Should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => { - // Arrange - const newAddressModel = { - streetAddress: "foo", - city: "foo", - state: "foo", - zipCode: "55555", - }; - const wrapper = shallowMount(addressQuestions, { - propsData: { - modelValue: newAddressModel, - }, - }); + describe("initial state", () => { + test("only street address field is shown", () => { + // Arrange + const { wrapper } = setupMocks({}); - await wrapper.setData({ - displayNoMatchWarning: true - }) - expect(wrapper.vm.displayNoMatchWarning).toBeTruthy(); + // Assert + const streetAddressField = wrapper.findComponent({ ref: "autocomplete" }); + const cityField = wrapper.findComponent({ ref: "city" }); + const stateField = wrapper.findComponent({ ref: "state" }); + const zipCodeField = wrapper.findComponent({ ref: "zipCode" }); - // Act - wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, wrapper.vm.addressModel); + expect(streetAddressField.exists()).toBe(true); + expect(streetAddressField.isVisible()).toBe(true); + expect(cityField.exists()).toBe(true); + expect(cityField.isVisible()).toBe(false); + expect(stateField.exists()).toBe(true); + expect(stateField.isVisible()).toBe(false); + expect(zipCodeField.exists()).toBe(true); + expect(zipCodeField.isVisible()).toBe(false); - // Assert - expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); - }); - - test("Should it set this.showAddressFields to true when the model is prepopulated", async () => { - // Arrange - // Act - const newAddressModel = { - streetAddress: "foo", - city: "foo", - state: "foo", - zipCode: "55555", - }; - const wrapper = shallowMount(addressQuestions, { - propsData: { - modelValue: newAddressModel, - }, - }); - - // Act - wrapper.vm.setupAddressLookup(); - - // Assert - expect(wrapper.vm.showAddressFields).toBe(true); - - }); - }); - - describe("happy paths", () => { - test("full street address is passed in => address fields are displayed", async () => { - // Arrange/Act - const { wrapper } = setupMocks({ - props: { - modelValue: { - streetAddress: "12345 Test Road", - city: "Tests", - state: "OH", - zipCode: "12312" - } - } - }); - - await wrapper.vm.$nextTick(); - - // Assert - const cityField = wrapper.findComponent({ ref: "city" }); - const stateField = wrapper.findComponent({ ref: "state" }); - const zipField = wrapper.findComponent({ ref: "zipCode" }); - expect(cityField.exists()).toBeTruthy(); - expect(cityField.isVisible()).toBeTruthy(); - expect(stateField.exists()).toBeTruthy(); - expect(cityField.isVisible()).toBeTruthy(); - expect(zipField.exists()).toBeTruthy(); - expect(cityField.isVisible()).toBeTruthy(); - }); - - test("full street address is passed in => don't load Google Autocomplete script", async () => { - // Arrange/Act - const { wrapper } = setupMocks({ - props: { - modelValue: { - streetAddress: "12345 Test Road", - city: "Tests", - state: "OH", - zipCode: "12312" - } - } - }); - - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.$loadScript).not.toHaveBeenCalled(); - }); - - test("address field is focused => disable autocomplete", async () => { - // Arrange - let focusEventCallbackFunction; - autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => { - if (eventName == "focus") { - focusEventCallbackFunction = callbackFunction; - } - }); - const { wrapper } = setupMocks({}); - await wrapper.vm.$nextTick(); - - // Act - focusEventCallbackFunction(); - await wrapper.vm.$nextTick(); - - // Assert - expect(autocompleteElement.getAttribute("autocomplete")).toEqual("do-not-autofill"); - }); - - test("street address is entered, user chooses good result from autocomplete results => other fields are filled in", async () => { - // Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - addressModel: { - streetAddress: "123 Test Street" - } - }) - - const selectedPlace = { - address_components: [ - { - long_name: "1234", - short_name: "1234", - types: ["street_number"] - }, - { - long_name: "Test Road", - short_name: "Test Road", - types: ["route"] - }, - { - long_name: "East Columbus", - short_name: "Columbus", - types: ["neighborhood", "political"] - }, - { - long_name: "Columbus", - short_name: "Columbus", - types: ["locality", "political"] - }, - { - long_name: "Franklin County", - short_name: "Franklin County", - types: ["administrative_area_level_2", "political"] - }, - { - long_name: "Ohio", - short_name: "OH", - types: ["administrative_area_level_1", "political"] - }, - { - long_name: "United States", - short_name: "US", - types: ["country", "political"] - }, - { - long_name: "43215", - short_name: "43215", - types: ["postal_code"] - }, - ] - } - - // Act - autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace })); - - // Assert - const addressModel = wrapper.vm.addressModel; - expect(addressModel.streetAddress).toEqual("1234 Test Road"); - expect(addressModel.city).toEqual("Columbus"); - expect(addressModel.state).toEqual("OH"); - expect(addressModel.zipCode).toEqual("43215"); - }) - - test("street address is entered, user chooses good result from autocomplete results => alerts are cleared", async () => { - // Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - addressModel: { - streetAddress: "123 Test Street" - }, - displayVerificationWarning: true, - displayNoMatchWarning: true - }) - - let alerts = wrapper.findAllComponents(alert); - alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy()); - - const selectedPlace = { - address_components: [ - { - long_name: "1234", - short_name: "1234", - types: ["street_number"] - }, - { - long_name: "Test Road", - short_name: "Test Road", - types: ["route"] - }, - { - long_name: "East Columbus", - short_name: "Columbus", - types: ["neighborhood", "political"] - }, - { - long_name: "Columbus", - short_name: "Columbus", - types: ["locality", "political"] - }, - { - long_name: "Franklin County", - short_name: "Franklin County", - types: ["administrative_area_level_2", "political"] - }, - { - long_name: "Ohio", - short_name: "OH", - types: ["administrative_area_level_1", "political"] - }, - { - long_name: "United States", - short_name: "US", - types: ["country", "political"] - }, - { - long_name: "43215", - short_name: "43215", - types: ["postal_code"] - }, - ] - } - - // Act - autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace })); - await wrapper.vm.$nextTick(); - - // Assert - alerts = wrapper.findAllComponents(alert); - alerts.forEach(alert => expect(alert.exists()).toBeFalsy()); - }); - - test("street address is entered, but user clicks away => first result is selected and other fields are filled in", async () => { - // Arrange - let changeEventCallbackFunction; - autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => { - if (eventName == "change") { - changeEventCallbackFunction = callbackFunction; - } - }); - - const { wrapper } = setupMocks({ - querySelectorFunction: function (query) { - if (query == ".pac-container .pac-item") { - let element = document.createElement("div"); - element.textContent = "123 Test Street" - return element; - } - }, - geocoderResult: { - address_components: [ - { - long_name: "1234", - short_name: "1234", - types: ["street_number"] - }, - { - long_name: "Test Road", - short_name: "Test Road", - types: ["route"] - }, - { - long_name: "East Columbus", - short_name: "Columbus", - types: ["neighborhood", "political"] - }, - { - long_name: "Columbus", - short_name: "Columbus", - types: ["locality", "political"] - }, - { - long_name: "Franklin County", - short_name: "Franklin County", - types: ["administrative_area_level_2", "political"] - }, - { - long_name: "Ohio", - short_name: "OH", - types: ["administrative_area_level_1", "political"] - }, - { - long_name: "United States", - short_name: "US", - types: ["country", "political"] - }, - { - long_name: "43215", - short_name: "43215", - types: ["postal_code"] - }, - ] - } - }); - - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - expect(verificationAlert.exists()).toBeFalsy(); - - await wrapper.vm.$nextTick(); - - // Act - changeEventCallbackFunction(); - - await wrapper.vm.$nextTick(); - - // Assert - const addressModel = wrapper.vm.addressModel; - expect(addressModel.streetAddress).toEqual("1234 Test Road"); - expect(addressModel.city).toEqual("Columbus"); - expect(addressModel.state).toEqual("OH"); - expect(addressModel.zipCode).toEqual("43215"); - }); - }); - - describe("alerts", () => { - const places = [null, { address_components: null }, undefined, {}]; - test.each(places)("selected place/place properties is null => display verification alert", async (place) => { - // Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - addressModel: { - streetAddress: "123 Test Street" - }, - displayVerificationWarning: true, - displayNoMatchWarning: true - }) - - let alerts = wrapper.findAllComponents(alert); - alerts.forEach(alert => expect(alert.isVisible()).toBeTruthy()); - - const selectedPlace = place; - - // Act - autocompleteElement.dispatchEvent(new CustomEvent("place_changed", { detail: selectedPlace })); - await wrapper.vm.$nextTick(); - - // Assert - const verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); - expect(verificationAlert.exists()).toBe(true); - expect(verificationAlert.isVisible()).toBe(true); - const noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBe(false); - }); - - test("user enters address that yields no autocomplete results => show noMatch alert", async () => { - // Arrange - let changeEventCallbackFunction; - autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => { - if (eventName == "change") { - changeEventCallbackFunction = callbackFunction; - } - }); - - const { wrapper } = setupMocks({}); - - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - - await wrapper.vm.$nextTick(); - - // Act - changeEventCallbackFunction(); - - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayNoMatchWarning).toBeTruthy(); - noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeTruthy(); - expect(noMatchAlert.isVisible()).toBeTruthy(); - }); - - test("user enters address that yields autocomplete results, but doesn't select => show verification alert", async () => { - // Arrange - let changeEventCallbackFunction; - autocompleteElement.addEventListener = jest.fn().mockImplementation((eventName, callbackFunction) => { - if (eventName == "change") { - changeEventCallbackFunction = callbackFunction; - } - }); - - const { wrapper } = setupMocks({ - querySelectorFunction: function (query) { - if (query == ".pac-container .pac-item") { - let element = document.createElement("div"); - element.textContent = "123 Test Street" - return element; - } - } - }); - - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - expect(verificationAlert.exists()).toBeFalsy(); - - await wrapper.vm.$nextTick(); - - // Act - changeEventCallbackFunction(); - - await wrapper.vm.$nextTick(); - - // Assert - verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); - expect(wrapper.vm.displayVerificationWarning).toBeTruthy(); - expect(verificationAlert.exists()).toBeTruthy(); - expect(verificationAlert.isVisible()).toBeTruthy(); - noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); - expect(noMatchAlert.exists()).toBeFalsy(); - }); - - describe("noMatch alert is cleared on address change", () => { - test("user sees noMatch warning and enters city => noMatch warning is removed", async () => { - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.setData({ - displayNoMatchWarning: true + const alerts = wrapper.findAllComponents(alert); + expect(alerts.length).toEqual(0); }); - await wrapper.vm.$nextTick(); - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeTruthy(); - expect(noMatchAlert.isVisible()).toBeTruthy(); + test("Should render addressQuestions sub-components (textbox-questions and dropdown-questions)", async () => { + // Arrange + const { wrapper } = setupMocks({}); - // Act - wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { - city: "Somewhere" - }) - await wrapper.vm.$nextTick(); + // Act + const streetAddress = wrapper.findComponent({ ref: "autocomplete" }); + const city = wrapper.findComponent({ ref: "city" }); + const state = wrapper.findComponent({ ref: "state" }); + const zipCode = wrapper.findComponent({ ref: "zipCode" }); - // Assert - expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); - noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - }); - - test("user sees noMatch warning and enters state => noMatch warning is removed", async () => { - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.setData({ - displayNoMatchWarning: true + // Assert + expect(streetAddress.exists()).toBe(true); + expect(city.exists()).toBe(true); + expect(state.exists()).toBe(true); + expect(zipCode.exists()).toBe(true); }); - await wrapper.vm.$nextTick(); - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeTruthy(); - expect(noMatchAlert.isVisible()).toBeTruthy(); + test("Should set this.displayNoMatchWarning to false when it is set to true, if the model if prepopulated", async () => { + // Arrange + const newAddressModel = { + streetAddress: "foo", + city: "foo", + state: "foo", + zipCode: "55555", + }; + const wrapper = shallowMount(addressQuestions, { + propsData: { + modelValue: newAddressModel, + }, + }); - // Act - wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { - state: "KO" - }) - await wrapper.vm.$nextTick(); + await wrapper.setData({ + displayNoMatchWarning: true, + }); + expect(wrapper.vm.displayNoMatchWarning).toBeTruthy(); - // Assert - expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); - noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - }); + // Act + wrapper.vm.$options.watch.addressModel.handler.call( + wrapper.vm, + wrapper.vm.addressModel + ); - test("user sees noMatch warning and enters zip code => noMatch warning is removed", async () => { - // Arrange - const { wrapper } = setupMocks({}); - - wrapper.setData({ - displayNoMatchWarning: true + // Assert + expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); }); - await wrapper.vm.$nextTick(); - let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeTruthy(); - expect(noMatchAlert.isVisible()).toBeTruthy(); + test("Should it set this.showAddressFields to true when the model is prepopulated", async () => { + // Arrange + // Act + const newAddressModel = { + streetAddress: "foo", + city: "foo", + state: "foo", + zipCode: "55555", + }; + const wrapper = shallowMount(addressQuestions, { + propsData: { + modelValue: newAddressModel, + }, + }); - // Act - wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { - zipCode: "12345" - }) - await wrapper.vm.$nextTick(); + // Act + wrapper.vm.setupAddressLookup(); - // Assert - expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); - noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); - expect(noMatchAlert.exists()).toBeFalsy(); - }); + // Assert + expect(wrapper.vm.showAddressFields).toBe(true); + }); + }); + + describe("happy paths", () => { + test("full street address is passed in => address fields are displayed", async () => { + // Arrange/Act + const { wrapper } = setupMocks({ + props: { + modelValue: { + streetAddress: "12345 Test Road", + city: "Tests", + state: "OH", + zipCode: "12312", + }, + }, + }); + + await wrapper.vm.$nextTick(); + + // Assert + const cityField = wrapper.findComponent({ ref: "city" }); + const stateField = wrapper.findComponent({ ref: "state" }); + const zipField = wrapper.findComponent({ ref: "zipCode" }); + expect(cityField.exists()).toBeTruthy(); + expect(cityField.isVisible()).toBeTruthy(); + expect(stateField.exists()).toBeTruthy(); + expect(cityField.isVisible()).toBeTruthy(); + expect(zipField.exists()).toBeTruthy(); + expect(cityField.isVisible()).toBeTruthy(); + }); + + test("full street address is passed in => don't load Google Autocomplete script", async () => { + // Arrange/Act + const { wrapper } = setupMocks({ + props: { + modelValue: { + streetAddress: "12345 Test Road", + city: "Tests", + state: "OH", + zipCode: "12312", + }, + }, + }); + + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.$loadScript).not.toHaveBeenCalled(); + }); + + test("address field is focused => disable autocomplete", async () => { + // Arrange + let focusEventCallbackFunction; + autocompleteElement.addEventListener = jest + .fn() + .mockImplementation((eventName, callbackFunction) => { + if (eventName == "focus") { + focusEventCallbackFunction = callbackFunction; + } + }); + const { wrapper } = setupMocks({}); + await wrapper.vm.$nextTick(); + + // Act + focusEventCallbackFunction(); + await wrapper.vm.$nextTick(); + + // Assert + expect(autocompleteElement.getAttribute("autocomplete")).toEqual("do-not-autofill"); + }); + + test("street address is entered, user chooses good result from autocomplete results => other fields are filled in", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + addressModel: { + streetAddress: "123 Test Street", + }, + }); + + const selectedPlace = { + address_components: [ + { + long_name: "1234", + short_name: "1234", + types: ["street_number"], + }, + { + long_name: "Test Road", + short_name: "Test Road", + types: ["route"], + }, + { + long_name: "East Columbus", + short_name: "Columbus", + types: ["neighborhood", "political"], + }, + { + long_name: "Columbus", + short_name: "Columbus", + types: ["locality", "political"], + }, + { + long_name: "Franklin County", + short_name: "Franklin County", + types: ["administrative_area_level_2", "political"], + }, + { + long_name: "Ohio", + short_name: "OH", + types: ["administrative_area_level_1", "political"], + }, + { + long_name: "United States", + short_name: "US", + types: ["country", "political"], + }, + { + long_name: "43215", + short_name: "43215", + types: ["postal_code"], + }, + ], + }; + + // Act + autocompleteElement.dispatchEvent( + new CustomEvent("place_changed", { detail: selectedPlace }) + ); + + // Assert + const addressModel = wrapper.vm.addressModel; + expect(addressModel.streetAddress).toEqual("1234 Test Road"); + expect(addressModel.city).toEqual("Columbus"); + expect(addressModel.state).toEqual("OH"); + expect(addressModel.zipCode).toEqual("43215"); + }); + + test("street address is entered, user chooses good result from autocomplete results => alerts are cleared", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + addressModel: { + streetAddress: "123 Test Street", + }, + displayVerificationWarning: true, + displayNoMatchWarning: true, + }); + + let alerts = wrapper.findAllComponents(alert); + alerts.forEach((alert) => expect(alert.isVisible()).toBeTruthy()); + + const selectedPlace = { + address_components: [ + { + long_name: "1234", + short_name: "1234", + types: ["street_number"], + }, + { + long_name: "Test Road", + short_name: "Test Road", + types: ["route"], + }, + { + long_name: "East Columbus", + short_name: "Columbus", + types: ["neighborhood", "political"], + }, + { + long_name: "Columbus", + short_name: "Columbus", + types: ["locality", "political"], + }, + { + long_name: "Franklin County", + short_name: "Franklin County", + types: ["administrative_area_level_2", "political"], + }, + { + long_name: "Ohio", + short_name: "OH", + types: ["administrative_area_level_1", "political"], + }, + { + long_name: "United States", + short_name: "US", + types: ["country", "political"], + }, + { + long_name: "43215", + short_name: "43215", + types: ["postal_code"], + }, + ], + }; + + // Act + autocompleteElement.dispatchEvent( + new CustomEvent("place_changed", { detail: selectedPlace }) + ); + await wrapper.vm.$nextTick(); + + // Assert + alerts = wrapper.findAllComponents(alert); + alerts.forEach((alert) => expect(alert.exists()).toBeFalsy()); + }); + + test("street address is entered, but user clicks away => first result is selected and other fields are filled in", async () => { + // Arrange + let changeEventCallbackFunction; + autocompleteElement.addEventListener = jest + .fn() + .mockImplementation((eventName, callbackFunction) => { + if (eventName == "change") { + changeEventCallbackFunction = callbackFunction; + } + }); + + const { wrapper } = setupMocks({ + querySelectorFunction: function (query) { + if (query == ".pac-container .pac-item") { + let element = document.createElement("div"); + element.textContent = "123 Test Street"; + return element; + } + }, + geocoderResult: { + address_components: [ + { + long_name: "1234", + short_name: "1234", + types: ["street_number"], + }, + { + long_name: "Test Road", + short_name: "Test Road", + types: ["route"], + }, + { + long_name: "East Columbus", + short_name: "Columbus", + types: ["neighborhood", "political"], + }, + { + long_name: "Columbus", + short_name: "Columbus", + types: ["locality", "political"], + }, + { + long_name: "Franklin County", + short_name: "Franklin County", + types: ["administrative_area_level_2", "political"], + }, + { + long_name: "Ohio", + short_name: "OH", + types: ["administrative_area_level_1", "political"], + }, + { + long_name: "United States", + short_name: "US", + types: ["country", "political"], + }, + { + long_name: "43215", + short_name: "43215", + types: ["postal_code"], + }, + ], + }, + }); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + expect(verificationAlert.exists()).toBeFalsy(); + + await wrapper.vm.$nextTick(); + + // Act + changeEventCallbackFunction(); + + await wrapper.vm.$nextTick(); + + // Assert + const addressModel = wrapper.vm.addressModel; + expect(addressModel.streetAddress).toEqual("1234 Test Road"); + expect(addressModel.city).toEqual("Columbus"); + expect(addressModel.state).toEqual("OH"); + expect(addressModel.zipCode).toEqual("43215"); + }); + }); + + describe("alerts", () => { + const places = [null, { address_components: null }, undefined, {}]; + test.each(places)( + "selected place/place properties is null => display verification alert", + async (place) => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + addressModel: { + streetAddress: "123 Test Street", + }, + displayVerificationWarning: true, + displayNoMatchWarning: true, + }); + + let alerts = wrapper.findAllComponents(alert); + alerts.forEach((alert) => expect(alert.isVisible()).toBeTruthy()); + + const selectedPlace = place; + + // Act + autocompleteElement.dispatchEvent( + new CustomEvent("place_changed", { detail: selectedPlace }) + ); + await wrapper.vm.$nextTick(); + + // Assert + const verificationAlert = wrapper.findComponent({ + ref: "alertVerificationWarning", + }); + expect(verificationAlert.exists()).toBe(true); + expect(verificationAlert.isVisible()).toBe(true); + const noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBe(false); + } + ); + + test("user enters address that yields no autocomplete results => show noMatch alert", async () => { + // Arrange + let changeEventCallbackFunction; + autocompleteElement.addEventListener = jest + .fn() + .mockImplementation((eventName, callbackFunction) => { + if (eventName == "change") { + changeEventCallbackFunction = callbackFunction; + } + }); + + const { wrapper } = setupMocks({}); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + + await wrapper.vm.$nextTick(); + + // Act + changeEventCallbackFunction(); + + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayNoMatchWarning).toBeTruthy(); + noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeTruthy(); + expect(noMatchAlert.isVisible()).toBeTruthy(); + }); + + test("user enters address that yields autocomplete results, but doesn't select => show verification alert", async () => { + // Arrange + let changeEventCallbackFunction; + autocompleteElement.addEventListener = jest + .fn() + .mockImplementation((eventName, callbackFunction) => { + if (eventName == "change") { + changeEventCallbackFunction = callbackFunction; + } + }); + + const { wrapper } = setupMocks({ + querySelectorFunction: function (query) { + if (query == ".pac-container .pac-item") { + let element = document.createElement("div"); + element.textContent = "123 Test Street"; + return element; + } + }, + }); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + let verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + expect(verificationAlert.exists()).toBeFalsy(); + + await wrapper.vm.$nextTick(); + + // Act + changeEventCallbackFunction(); + + await wrapper.vm.$nextTick(); + + // Assert + verificationAlert = wrapper.findComponent({ ref: "alertVerificationWarning" }); + expect(wrapper.vm.displayVerificationWarning).toBeTruthy(); + expect(verificationAlert.exists()).toBeTruthy(); + expect(verificationAlert.isVisible()).toBeTruthy(); + noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); + expect(noMatchAlert.exists()).toBeFalsy(); + }); + + describe("noMatch alert is cleared on address change", () => { + test("user sees noMatch warning and enters city => noMatch warning is removed", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.setData({ + displayNoMatchWarning: true, + }); + await wrapper.vm.$nextTick(); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeTruthy(); + expect(noMatchAlert.isVisible()).toBeTruthy(); + + // Act + wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { + city: "Somewhere", + }); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); + noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + }); + + test("user sees noMatch warning and enters state => noMatch warning is removed", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.setData({ + displayNoMatchWarning: true, + }); + await wrapper.vm.$nextTick(); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeTruthy(); + expect(noMatchAlert.isVisible()).toBeTruthy(); + + // Act + wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { + state: "KO", + }); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); + noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + }); + + test("user sees noMatch warning and enters zip code => noMatch warning is removed", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + wrapper.setData({ + displayNoMatchWarning: true, + }); + await wrapper.vm.$nextTick(); + + let noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeTruthy(); + expect(noMatchAlert.isVisible()).toBeTruthy(); + + // Act + wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, { + zipCode: "12345", + }); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayNoMatchWarning).toBeFalsy(); + noMatchAlert = wrapper.findComponent({ ref: "alertNoMatchWarning" }); + expect(noMatchAlert.exists()).toBeFalsy(); + }); + }); }); - }); }); -function setupMocks({ mountOptions, props, isShallowMount = true, querySelectorFunction, geocoderResult = ["1234 Test Street"] }) { - store.commit(storeMutations.RESET_STATE); +function setupMocks({ + mountOptions, + props, + isShallowMount = true, + querySelectorFunction, + geocoderResult = ["1234 Test Street"], +}) { + store.commit(storeMutations.RESET_STATE); - const resultingMountOptions = getMountOptions({ - ...mountOptions, - router: { - navigate: jest.fn(), - navigate: jest.fn() - }, - loadScript: jest.fn().mockResolvedValue() - }); + const resultingMountOptions = getMountOptions({ + ...mountOptions, + router: { + navigate: jest.fn(), + navigate: jest.fn(), + }, + loadScript: jest.fn().mockResolvedValue(), + }); - window.google = { - maps: { - event: { - addListener: jest.fn().mockImplementation((element, eventName, callbackFunction) => { - function interceptedCallbackFunction(e) { - callbackFunction(e.detail); - } - // selectedPlace = "Woogly"; - element.addEventListener(eventName, interceptedCallbackFunction); - }), - removeListener: jest.fn(), - clearInstanceListeners: jest.fn() - }, - places: { - Autocomplete: jest.fn().mockImplementation((el) => el) - }, - Geocoder: class Geocoder { - // constructor(); + window.google = { + maps: { + event: { + addListener: jest + .fn() + .mockImplementation((element, eventName, callbackFunction) => { + function interceptedCallbackFunction(e) { + callbackFunction(e.detail); + } + // selectedPlace = "Woogly"; + element.addEventListener(eventName, interceptedCallbackFunction); + }), + removeListener: jest.fn(), + clearInstanceListeners: jest.fn(), + }, + places: { + Autocomplete: jest.fn().mockImplementation((el) => el), + }, + Geocoder: class Geocoder { + // constructor(); - geocode(request, callback) { - callback([geocoderResult], true) + geocode(request, callback) { + callback([geocoderResult], true); + } + }, + GeocoderStatus: { + OK: true, + }, + }, + }; + + if (props) resultingMountOptions.propsData = props; + + const wrapper = isShallowMount + ? shallowMount(addressQuestions, resultingMountOptions) + : mount(addressQuestions, resultingMountOptions); + document.querySelector = jest.fn().mockImplementation((query) => { + let result = null; + if (query == ".pac-container") result = document.createElement("div"); + else if (querySelectorFunction) { + result = querySelectorFunction(query); } - }, - GeocoderStatus: { - OK: true - } - } - }; - if (props) - resultingMountOptions.propsData = props; + return result ?? null; + }); - const wrapper = isShallowMount ? shallowMount(addressQuestions, resultingMountOptions) : mount(addressQuestions, resultingMountOptions); - document.querySelector = jest.fn().mockImplementation(query => { - let result = null; - if (query == ".pac-container") - result = document.createElement("div"); - else if (querySelectorFunction) { - result = querySelectorFunction(query); - } - - return result ?? null; - }); - - return { wrapper }; -} \ No newline at end of file + return { wrapper }; +} diff --git a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue index 90fa2bba9..74c1866f1 100644 --- a/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue +++ b/src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue @@ -1,76 +1,72 @@ diff --git a/src/layouts/address-lookup/customer-questions/customer-questions.spec.js b/src/layouts/address-lookup/customer-questions/customer-questions.spec.js index 949d3dde0..11c7fb3a9 100644 --- a/src/layouts/address-lookup/customer-questions/customer-questions.spec.js +++ b/src/layouts/address-lookup/customer-questions/customer-questions.spec.js @@ -11,26 +11,23 @@ const customerModel = { firstName: "", lastName: "", emailAddress: "", -} +}; describe("customerQuestions.vue", () => { - it("Should render customerQuestions sub-components (addressQuestions, first name, last name, and email textbox-questions)", async () => { - // Arrange + // Arrange const wrapper = shallowMount(customerQuestions); // Act - const addressQuestions = wrapper.findComponent({ ref: 'addressQuestions' }); - const firstName = wrapper.findComponent({ ref: 'firstName' }); - const lastName = wrapper.findComponent({ ref: 'lastName' }); - const emailAddress = wrapper.findComponent({ ref: 'emailAddress' }); + const addressQuestions = wrapper.findComponent({ ref: "addressQuestions" }); + const firstName = wrapper.findComponent({ ref: "firstName" }); + const lastName = wrapper.findComponent({ ref: "lastName" }); + const emailAddress = wrapper.findComponent({ ref: "emailAddress" }); // Assert expect(addressQuestions.exists()).toBe(true); expect(firstName.exists()).toBe(true); expect(lastName.exists()).toBe(true); expect(emailAddress.exists()).toBe(true); - }); - -}) \ No newline at end of file +}); diff --git a/src/layouts/address-lookup/customer-questions/customer-questions.vue b/src/layouts/address-lookup/customer-questions/customer-questions.vue index e837f26fc..d10812df2 100644 --- a/src/layouts/address-lookup/customer-questions/customer-questions.vue +++ b/src/layouts/address-lookup/customer-questions/customer-questions.vue @@ -1,49 +1,43 @@ \ No newline at end of file +export default { + name: "customer-questions", + emits: ["update:modelValue"], // The component emits an event + props: { + modelValue: { + type: Object, + default: () => ({ + customerQuestions: { + addressQuestions: { + streetAddress: "", + city: "", + state: "", + zipCode: "", + }, + firstName: "", + lastName: "", + emailAddress: "", + }, + }), + }, + validationRules: String, + }, + computed: { + customerModel: { + get: function () { + return this.modelValue; + }, + set: function (newValue) { + this.$emit("update:modelValue", newValue); + }, + }, + }, + components: { + addressQuestions, + textboxQuestion, + textBlock, + }, +}; + diff --git a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js index 16451b219..4828d00c5 100644 --- a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js +++ b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.spec.js @@ -1,70 +1,66 @@ import { shallowMount } from "@vue/test-utils"; import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question"; import { ValueToLogTypes } from "@/constants/analytics"; - describe("addressVehiclesQuestion.vue", () => { - it("Should return content for differentVehicleAlertHeader", () => { - // Arrange - const wrapper = shallowMount(addressVehiclesQuestion, { - mixins: [mockMixin], - }); - - // Assert - expect(wrapper.vm.differentVehicleAlertHeader).toEqual('FoundWindshieldTestReturn'); + // Arrange + const wrapper = shallowMount(addressVehiclesQuestion, { + mixins: [mockMixin], + }); + + // Assert + expect(wrapper.vm.differentVehicleAlertHeader).toEqual("FoundWindshieldTestReturn"); }); it("Should return content for differentVehicleAlertBody", () => { - // Arrange - const wrapper = shallowMount(addressVehiclesQuestion, { - mixins: [mockMixin], - propsData: { - vehicles: ["1", "2"], - modelValue: ["1", "2"], - } - }); - - // Assert - expect(wrapper.vm.differentVehicleAlertBody).toEqual('FoundWindshieldTestReturn'); + // Arrange + const wrapper = shallowMount(addressVehiclesQuestion, { + mixins: [mockMixin], + propsData: { + vehicles: ["1", "2"], + modelValue: ["1", "2"], + }, + }); + + // Assert + expect(wrapper.vm.differentVehicleAlertBody).toEqual("FoundWindshieldTestReturn"); }); it("Should emit a modelValue change when setting selectedVehicleVin", async () => { - // Arrange - const wrapper = shallowMount(addressVehiclesQuestion, { - mixins: [mockMixin], - propsData: { - vehicles: ["1", "2", "newValue"], - modelValue: "2", - } - }); + // Arrange + const wrapper = shallowMount(addressVehiclesQuestion, { + mixins: [mockMixin], + propsData: { + vehicles: ["1", "2", "newValue"], + modelValue: "2", + }, + }); - // Act - const localThis = { $emit: jest.fn() } - addressVehiclesQuestion.computed.selectedVehicleVin.set.call(localThis, 'newValue'); + // Act + const localThis = { $emit: jest.fn() }; + addressVehiclesQuestion.computed.selectedVehicleVin.set.call(localThis, "newValue"); - // Assert - expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue"); + // Assert + expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue"); }); - }); const mockMixin = { methods: { - getCmsContent: jest.fn((contentName) => { - if (contentName === "FoundWindshield") { - return 'FoundWindshieldTestReturn'; - } - return null; - }), - vehicles: jest.fn(() => { - return [{ vehicle: "test" }]; - }) + getCmsContent: jest.fn((contentName) => { + if (contentName === "FoundWindshield") { + return "FoundWindshieldTestReturn"; + } + return null; + }), + vehicles: jest.fn(() => { + return [{ vehicle: "test" }]; + }), }, computed: { - ValueToLogTypes() { - return ValueToLogTypes; - } + ValueToLogTypes() { + return ValueToLogTypes; + }, }, - - } +}; diff --git a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue index ade10ed99..da5af0819 100644 --- a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue +++ b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue @@ -1,24 +1,23 @@ \ No newline at end of file +} + diff --git a/src/layouts/address-vehicles/address-vehicles.spec.js b/src/layouts/address-vehicles/address-vehicles.spec.js index 8b1893765..e3ce48a32 100644 --- a/src/layouts/address-vehicles/address-vehicles.spec.js +++ b/src/layouts/address-vehicles/address-vehicles.spec.js @@ -11,221 +11,222 @@ import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-h // Mock our module for promises. jest.mock("@/helpers/damage-helper", () => ({ - isGlassAvailableForCarId: () => { - return false; - }, + isGlassAvailableForCarId: () => { + return false; + }, })); - describe("addressVehicles.vue", () => { test("Should return true for valid page requisites if carId / zipCode / emailAddress / pageData exists", async () => { - // Arrange - const { wrapper } = setupMocks({}); - store.commit(storeMutations.UPDATE_CAR_ID, "NOT NULL"); - store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, "12345"); - store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, "test@test.com"); - - // Act - const result = wrapper.vm.arePagePrerequisitesValid(); + // Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_CAR_ID, "NOT NULL"); + store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, "12345"); + store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, "test@test.com"); - //Assert - expect(result).toBe(true); + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); - wrapper.unmount(); + //Assert + expect(result).toBe(true); + + wrapper.unmount(); }); test("Should return false for valid page requisites if carId is missing", async () => { - // Arrange - const { wrapper } = setupMocks({}); - - // Act - store.commit(storeMutations.UPDATE_CAR_ID, null); - const result = wrapper.vm.arePagePrerequisitesValid(); + // Arrange + const { wrapper } = setupMocks({}); - //Assert - expect(result).toBe(false); + // Act + store.commit(storeMutations.UPDATE_CAR_ID, null); + const result = wrapper.vm.arePagePrerequisitesValid(); - wrapper.unmount(); + //Assert + expect(result).toBe(false); + + wrapper.unmount(); }); - // NOTE: this test is only here to meet code coverage; it does not test any logic in the original function test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.$router.navigateWithoutSaving = jest.fn(); - - // Act - await wrapper.setData({ - selectedVehicleVin: '5NMS3CADXLH233004', - }); - wrapper.vm.backButtonAction(); + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.$router.navigateWithoutSaving = jest.fn(); - //Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalled(); + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004", + }); + wrapper.vm.backButtonAction(); - wrapper.unmount(); + //Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalled(); + + wrapper.unmount(); }); // NOTE: this test is only here to meet code coverage; it does not test any logic in the original function test("Should run several related methods if forwardButtonAction is run", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const lookupVinResponse = { - data: { - carId: "456" - } - } - - // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse)); - wrapper.vm.$router.navigate = jest.fn(); - wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {}); - wrapper.vm.navigateForward = jest.fn().mockImplementation(()=> {}); + // Arrange + const { wrapper } = setupMocks({}); + const lookupVinResponse = { + data: { + carId: "456", + }, + }; - // Act - await wrapper.setData({ - selectedVehicleVin: '5NMS3CADXLH233004', - }); - - await wrapper.vm.forwardButtonAction(); - wrapper.vm.$nextTick(); + // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse)); + wrapper.vm.$router.navigate = jest.fn(); + wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {}); + wrapper.vm.navigateForward = jest.fn().mockImplementation(() => {}); - //Assert - expect(wrapper.vm.navigateForward).toBeCalled(); + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004", + }); - wrapper.unmount(); + await wrapper.vm.forwardButtonAction(); + wrapper.vm.$nextTick(); + + //Assert + expect(wrapper.vm.navigateForward).toBeCalled(); + + wrapper.unmount(); }); test("Should return out of forwardButtonAction if lookupVin returns with an error", async () => { - // Arrange - const { wrapper } = setupMocks({}); + // Arrange + const { wrapper } = setupMocks({}); - const lookupVinResponse = { - error: "there is an error" - } - - // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.lookupVin = jest.fn(() => Promise.reject(lookupVinResponse)); - wrapper.vm.$router.navigateWithSaving = jest.fn(); - wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {}); + const lookupVinResponse = { + error: "there is an error", + }; - // Act - await wrapper.setData({ - selectedVehicleVin: '5NMS3CADXLH233004', - }); - await wrapper.vm.forwardButtonAction(); - wrapper.vm.$nextTick(); + // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.lookupVin = jest.fn(() => Promise.reject(lookupVinResponse)); + wrapper.vm.$router.navigateWithSaving = jest.fn(); + wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {}); - //Assert - expect(wrapper.vm.forwardButtonAction).toReturn; + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004", + }); + await wrapper.vm.forwardButtonAction(); + wrapper.vm.$nextTick(); - wrapper.unmount(); + //Assert + expect(wrapper.vm.forwardButtonAction).toReturn; + + wrapper.unmount(); }); test("Should navigate to CLICKED_FORWARD scenario if carId is different and selected glass not available for vehicle on navigateForward", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$router.navigateWithSaving = jest.fn(); - - // Act - await wrapper.setData({ - selectedVehicleVin: '5NMS3CADXLH233004', - isSelectedGlassAvailableForVehicle: false, - isCarIdDifferent: true, - }); - await wrapper.vm.navigateForward(); + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$router.navigateWithSaving = jest.fn(); - //Assert - expect(wrapper.vm.$router.navigateWithSaving).toBeCalledTimes(1); + // Act + await wrapper.setData({ + selectedVehicleVin: "5NMS3CADXLH233004", + isSelectedGlassAvailableForVehicle: false, + isCarIdDifferent: true, + }); + await wrapper.vm.navigateForward(); - wrapper.unmount(); + //Assert + expect(wrapper.vm.$router.navigateWithSaving).toBeCalledTimes(1); + + wrapper.unmount(); }); test("carId is not different on navigateForward (car was found) => Should handle navigating forward with car match", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$refs.loadingModal.showModal = jest.fn(); - navigateToHeritage.navigateToHeritageFunnel = jest.fn(); - - // Act - await wrapper.setData({ - isCarIdDifferent: false, - }); - await wrapper.vm.navigateForward(); + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); + navigateToHeritage.navigateToHeritageFunnel = jest.fn(); - //Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1); + // Act + await wrapper.setData({ + isCarIdDifferent: false, + }); + await wrapper.vm.navigateForward(); - wrapper.unmount(); + //Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toBeCalledTimes(1); + + wrapper.unmount(); }); }); function setupMocks({}) { - //Mock store - store.commit(storeMutations.RESET_STATE); - store.commit(storeMutations.UPDATE_PAGE_DATA, { - page: "address-vehicles", - data: [{ - vehicle: { - "carId": "CR00069309", - "category": "SUV", - "year": 2020, - "make": "Hyundai", - "model": "Santa Fe", - "style": "4 door utility", - "imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg", - "imageVifNumber": "13769", - "imageVifColor": "white" - }, - vin: "5NMS3CADXLH233004" - }], - }) + //Mock store + store.commit(storeMutations.RESET_STATE); + store.commit(storeMutations.UPDATE_PAGE_DATA, { + page: "address-vehicles", + data: [ + { + vehicle: { + carId: "CR00069309", + category: "SUV", + year: 2020, + make: "Hyundai", + model: "Santa Fe", + style: "4 door utility", + imageUrl: + "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg", + imageVifNumber: "13769", + imageVifColor: "white", + }, + vin: "5NMS3CADXLH233004", + }, + ], + }); - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn(), - }, - actionList: [ - { - actionName: storeActions.LOOKUP_VEHICLE_BY_VIN, - data: {} - } - ] - }); + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn(), + }, + actionList: [ + { + actionName: storeActions.LOOKUP_VEHICLE_BY_VIN, + data: {}, + }, + ], + }); - //Mock props - const mockMixin = { - methods: { - getCmsContent: jest.fn((contentName) => { - if (contentName === "FoundMultipleVehicles") { - return 'FoundMultipleVehiclesTestReturn'; - } - if (contentName === "ProvideVinAlert") { - return 'ProvideVinAlertTestReturn'; - } - return null; - }), - }, - computed: { - dynamicStrings() { - return {ROUTER_LINK: "routerLink:"} - } - } - } + //Mock props + const mockMixin = { + methods: { + getCmsContent: jest.fn((contentName) => { + if (contentName === "FoundMultipleVehicles") { + return "FoundMultipleVehiclesTestReturn"; + } + if (contentName === "ProvideVinAlert") { + return "ProvideVinAlertTestReturn"; + } + return null; + }), + }, + computed: { + dynamicStrings() { + return { ROUTER_LINK: "routerLink:" }; + }, + }, + }; - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(addressVehicles, mountOptions); + mountOptions.mixins = [mockMixin]; - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + const wrapper = shallowMount(addressVehicles, mountOptions); - return { wrapper }; + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + return { wrapper }; } diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue index a0edf876f..ba019bf47 100644 --- a/src/layouts/address-vehicles/address-vehicles.vue +++ b/src/layouts/address-vehicles/address-vehicles.vue @@ -1,48 +1,48 @@ diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue index 187f02fe1..9384a060b 100644 --- a/src/layouts/capability-questions/capability-questions.vue +++ b/src/layouts/capability-questions/capability-questions.vue @@ -3,21 +3,32 @@
- +
-
-
-
@@ -32,7 +43,7 @@ import alert from "@/ux-components/alert/alert"; import questionChain from "@/common-components/question-chain/question-chain"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; import funnelFooter from "@/common-components/funnel-footer/funnel-footer"; -import loadingModal from '@/common-components/loading-modal/loading-modal.vue'; +import loadingModal from "@/common-components/loading-modal/loading-modal.vue"; // Supporting Files import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; @@ -73,7 +84,8 @@ export default { }, data() { return { - capabilityQuestionsData: store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS).partsOrQuestions, + capabilityQuestionsData: store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS) + .partsOrQuestions, selectedAnswers: {}, currentQuestionChainIndex: 0, }; @@ -86,40 +98,58 @@ export default { return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText"); }, windshieldPart() { - return this.pageData.partsOrQuestions.find(x => x.glassLocation === damageLocationsSelected.WINDSHIELD); + return this.pageData.partsOrQuestions.find( + (x) => x.glassLocation === damageLocationsSelected.WINDSHIELD + ); }, windshieldPartInfo() { return this.windshieldPart.parts[0]; }, pageData() { return this.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); - } + }, }, mounted() { // are there alreadyAnsweredQuestions? const alreadyAnsweredQuestions = store.getters.damage.capabilityQuestionAnswers; - this.capabilityQuestionsData = this.pageData.partsOrQuestions.filter(x => x.capabilityQuestions).map((glass, i) => { - // NOTE: questions for property "questions" can differ between layouts - glass.questions = glass.capabilityQuestions; - // reset selectedAnswers for this glass - this.selectedAnswers[glass.key] = []; - // pass in: glass, i, alreadyAnsweredQuestions - return this.setupInitialData(glass, i, alreadyAnsweredQuestions); - }); + this.capabilityQuestionsData = this.pageData.partsOrQuestions + .filter((x) => x.capabilityQuestions) + .map((glass, i) => { + // NOTE: questions for property "questions" can differ between layouts + glass.questions = glass.capabilityQuestions; + // reset selectedAnswers for this glass + this.selectedAnswers[glass.key] = []; + // pass in: glass, i, alreadyAnsweredQuestions + return this.setupInitialData(glass, i, alreadyAnsweredQuestions); + }); }, methods: { showThisQuestionChain(glass, i) { - if (!glass.capabilityQuestions || glass.capabilityQuestions?.length < 1 || glass.isSuppressedPart) { return false; } // return false if no capabilityQuestions or if suppressed - return this.currentQuestionChainIndex === i || glass.answerData?.answerResult?.length > 0; + if ( + !glass.capabilityQuestions || + glass.capabilityQuestions?.length < 1 || + glass.isSuppressedPart + ) { + return false; + } // return false if no capabilityQuestions or if suppressed + return ( + this.currentQuestionChainIndex === i || glass.answerData?.answerResult?.length > 0 + ); }, arePagePrerequisitesValid() { - const capabilityQuestionsPageData = store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); - return capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0; + const capabilityQuestionsPageData = store.getters.pageData( + fmgPageValues.CAPABILITY_QUESTIONS + ); + return ( + capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0 + ); }, async forwardButtonAction() { const capabilityQuestionsAnswersArray = this.capabilityQuestionsData.map((glass) => { - const selectedAnswerResult2 = this.getCorrespondingAnswerResult2(glass.answerData.answerResult); + const selectedAnswerResult2 = this.getCorrespondingAnswerResult2( + glass.answerData.answerResult + ); return { glassLocation: glass.glassLocation, @@ -138,15 +168,29 @@ export default { }); // save to vuex store as order.damage.capabilityQuestionAnswers (array) - await this.dispatchStoreAction(this.storeActions.SAVE_CAPABILITY_QUESTION_ANSWERS, capabilityQuestionsAnswersArray, false); + await this.dispatchStoreAction( + this.storeActions.SAVE_CAPABILITY_QUESTION_ANSWERS, + capabilityQuestionsAnswersArray, + false + ); // get parts from the capabilityQuestionAnswers let partsOrQuestions = this.pageData.partsOrQuestions; for (let answer of capabilityQuestionsAnswersArray) { - const correspondingPart = partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === answer.glassLocation); - const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, answer.glassLocation, false)).data; + const correspondingPart = partsOrQuestions.find( + (partOrQuestion) => partOrQuestion.glassLocation === answer.glassLocation + ); + const partFromCapabilityQuestionAnswer = ( + await this.dispatchStoreAction( + storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, + answer.glassLocation, + false + ) + ).data; - partsOrQuestions.find(partOrQuestion => partOrQuestion.location === answer.location).parts = partFromCapabilityQuestionAnswer; + partsOrQuestions.find( + (partOrQuestion) => partOrQuestion.location === answer.location + ).parts = partFromCapabilityQuestionAnswer; } this.navigateForward(partsOrQuestions); @@ -154,7 +198,7 @@ export default { handleAnswerUpdates(answer) { // only runs when all questions in a question-chain have been answered // when selectedAnswers updates, user has completed this part's question chain and has a final answer - // (does not get run for each invididual question's answer, only when + // (does not get run for each invididual question's answer, only when // all relevant questions for the current part have been answered) /* @@ -182,7 +226,6 @@ export default { // loop through every answered question on the currently answered glass part answer.answeredQuestions?.forEach((aq) => { - // keep track of this question number answeredQuestionIndexes.push(aq.questionNum); @@ -193,10 +236,8 @@ export default { // loop through all glass parts data this.capabilityQuestionsData.forEach((glass, gpIndex) => { - // only look for duplicates forward... to parts that follow after the currently being answered part if (gpIndex > answer.glass) { - let suppressUntil; // reset this glass part, in case user is changing their previous answers glass.answerData = null; @@ -204,7 +245,6 @@ export default { // loop through this glass part's part questions, looking for a questionText match glass.capabilityQuestions.forEach((pq, pqIndex) => { - // clear out any previously set answers pq.answerSelected = null; @@ -222,8 +262,8 @@ export default { // if these match then we have a duplicate question if (pq.questionText.toUpperCase() === answeredQuestionText) { - - const thisAnsweredCapabilityQuestion = glass.capabilityQuestions[pqIndex]; + const thisAnsweredCapabilityQuestion = + glass.capabilityQuestions[pqIndex]; let matchedAnswer; let rejectedAnswers = []; // set as an array, in case we ever have questions with more than 2 answers... @@ -239,17 +279,26 @@ export default { }); // Update the key to re-render this part's question-chain component - this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].glassLocation + this.capabilityQuestionsData[gpIndex].glassName + Date.now().toString(); + this.capabilityQuestionsData[gpIndex].key = + this.capabilityQuestionsData[gpIndex].glassLocation + + this.capabilityQuestionsData[gpIndex].glassName + + Date.now().toString(); // handle suppressing downstream in this question chain if (matchedAnswer.nextQuestionSequence) { // ensure that the question that the accepted answer has set to be next is NOT suppressed - glass.capabilityQuestions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion = null; + glass.capabilityQuestions[ + matchedAnswer.nextQuestionSequence - 1 + ].suppressQuestion = null; // if the duplicate is the 1ST question, then set suppressUntil var to lowest nextQuestion number if (pqIndex === 0) { - if (!suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } - if (matchedAnswer.nextQuestionSequence < suppressUntil) { suppressUntil = matchedAnswer.nextQuestionSequence } + if (!suppressUntil) { + suppressUntil = matchedAnswer.nextQuestionSequence; + } + if (matchedAnswer.nextQuestionSequence < suppressUntil) { + suppressUntil = matchedAnswer.nextQuestionSequence; + } } } @@ -257,9 +306,13 @@ export default { glass.capabilityQuestions.forEach((q) => { q.answers.forEach((thisAns) => { // restore any of the answers that formerly led to the duplicated question - if (thisAns.originalNextQuestionSequence === pq.questionSequence) { + if ( + thisAns.originalNextQuestionSequence === + pq.questionSequence + ) { // restore original nextQuestionSequence - thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence; + thisAns.nextQuestionSequence = + thisAns.originalNextQuestionSequence; this.originalNextQuestionSequence = null; // restore original answerResult if (thisAns.originalAnswerResult) { @@ -271,12 +324,17 @@ export default { if (thisAns.nextQuestionSequence === pq.questionSequence) { // update either the nextQuestionSequence or the answerResult if (matchedAnswer.nextQuestionSequence) { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; - thisAns.nextQuestionSequence = matchedAnswer.nextQuestionSequence; + thisAns.originalNextQuestionSequence = + thisAns.nextQuestionSequence; + thisAns.nextQuestionSequence = + matchedAnswer.nextQuestionSequence; } else { - thisAns.originalNextQuestionSequence = thisAns.nextQuestionSequence; + thisAns.originalNextQuestionSequence = + thisAns.nextQuestionSequence; thisAns.nextQuestionSequence = null; - thisAns.originalAnswerResult = thisAns.originalAnswerResult || thisAns.answerResult; + thisAns.originalAnswerResult = + thisAns.originalAnswerResult || + thisAns.answerResult; thisAns.answerResult = matchedAnswer.answerResult; } } @@ -288,11 +346,19 @@ export default { const thisGlassPart = "glass" + gpIndex; if (foundDuplicateQuestions[thisGlassPart]) { - if (!foundDuplicateQuestions[thisGlassPart].includes(thisAnsweredCapabilityQuestion.questionSequence)) { - foundDuplicateQuestions[thisGlassPart].push(thisAnsweredCapabilityQuestion.questionSequence); + if ( + !foundDuplicateQuestions[thisGlassPart].includes( + thisAnsweredCapabilityQuestion.questionSequence + ) + ) { + foundDuplicateQuestions[thisGlassPart].push( + thisAnsweredCapabilityQuestion.questionSequence + ); } } else { - foundDuplicateQuestions[thisGlassPart] = [thisAnsweredCapabilityQuestion.questionSequence]; + foundDuplicateQuestions[thisGlassPart] = [ + thisAnsweredCapabilityQuestion.questionSequence, + ]; } // are there any questions left that are not suppressed? @@ -312,28 +378,30 @@ export default { }; // set the answerData as 'already answered' glass.answerData = { - answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, + answerResult: matchedAnswer.nextQuestionSequence + ? matchedAnswer.nextQuestionSequence + : matchedAnswer.answerResult, answeredQuestions: [answeredQuestionObj], }; // suppress this glass because it has an answer glass.isSuppressedPart = true; } - } - }); // Update the key to re-render this part's question-chain component - this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].glassLocation + this.capabilityQuestionsData[gpIndex].glassName + Date.now().toString(); - + this.capabilityQuestionsData[gpIndex].key = + this.capabilityQuestionsData[gpIndex].glassLocation + + this.capabilityQuestionsData[gpIndex].glassName + + Date.now().toString(); } }); }); // DETERMINE ANSWERED QUESTIONS LIST FOR THIS GLASS PART - // look through all (this part's) part questions for any duplicates that were suppressed; + // look through all (this part's) part questions for any duplicates that were suppressed; // add them to the list of answered questions if found // EX answeredQuestionIndexes: [1,5,11,13] @@ -344,7 +412,9 @@ export default { // }; const thisPartsDupes = foundDuplicateQuestions["glass" + answer.glassIndex]; - const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : []; + const completeAnsweredQuestions = answer.answeredQuestions + ? [...answer.answeredQuestions] + : []; const glassPartAnswered = this.capabilityQuestionsData[answer.glassIndex]; thisPartsDupes?.forEach((dupe) => { @@ -357,15 +427,21 @@ export default { // did one of the answers of this question point to the duplicated question? q.answers.forEach((a) => { - if ((dupe === a.originalNextQuestionSequence) && - (answeredQuestionIndexes.includes(q.questionSequence)) && - (a.answerText.toUpperCase() === dupeQuestionAnswer.answerText.toUpperCase())) { + if ( + dupe === a.originalNextQuestionSequence && + answeredQuestionIndexes.includes(q.questionSequence) && + a.answerText.toUpperCase() === + dupeQuestionAnswer.answerText.toUpperCase() + ) { includeThisDupeInAnsweredQuestions = true; } }); // is this q.questionSequence listed as the duplicated question's nextQuestionSequence? - if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) { + if ( + q.questionSequence === dupeQuestionAnswer.nextQuestionSequence && + answeredQuestionIndexes.includes(q.questionSequence) + ) { includeThisDupeInAnsweredQuestions = true; } @@ -382,18 +458,20 @@ export default { // make sure there are no duplicated dupes in the list... const foundInCompleteAnsweredQuestions = new Set(); - let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => { + let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter((el) => { const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText); foundInCompleteAnsweredQuestions.add(el.questionText); return !duplicate; }); - filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a, b) => a.questionNum - b.questionNum); + filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort( + (a, b) => a.questionNum - b.questionNum + ); // set final answer data for the current answered glass part glassPartAnswered.answerData = { answerResult: answer.answerResult, answeredQuestions: filteredCompleteAnsweredQuestions, - } + }; // this part has been fully answered, so advance to next part's question chain for (let i = answer.glassIndex + 1; i < this.capabilityQuestionsData.length; i++) { @@ -408,10 +486,15 @@ export default { // Find the part that has some answer that has an answerResult matching the selected answerResult, then get the corresponding answerResult2 getCorrespondingAnswerResult2(answerResult1) { return this.capabilityQuestionsData - .find(part => part.capabilityQuestions.some(question => question.answers.some(answer => answer.answerResult == answerResult1))) // found part - .capabilityQuestions.find(question => question.answers.some(answer => answer.answerResult == answerResult1)) // found question - .answers.find(answer => answer.answerResult == answerResult1) - .answerResult2; + .find((part) => + part.capabilityQuestions.some((question) => + question.answers.some((answer) => answer.answerResult == answerResult1) + ) + ) // found part + .capabilityQuestions.find((question) => + question.answers.some((answer) => answer.answerResult == answerResult1) + ) // found question + .answers.find((answer) => answer.answerResult == answerResult1).answerResult2; }, }, components: { @@ -430,7 +513,7 @@ export default { \ No newline at end of file + font-weight: 500; + color: $black; +} +div .current_car_info-text { + padding-bottom: 16px; +} + diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js index ca9c235b0..5c562d002 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js +++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js @@ -12,590 +12,607 @@ import { storeActions } from "@/constants/store-actions"; import { storeMutations } from "@/constants/store-mutations"; import store from "@/store"; -jest.mock('@/assets/img/loader.gif', () => 'loader.gif') -jest.mock('@/assets/img/windshield.png', () => 'windshield.png') +jest.mock("@/assets/img/loader.gif", () => "loader.gif"); +jest.mock("@/assets/img/windshield.png", () => "windshield.png"); // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), + settleAllPromises: jest.fn(), })); // Mock fetchCmsContentForPage jest.mock("@/helpers/cms-content-helper", () => ({ - fetchCmsContentForPage: jest.fn(), + fetchCmsContentForPage: jest.fn(), })); // Mock damage helper jest.mock("@/helpers/damage-helper", () => ({ - isGlassAvailableForCarId: () => { return false; }, - getDamageString: () => { return 'damage string'; } + isGlassAvailableForCarId: () => { + return false; + }, + getDamageString: () => { + return "damage string"; + }, })); describe("license-plate-lookup.vue", () => { - describe("get values from store", () => { - test("getLicensePlateFromStore returns store license plate", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const mockLicensePlate = "TESTPLATE"; - store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, mockLicensePlate); + describe("get values from store", () => { + test("getLicensePlateFromStore returns store license plate", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockLicensePlate = "TESTPLATE"; + store.commit(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, mockLicensePlate); - // Act - const licensePlate = wrapper.vm.getLicensePlateFromStore(); + // Act + const licensePlate = wrapper.vm.getLicensePlateFromStore(); - // Assert - expect(licensePlate).toEqual(mockLicensePlate); - }); - - test("getRegistrationZipFromStore returns store registration zip", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const mockRegistrationZip = "12345"; - store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, mockRegistrationZip); - - // ACT - const registrationZip = wrapper.vm.getRegistrationZipFromStore(); - - // Assert - expect(registrationZip).toEqual(mockRegistrationZip); - }); - - test("getEmailFromStore returns store customer email", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const mockEmail = "test@test.com"; - store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, mockEmail); - - // ACT - const customerEmail = wrapper.vm.getEmailFromStore(); - - // Assert - expect(customerEmail).toEqual(mockEmail); - }); - - test("getServiceZipFromStore returns store service zip", async () => { - // Arrange - const { wrapper } = setupMocks({}); - const mockServiceZip = "12345"; - store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, mockServiceZip); - - // ACT - const serviceZip = wrapper.vm.getServiceZipFromStore(); - - // Assert - expect(serviceZip).toEqual(mockServiceZip); - }); - }); - - describe("navigation", () => { - test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => { - - //Arrange - const { wrapper } = setupMocks({}); - - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - wrapper.vm.backButtonAction(); - - //Assert - expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); - }); - - describe("on forwardButtonAction click", () => { - test("Navigate forward should be called and isCarIdDifferent should be set to false when data entered matches store data on forwardButtonAction click", async () => { - - // Arrange - const mockCarId = "TESTID"; - const { wrapper } = setupMocks({ carId: mockCarId, isServiceable: true }); - - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); - wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: mockCarId - } - } - })); - - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.isCarIdDifferent).toEqual(false); - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); - }); - - - - test("Function should stop and datam isCarIdDifferent should be set to true when carId entered doesn't match store carId or previously entered carId on forwardButtonAction click", async () => { - // Arrange - - // Setup state data / return data. - const { wrapper } = setupMocks({ carId: "C111111", isServiceable: true }); - store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); - - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + // Assert + expect(licensePlate).toEqual(mockLicensePlate); }); - // Mock store action call - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" // Make sure carId returned from call does not match carId in state. - } - } - })); + test("getRegistrationZipFromStore returns store registration zip", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockRegistrationZip = "12345"; + store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, mockRegistrationZip); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); + // ACT + const registrationZip = wrapper.vm.getRegistrationZipFromStore(); - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.isCarIdDifferent).toEqual(true); - }); - - test("Navigate forward should be called and isCarId should be set to true when carId entered matches previously entered carId and rest of data entered matches store data on forwardButtonAction click", async () => { - - // Arrange - const { wrapper } = setupMocks({ carId: "C10000", isServiceable: true }); - - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + // Assert + expect(registrationZip).toEqual(mockRegistrationZip); }); - wrapper.vm.previouslyEnteredCarId = "C00000"; - wrapper.vm.navigateForward = jest.fn(); + test("getEmailFromStore returns store customer email", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockEmail = "test@test.com"; + store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, mockEmail); - // Mock store action call - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" // Make sure carId returned from call does not match carId in state. - } - } - })); + // ACT + const customerEmail = wrapper.vm.getEmailFromStore(); - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - await wrapper.vm.forwardButtonAction(); - - //Assert - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); - expect(wrapper.vm.isCarIdDifferent).toEqual(true); - }); - }); - - describe("navigateForward", () => { - test("navigateWithSaving should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - await wrapper.setData({ - isCarIdDifferent: true, - isSelectedGlassAvailableForVehicle: false - }) - - wrapper.vm.$router.navigate = jest.fn(); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + // Assert + expect(customerEmail).toEqual(mockEmail); }); - wrapper.vm.dispatchStoreAction = jest.fn(); - await wrapper.vm.navigateForward(); + test("getServiceZipFromStore returns store service zip", async () => { + // Arrange + const { wrapper } = setupMocks({}); + const mockServiceZip = "12345"; + store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, mockServiceZip); - //Assert - expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); - }); + // ACT + const serviceZip = wrapper.vm.getServiceZipFromStore(); - test("navigateForwardWithSingleCarMatch should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - await wrapper.setData({ - isCarIdDifferent: false - }) - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { - return ''; + // Assert + expect(serviceZip).toEqual(mockServiceZip); }); - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - await wrapper.vm.navigateForward(); - - //Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalled(); - }); - - test("carId matches returned vehicle => navigateForwardWithSingleCarMatch", async () => { - // Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - isCarIdDifferent: false - }) - - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - - // Act - await wrapper.vm.navigateForward(); - - //Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); - }); - - test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => { - // Arrange - const { wrapper } = setupMocks({}); - await wrapper.setData({ - isSelectedGlassAvailableForVehicle: true - }) - - wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); - - // Act - await wrapper.vm.navigateForward(); - - //Assert - expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); - }); - }); - }); - - describe("button text", () => { - test("Button Text should revert to initial value when licensePlate textfield has new text", async () => { - - // Arrange - const { wrapper } = setupMocks({}); - - //Act - wrapper.setData({ - licensePlate: "NEWPLATE" - }) - wrapper.vm.getCmsContent = jest.fn(); - await wrapper.vm.$nextTick(); - - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); }); - test("Button Text should revert to initial value when registrationZip textfield has new text", async () => { + describe("navigation", () => { + test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => { + //Arrange + const { wrapper } = setupMocks({}); - // Arrange - const { wrapper } = setupMocks({}); + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); - //Act - await wrapper.setData({ - registrationZipCode: "55555" - }) - wrapper.vm.getCmsContent = jest.fn(); - await wrapper.vm.$nextTick(); + wrapper.vm.backButtonAction(); - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); + //Assert + expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalled(); + }); + + describe("on forwardButtonAction click", () => { + test("Navigate forward should be called and isCarIdDifferent should be set to false when data entered matches store data on forwardButtonAction click", async () => { + // Arrange + const mockCarId = "TESTID"; + const { wrapper } = setupMocks({ carId: mockCarId, isServiceable: true }); + + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.navigateForward = jest.fn(); + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: mockCarId, + }, + }, + }) + ); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.isCarIdDifferent).toEqual(false); + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); + + test("Function should stop and datam isCarIdDifferent should be set to true when carId entered doesn't match store carId or previously entered carId on forwardButtonAction click", async () => { + // Arrange + + // Setup state data / return data. + const { wrapper } = setupMocks({ carId: "C111111", isServiceable: true }); + store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []); + + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ""; + }); + + // Mock store action call + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", // Make sure carId returned from call does not match carId in state. + }, + }, + }) + ); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.isCarIdDifferent).toEqual(true); + }); + + test("Navigate forward should be called and isCarId should be set to true when carId entered matches previously entered carId and rest of data entered matches store data on forwardButtonAction click", async () => { + // Arrange + const { wrapper } = setupMocks({ carId: "C10000", isServiceable: true }); + + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ""; + }); + + wrapper.vm.previouslyEnteredCarId = "C00000"; + wrapper.vm.navigateForward = jest.fn(); + + // Mock store action call + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", // Make sure carId returned from call does not match carId in state. + }, + }, + }) + ); + + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); + + await wrapper.vm.forwardButtonAction(); + + //Assert + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + expect(wrapper.vm.isCarIdDifferent).toEqual(true); + }); + }); + + describe("navigateForward", () => { + test("navigateWithSaving should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + //Act + await wrapper.setData({ + isCarIdDifferent: true, + isSelectedGlassAvailableForVehicle: false, + }); + + wrapper.vm.$router.navigate = jest.fn(); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ""; + }); + wrapper.vm.dispatchStoreAction = jest.fn(); + + await wrapper.vm.navigateForward(); + + //Assert + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); + }); + + test("navigateForwardWithSingleCarMatch should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + //Act + await wrapper.setData({ + isCarIdDifferent: false, + }); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { + return ""; + }); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + await wrapper.vm.navigateForward(); + + //Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalled(); + }); + + test("carId matches returned vehicle => navigateForwardWithSingleCarMatch", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + isCarIdDifferent: false, + }); + + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + // Act + await wrapper.vm.navigateForward(); + + //Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); + }); + + test("selected glass is available for returned vehicle => navigateForwardWithSingleCarMatch", async () => { + // Arrange + const { wrapper } = setupMocks({}); + await wrapper.setData({ + isSelectedGlassAvailableForVehicle: true, + }); + + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); + + // Act + await wrapper.vm.navigateForward(); + + //Assert + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1); + }); + }); }); - test("Button Text should revert to initial value when serviceZip textfield has new text", async () => { + describe("button text", () => { + test("Button Text should revert to initial value when licensePlate textfield has new text", async () => { + // Arrange + const { wrapper } = setupMocks({}); - // Arrange - const { wrapper } = setupMocks({}); + //Act + wrapper.setData({ + licensePlate: "NEWPLATE", + }); + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - //Act - await wrapper.setData({ - serviceZipCode: "55555" - }) - wrapper.vm.getCmsContent = jest.fn(); - await wrapper.vm.$nextTick(); + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); + }); - //Assert - expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); - }); - }) + test("Button Text should revert to initial value when registrationZip textfield has new text", async () => { + // Arrange + const { wrapper } = setupMocks({}); - describe("saving registrationZip and serviceZip on continue", () => { - test("registrationZip is serviceable and vehicle match is found => sets service zip/state to registration zip/state", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + //Act + await wrapper.setData({ + registrationZipCode: "55555", + }); + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - await wrapper.setData({ registrationZipCode: "00000" }); - navigateToHeritage.navigateToHeritageFunnel = jest.fn(); + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); + }); - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" - } - } - })); + test("Button Text should revert to initial value when serviceZip textfield has new text", async () => { + // Arrange + const { wrapper } = setupMocks({}); - // Act - await wrapper.vm.forwardButtonAction(); + //Act + await wrapper.setData({ + serviceZipCode: "55555", + }); + wrapper.vm.getCmsContent = jest.fn(); + await wrapper.vm.$nextTick(); - // Assert - expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual(wrapper.vm.$store.getters.vehicle.registration.zipCode); - expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345"); - expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("12345"); - }) - - test("vehicle match is found but registrationZip is not serviceable => shows service zip/state field", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return { data: { isServiceable: false, state: "XX" } }; - }); - - await wrapper.setData({ registrationZip: "00000" }); - navigateToHeritage.navigateToHeritageFunnel = jest.fn(); - - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" - } - } - })); - - // Act - await wrapper.vm.forwardButtonAction(); - - // Assert - const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZipQuestionWidget']"); - expect(serviceZipField.exists()).toBe(true); - expect(serviceZipField.isVisible()).toBe(true); - }) - - test("registrationZip is not serviceable so serviceZip field is shown, continue clicked => user cannot continue", async () => { - // Arrange - const { wrapper } = setupMocks({}); - wrapper.vm.validateZip = jest.fn().mockImplementation(() => { - return { data: { isServiceable: false, state: "XX" } }; - }); - - await wrapper.setData({ registrationZipCode: "00000" }); - navigateToHeritage.navigateToHeritageFunnel = jest.fn(); - - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" - } - } - })); - - await wrapper.vm.forwardButtonAction(); - wrapper.vm.$router.navigate = jest.fn(); - // At this point, serviceZip field is shown - - // Act - // Continue without entering anything into service zip field - await wrapper.vm.forwardButtonAction(); - - // Assert - const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZipQuestionWidget']"); - expect(serviceZipField.exists()).toBe(true); - expect(serviceZipField.isVisible()).toBe(true); 3 - expect(navigateToHeritage.navigateToHeritageFunnel).not.toHaveBeenCalled(); - expect(wrapper.vm.$router.navigate).not.toHaveBeenCalled(); + //Assert + expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); + }); }); - test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => user can continue", async () => { - // Arrange - const { wrapper } = setupMocks({ isServiceable: false}); - const registrationZip = "00000"; - const serviceZip = "99999"; + describe("saving registrationZip and serviceZip on continue", () => { + test("registrationZip is serviceable and vehicle match is found => sets service zip/state to registration zip/state", async () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); - wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" - } - } - })); + await wrapper.setData({ registrationZipCode: "00000" }); + navigateToHeritage.navigateToHeritageFunnel = jest.fn(); - await wrapper.setData({ registrationZipCode: registrationZip }); - await wrapper.vm.forwardButtonAction(); + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", + }, + }, + }) + ); - // At this point, serviceZip field is shown - await wrapper.setData({ serviceZipCode: serviceZip }); + // Act + await wrapper.vm.forwardButtonAction(); - // Act - - // Continue after entering input into service zip field - await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual( + wrapper.vm.$store.getters.vehicle.registration.zipCode + ); + expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345"); + expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("12345"); + }); - // Assert - const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZipQuestionWidget']"); - expect(serviceZipField.exists()).toBe(true); - expect(serviceZipField.isVisible()).toBe(true); + test("vehicle match is found but registrationZip is not serviceable => shows service zip/state field", async () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: false, state: "XX" } }; + }); + + await wrapper.setData({ registrationZip: "00000" }); + navigateToHeritage.navigateToHeritageFunnel = jest.fn(); + + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", + }, + }, + }) + ); + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent( + "[cmsWidgetName='ServiceZipQuestionWidget']" + ); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); + }); + + test("registrationZip is not serviceable so serviceZip field is shown, continue clicked => user cannot continue", async () => { + // Arrange + const { wrapper } = setupMocks({}); + wrapper.vm.validateZip = jest.fn().mockImplementation(() => { + return { data: { isServiceable: false, state: "XX" } }; + }); + + await wrapper.setData({ registrationZipCode: "00000" }); + navigateToHeritage.navigateToHeritageFunnel = jest.fn(); + + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", + }, + }, + }) + ); + + await wrapper.vm.forwardButtonAction(); + wrapper.vm.$router.navigate = jest.fn(); + // At this point, serviceZip field is shown + + // Act + // Continue without entering anything into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent( + "[cmsWidgetName='ServiceZipQuestionWidget']" + ); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); + 3; + expect(navigateToHeritage.navigateToHeritageFunnel).not.toHaveBeenCalled(); + expect(wrapper.vm.$router.navigate).not.toHaveBeenCalled(); + }); + + test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => user can continue", async () => { + // Arrange + const { wrapper } = setupMocks({ isServiceable: false }); + const registrationZip = "00000"; + const serviceZip = "99999"; + + wrapper.vm.navigateForward = jest.fn(); + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", + }, + }, + }) + ); + + await wrapper.setData({ registrationZipCode: registrationZip }); + await wrapper.vm.forwardButtonAction(); + + // At this point, serviceZip field is shown + await wrapper.setData({ serviceZipCode: serviceZip }); + + // Act + + // Continue after entering input into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + const serviceZipField = wrapper.findComponent( + "[cmsWidgetName='ServiceZipQuestionWidget']" + ); + expect(serviceZipField.exists()).toBe(true); + expect(serviceZipField.isVisible()).toBe(true); + }); + + test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => service and registration zips/states saved", async () => { + // Arrange + const { wrapper } = setupMocks({ isServiceable: true }); + const registrationZip = "12345"; + const serviceZip = "12345"; + + wrapper.vm.navigateForward = jest.fn(); + wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + vehicle: { + carId: "C00000", + }, + }, + }) + ); + + await wrapper.setData({ registrationZipCode: registrationZip }); + await wrapper.vm.forwardButtonAction(); + + // At this point, serviceZip field is shown + await wrapper.setData({ serviceZip: serviceZip }); + + // Act + + // Continue after entering value into service zip field + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual(registrationZip); + expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual(serviceZip); + expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + }); }); - test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => service and registration zips/states saved", async () => { - // Arrange - const { wrapper } = setupMocks({ isServiceable: true }); - const registrationZip = "12345"; - const serviceZip = "12345"; + describe("miscellaneous", () => { + test("CarId set, arePagePrerequisitesValid should be true ", async () => { + //Arrange + const { wrapper } = setupMocks({}); + store.commit(storeMutations.UPDATE_CAR_ID, "TESTCARID"); - wrapper.vm.navigateForward = jest.fn(); - wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() => Promise.resolve({ - data: { - vehicle: { - carId: "C00000" - } - } - })); + //Act + licensePlateLookup.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "license-plate-lookup" } }, + undefined, + (c) => c(wrapper.vm) + ); - await wrapper.setData({ registrationZipCode: registrationZip }); - await wrapper.vm.forwardButtonAction(); - - // At this point, serviceZip field is shown - await wrapper.setData({ serviceZip: serviceZip }); + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + await nextTick(); - - // Act - - // Continue after entering value into service zip field - await wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual(registrationZip); - expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual(serviceZip); - expect(wrapper.vm.navigateForward).toHaveBeenCalled(); + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); }); - }) - - describe("miscellaneous", () => { - test("CarId set, arePagePrerequisitesValid should be true ", async () => { - //Arrange - const { wrapper } = setupMocks({}); - store.commit(storeMutations.UPDATE_CAR_ID, "TESTCARID"); - - //Act - licensePlateLookup.beforeRouteEnter.call( - wrapper.vm, - { query: { fmgPage: "license-plate-lookup" } }, - undefined, - (c) => c(wrapper.vm) - ); - - let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - await nextTick(); - - //Assert - expect(arePagePrerequisitesValid).toBe(true); - }); - - }) }); function setupMocks({ - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, - partsOrQuestions = [], - isServiceable = false, - carId = "" + pageHeaderWidgetHeaderText = {}, + mountOptionsMockData = {}, + partsOrQuestions = [], + isServiceable = false, + carId = "", }) { - store.commit(storeMutations.RESET_STATE); - //Mock api responses - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleBannerWidget: { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, - }, - serviceZipValidationResponse: { - isValid: true, - isServiceable: isServiceable - }, - registrationZipValidationResponse: { - state: "CO" - } - }; - - mountOptionsMockData = { - ...mountOptionsMockData, - router: { - navigate: jest.fn(), - navigateWithoutSaving: jest.fn(), - navigateWithSaving: jest.fn() - }, - store: { - getters: { - vehicle: { - registration: { - licensePlate: "TESTPLATE", - zipCode: "12345" - }, - carId: carId + store.commit(storeMutations.RESET_STATE); + //Mock api responses + const apiResponses = { + cmsContent: { + FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, + VehicleBannerWidget: { + GenericVehicleImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", + }, + FunnelHeaderWidget: { + LogoImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }, }, - order: { - customer: { - emailAddress: "test@test.com" - }, - serviceLocation: { - zipCode: "12345" - } - } - } - }, - actionList: [ - { - actionName: storeActions.GET_PARTS_OR_QUESTIONS, - data: { - partsOrQuestions: partsOrQuestions - } - }, - ] - } + serviceZipValidationResponse: { + isValid: true, + isServiceable: isServiceable, + }, + registrationZipValidationResponse: { + state: "CO", + }, + }; - const apiPromise = Promise.resolve(apiResponses); + mountOptionsMockData = { + ...mountOptionsMockData, + router: { + navigate: jest.fn(), + navigateWithoutSaving: jest.fn(), + navigateWithSaving: jest.fn(), + }, + store: { + getters: { + vehicle: { + registration: { + licensePlate: "TESTPLATE", + zipCode: "12345", + }, + carId: carId, + }, + order: { + customer: { + emailAddress: "test@test.com", + }, + serviceLocation: { + zipCode: "12345", + }, + }, + }, + }, + actionList: [ + { + actionName: storeActions.GET_PARTS_OR_QUESTIONS, + data: { + partsOrQuestions: partsOrQuestions, + }, + }, + ], + }; - settleAllPromises.mockImplementation(() => apiPromise); - fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + const apiPromise = Promise.resolve(apiResponses); - const mountOptions = getMountOptions(mountOptionsMockData); - mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods + settleAllPromises.mockImplementation(() => apiPromise); + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const wrapper = shallowMount(licensePlateLookup, mountOptions); + const mountOptions = getMountOptions(mountOptionsMockData); + mountOptions["attachTo"] = document.body; // append wrapper to document.body to test DOM methods - wrapper.vm.setCmsContent = jest.fn(); - wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); - wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); - wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); - wrapper.vm.$refs.loadingModal.showModal = jest.fn(); + const wrapper = shallowMount(licensePlateLookup, mountOptions); - return { wrapper, apiPromise }; + wrapper.vm.setCmsContent = jest.fn(); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); + wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); + wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); + wrapper.vm.$refs.loadingModal.showModal = jest.fn(); + + return { wrapper, apiPromise }; } diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 166c1c05e..2acec386d 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -1,111 +1,93 @@ diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue index 50cfe42c2..1b8b6da43 100644 --- a/src/layouts/molding-questions/molding-questions.vue +++ b/src/layouts/molding-questions/molding-questions.vue @@ -1,14 +1,11 @@