Merge branch 'release/2022.06.23' into feature/CSR-414-tests
This commit is contained in:
commit
de01f19e84
51 changed files with 3949 additions and 1891 deletions
|
|
@ -26,7 +26,7 @@ resources:
|
|||
type: github
|
||||
name: Safelite/AzureDevOps
|
||||
endpoint: Safelite
|
||||
ref: refs/tags/t5.4.0
|
||||
ref: refs/tags/t5.5.19
|
||||
|
||||
variables:
|
||||
- group: Digital-Infrastructure
|
||||
|
|
@ -67,9 +67,10 @@ stages:
|
|||
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
buildOutputDir: dist
|
||||
environment: Dev
|
||||
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
artifactName: vueDist
|
||||
artifactName: vueDistDev
|
||||
awsProfile: $(devDeploymentProfile)
|
||||
outputPath: /fmg/
|
||||
deployBuckets:
|
||||
|
|
@ -109,9 +110,10 @@ stages:
|
|||
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
buildOutputDir: dist
|
||||
environment: Qa
|
||||
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
artifactName: vueDist
|
||||
artifactName: vueDistQa
|
||||
awsProfile: $(qaDeploymentProfile)
|
||||
outputPath: /fmg/
|
||||
deployBuckets:
|
||||
|
|
@ -131,7 +133,7 @@ stages:
|
|||
|
||||
# Prod Build/Deploy
|
||||
- stage: Prod
|
||||
condition: eq(variables['Build.SourceBranch'], variables['prod-branch'] )
|
||||
condition: succeeded('Qa')
|
||||
variables:
|
||||
- group: FixMyGlassProd
|
||||
jobs:
|
||||
|
|
@ -150,9 +152,10 @@ stages:
|
|||
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
buildOutputDir: dist
|
||||
environment: Prod
|
||||
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
||||
parameters:
|
||||
artifactName: vueDist
|
||||
artifactName: vueDistProd
|
||||
awsProfile: $(prodDeploymentProfile)
|
||||
outputPath: /fmg/
|
||||
deployBuckets:
|
||||
|
|
@ -168,4 +171,8 @@ stages:
|
|||
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)
|
||||
cfDistributionId: $(cfDistributionId)
|
||||
- template: templates/digital/auto-tag.yml@AzureDevOps
|
||||
parameters:
|
||||
userName: SafeliteAzureDevops
|
||||
userEmail: githubazuredevops@safelite.com
|
||||
|
|
@ -18,15 +18,10 @@ module.exports = {
|
|||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||
"!src/layouts/part-questions/**/*.vue",
|
||||
"!src/layouts/reveal/**/*.vue",
|
||||
"!src/layouts/estimate/**/*.vue",
|
||||
// TODO REMOVE THESE AFTER WRITING UNIT TESTS
|
||||
"!src/layouts/address-lookup/address-lookup.vue",
|
||||
"!src/layouts/address-lookup/customer-questions/customer-questions.vue",
|
||||
"!src/layouts/address-lookup/customer-questions/address-questions/address-questions.vue",
|
||||
"!src/layouts/estimate/**/*.vue",
|
||||
// TODO REMOVE THESE AFTER WRITING UNIT TESTS
|
||||
"!src/layouts/address-vehicles/address-vehicles.vue",
|
||||
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
|
||||
"!src/common-components/dropdown-question/dropdown-question.vue",
|
||||
"!src/common-components/textbox-question/textbox-question.vue",
|
||||
"!src/ux-components/alert\alert.vue",
|
||||
"!src/helpers/validation-rules.js",
|
||||
// END
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit --coverage --ci",
|
||||
"test:unit:lite": "vue-cli-service test:unit --ci",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import dropdownQuestion from "./dropdown-question";
|
||||
|
||||
// Mock CMS content
|
||||
const questionText = "Question Text";
|
||||
const mockMixin = {
|
||||
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]
|
||||
});
|
||||
|
||||
wrapper.getCmsContent = jest.fn();
|
||||
|
||||
// Act
|
||||
const select = wrapper.find("select");
|
||||
|
||||
// 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]
|
||||
});
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// Assert
|
||||
expect(label.text()).toContain(questionText);
|
||||
|
||||
});
|
||||
|
||||
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]
|
||||
});
|
||||
|
||||
// Mock CMS content ...
|
||||
// Trust me, the below instance of the string "Question 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 = "Question Text";
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// 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]
|
||||
});
|
||||
|
||||
// Act
|
||||
const select = wrapper.find("select");
|
||||
|
||||
// Assert
|
||||
expect(select.attributes().id).toEqual("input ID");
|
||||
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value as the aria-label attribute.", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
options: {},
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// Assert
|
||||
expect(label.attributes("aria-label")).toContain(questionText);
|
||||
|
||||
});
|
||||
|
||||
it("Should return aria-disabled state as disabled", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
options: {},
|
||||
isDisabled: true,
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Act
|
||||
const select = wrapper.find("select");
|
||||
|
||||
// Assert
|
||||
expect(select.attributes("aria-disabled")).toEqual("true");
|
||||
|
||||
});
|
||||
|
||||
it("Should emit new value when modelValue is changed", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
options: {},
|
||||
modelValue: "val",
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Act
|
||||
await wrapper.find("select").setValue("val2");
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted()).toHaveProperty('change')
|
||||
|
||||
});
|
||||
|
||||
it("Should call this.handleChange with new value when selectedOption is changed", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
options: {},
|
||||
modelValue: 0,
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
wrapper.vm.handleChange = jest.fn().mockImplementation(() => {});
|
||||
|
||||
// Act
|
||||
wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.handleChange).toHaveBeenCalled;
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import dropdownQuestion from "./dropdown-question";
|
||||
import { nextTick } from "vue";
|
||||
import { maska } from 'maska';
|
||||
|
||||
describe("dropdownQuestion.vue", () => {
|
||||
|
||||
it("Should return aria-disabled state", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
isDisabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("select");
|
||||
|
||||
// Expect
|
||||
expect(input.attributes()["aria-disabled"]).toEqual("true");
|
||||
});
|
||||
|
||||
it("Should render a select input", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
name: "test",
|
||||
label: "unit test label",
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("select");
|
||||
|
||||
expect(input.exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("Should return input id", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
propsData: {
|
||||
inputId: "input ID",
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("select");
|
||||
|
||||
// Expect
|
||||
expect(input.attributes().id).toEqual("input ID");
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => {
|
||||
// Arrange
|
||||
//Mock CMS content
|
||||
const questionText = "Question Text";
|
||||
const cmsContent = {
|
||||
QuestionText: questionText,
|
||||
};
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
});
|
||||
await wrapper.setData({
|
||||
questionText: questionText,
|
||||
});
|
||||
wrapper.vm.initializeComponent(cmsContent);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.find("label").text()).toContain(questionText);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value with '⁠' after the first character as the label text when disableAutoFill is true.", async () => {
|
||||
// Arrange
|
||||
//Mock CMS content
|
||||
const originalQuestionText = "Question Text";
|
||||
// Trust me, the below instance of the string "Question Text" actually has the ⁠ in it. You just can't see it
|
||||
// Don't believe me? Copy it and paste it into Google. Then inspect the search field element in Dev Tools,
|
||||
// you will see "Q&uestion Text"
|
||||
const expectedQuestionText = "Question Text";
|
||||
const cmsContent = {
|
||||
QuestionText: originalQuestionText,
|
||||
};
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
disableAutoFill: true,
|
||||
},
|
||||
});
|
||||
await wrapper.setData({
|
||||
questionText: originalQuestionText,
|
||||
});
|
||||
wrapper.vm.initializeComponent(cmsContent);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$el.children[0].innerHTML).toBe(expectedQuestionText);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it("Should emit new value when modelValue is changed", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(dropdownQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
modelValue: "val",
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.find("select").setValue("val2");
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted()).toHaveProperty('change')
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -3,30 +3,6 @@ import funnelFooter from "./funnel-footer";
|
|||
|
||||
describe("funnel-footer.vue", () => {
|
||||
|
||||
it("Should return footer-link class", async () => {
|
||||
// Act
|
||||
const r = {
|
||||
test:"testing",
|
||||
clientHeight: 10,
|
||||
offsetHeight: 24,
|
||||
};
|
||||
|
||||
global.document.querySelector = jest.fn().mockImplementation(()=> {
|
||||
return r;
|
||||
});
|
||||
|
||||
const wrapper = mount(funnelFooter, {
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Assert
|
||||
const link = wrapper.find("a");
|
||||
|
||||
// Expect
|
||||
expect(link.attributes('class')).toContain("footer");
|
||||
|
||||
});
|
||||
|
||||
it("Should emit ForwardClicked on button click", async () => {
|
||||
// Act
|
||||
const wrapper = mount(funnelFooter, {
|
||||
|
|
@ -53,7 +29,7 @@ describe("funnel-footer.vue", () => {
|
|||
mixins: [mockMixin]
|
||||
});
|
||||
wrapper.vm.updateButtonText('newText');
|
||||
|
||||
|
||||
// Assert
|
||||
expect(wrapper.componentVM.customButtontext).toBe('newText');
|
||||
});
|
||||
|
|
@ -65,4 +41,4 @@ const mockMixin = {
|
|||
getCmsContent: jest.fn(),
|
||||
getFooterInfoBoxHeight: jest.fn(()=>80)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,7 @@
|
|||
<template>
|
||||
<div class="footer pt-4">
|
||||
<div class="container-fluid g-2">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center pb-2 fs-7">
|
||||
© {{new Date().getFullYear()}} Safelite Group
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" :style="`padding-bottom: ${paddingHeight}px`">
|
||||
<div class="col d-flex justify-content-center justify-content-around text-center">
|
||||
<textLink linkType="footer" text="Terms of use" href="https://www.safelite.com/terms-of-use" />
|
||||
<textLink linkType="footer" text="Privacy policy" href="https://www.safelite.com/safelite-group-privacy-policy" />
|
||||
<textLink linkType="footer" text="Do not sell my information" href="https://privacyportal-cdn.onetrust.com/dsarwebform/d3b95a93-e22e-4d4d-a806-482052406557/9e371601-eae3-4338-9430-b90b9036022b.html" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid fixed-bottom g-5 bg-light py-4" id="infoBox">
|
||||
<div class="row d-flex flex-row-reverse align-items-center">
|
||||
<div class="row" :style="`padding-bottom: ${paddingHeight}px`"></div>
|
||||
<footer class="footer container-fluid fixed-bottom g-5 bg-light py-4" id="infoBox">
|
||||
<div class="row d-flex flex-row-reverse align-items-center vw-100">
|
||||
<div class="col button-col d-flex" id="stacked">
|
||||
<buttonMain
|
||||
ref="buttonMain"
|
||||
|
|
@ -26,6 +12,8 @@
|
|||
:aria-disabled="isForwardActionDisabled"
|
||||
:isDisabled="isForwardActionDisabled"
|
||||
@click-event="buttonClick"
|
||||
data-bs-target="#footerModal"
|
||||
data-bs-dismiss="modal"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break">
|
||||
|
|
@ -34,11 +22,12 @@
|
|||
:text="backLink"
|
||||
@click-event="linkClick"
|
||||
href="javascript:void(0)"
|
||||
data-bs-target="#footerModal"
|
||||
data-bs-dismiss="modal"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -80,7 +69,7 @@ export default {
|
|||
},
|
||||
buttonText(){
|
||||
return this.customButtontext ? this.customButtontext : this.getCmsContent(this.cmsWidgetName, 'ForwardButtonText');
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onResize() {
|
||||
|
|
@ -112,7 +101,6 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
display: flex;
|
||||
margin-top: auto;
|
||||
a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
v-if="imageSrc"
|
||||
>
|
||||
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
|
||||
<menuModal/>
|
||||
</div>
|
||||
<alert
|
||||
class="position-absolute rounded-0 w-100 border-0 shadow-sm"
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
import alert from "@/ux-components/alert/alert";
|
||||
import eventBus from "@/helpers/event-bus/event-bus";
|
||||
import { globalEvents } from "@/constants/events";
|
||||
import menuModal from "@/common-components/funnel-header/menu-modal/menu-modal";
|
||||
|
||||
export default {
|
||||
name: "funnel-header",
|
||||
|
|
@ -43,6 +45,7 @@ export default {
|
|||
},
|
||||
components: {
|
||||
alert,
|
||||
menuModal,
|
||||
},
|
||||
mounted() {
|
||||
// Check if alert event is on the bus
|
||||
|
|
@ -50,7 +53,6 @@ export default {
|
|||
globalEvents.Categories.GLOBAL_ALERT,
|
||||
globalEvents.SubCategories.PAGE_NOT_FOUND
|
||||
);
|
||||
|
||||
// If alert event is on the bus, then display the alert
|
||||
if (alertEvent !== undefined) {
|
||||
this.displayGlobalAlert = true;
|
||||
|
|
@ -70,5 +72,6 @@ export default {
|
|||
}
|
||||
.alert {
|
||||
left: 0;
|
||||
top: 72px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
119
src/common-components/funnel-header/menu-modal/menu-modal.vue
Normal file
119
src/common-components/funnel-header/menu-modal/menu-modal.vue
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<div class="menu-modal-container">
|
||||
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" data-bs-toggle="modal" data-bs-target="#footerModal">
|
||||
<div class="bar1"></div>
|
||||
<div class="bar2"></div>
|
||||
<div class="bar3"></div>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true" v-on="{ 'show.bs.modal' : show, 'hide.bs.modal' : hide }" :style="`height: calc(100% - ${currentFooterAndHeaderHeight}px);`">
|
||||
<div class="modal-dialog modal-fullscreen">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header visually-hidden">
|
||||
<h5 class="modal-title" id="footerModalLabel">Footer Navigation</h5>
|
||||
</div>
|
||||
<div class="modal-body d-flex flex-column">
|
||||
<textLink linkType="navigation" text="Terms of use" href="https://www.safelite.com/terms-of-use" target="_blank" />
|
||||
<textLink linkType="navigation" text="Privacy policy" href="https://www.safelite.com/safelite-group-privacy-policy" target="_blank" />
|
||||
<textLink linkType="navigation" text="Do not sell my information" href="https://privacyportal-cdn.onetrust.com/dsarwebform/d3b95a93-e22e-4d4d-a806-482052406557/9e371601-eae3-4338-9430-b90b9036022b.html" target="_blank" />
|
||||
</div>
|
||||
<div class="modal-footer d-flex justify-content-start">
|
||||
© {{new Date().getFullYear()}} Safelite Group
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import textLink from "@/ux-components/text-link/text-link";
|
||||
export default {
|
||||
name: 'menuModal',
|
||||
data() {
|
||||
return {
|
||||
isActive: false,
|
||||
currentFooterAndHeaderHeight: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.currentFooterAndHeaderHeight = this.getFooterInfoBoxHeight() + 72;
|
||||
this.isActive = true;
|
||||
document.querySelector('.page-container-grouped-styles').scrollTo({
|
||||
top: 0, behavior: 'smooth'
|
||||
});
|
||||
},
|
||||
hide() {
|
||||
var self = this;
|
||||
self.isActive = false;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
textLink,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.menu-modal-container {
|
||||
position: absolute;
|
||||
padding: 1.47rem 1rem 1.47rem 1.47rem;
|
||||
right: 0;
|
||||
button {
|
||||
border: none;
|
||||
&.menu-button {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px 0 rgba(0,0,0,0.2);
|
||||
background-color: $white;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0;//Required to prevent 'squish' on iPhone
|
||||
z-index: 1056;
|
||||
.bar1,
|
||||
.bar2,
|
||||
.bar3 {
|
||||
width: 14px;
|
||||
height: 2px;
|
||||
background-color: $blue;
|
||||
margin: 1px 0;
|
||||
transition: 0.25s;
|
||||
}
|
||||
&.active .bar1 {
|
||||
transform: rotate(-45deg) translate(-3px, 3px);
|
||||
}
|
||||
&.active .bar2 {opacity: 0;}
|
||||
&.active .bar3 {
|
||||
transform: rotate(45deg) translate(-3px, -3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal {
|
||||
max-width: 576px;
|
||||
left: auto;
|
||||
height: calc(100% - 72px);
|
||||
top: 72px;
|
||||
border-top: 1px solid $gray-300;
|
||||
.modal-body {
|
||||
padding: 2rem;
|
||||
}
|
||||
.modal-fullscreen {
|
||||
width: 100vw;
|
||||
max-width: 576px;
|
||||
}
|
||||
.navigation-link {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.modal-footer {
|
||||
border-top: none;
|
||||
padding: 2rem;
|
||||
}
|
||||
//.modal-backdrop styles are in common-styles.scss
|
||||
}
|
||||
</style>
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<div class="row g-2 h-100 d-flex align-items-center">
|
||||
<div class="container-fluid overflow-hidden">
|
||||
<div class="row h-100">
|
||||
<div class="col text-center tagbg mb-2">
|
||||
<div class="col text-center tagbg mb-4">
|
||||
<div class="spinner-border text-danger" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
|
|
@ -12,17 +12,7 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="text-container slide">
|
||||
<p>Finishing up
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
</p>
|
||||
<p>Nearly there
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
</p>
|
||||
<p>Generating your quote
|
||||
<p>Assessing your damage
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
|
|
@ -32,7 +22,17 @@
|
|||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
</p>
|
||||
<p>Assessing your damage
|
||||
<p>Generating your quote
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
</p>
|
||||
<p>Nearly there
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
</p>
|
||||
<p>Finishing up
|
||||
<span class="dot-1">.</span>
|
||||
<span class="dot-2">.</span>
|
||||
<span class="dot-3">.</span>
|
||||
|
|
@ -77,7 +77,7 @@ export default {
|
|||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1055;
|
||||
z-index: 1057;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
|
|
@ -130,39 +130,39 @@ export default {
|
|||
|
||||
p {
|
||||
margin: 0 175px;
|
||||
transform: translateX(-2346px);
|
||||
transform: translateX(180px);
|
||||
}
|
||||
|
||||
@keyframes slide-in {
|
||||
0% {
|
||||
transform: translateX(-2346px)
|
||||
transform: translateX(180px)
|
||||
}
|
||||
11% {
|
||||
transform: translateX(-2010px)
|
||||
transform: translateX(-80px)
|
||||
}
|
||||
22% {
|
||||
transform: translateX(-2010px)
|
||||
transform: translateX(-80px)
|
||||
}
|
||||
33% {
|
||||
transform: translateX(-1490px)
|
||||
transform: translateX(-600px)
|
||||
}
|
||||
44% {
|
||||
transform: translateX(-1490px)
|
||||
transform: translateX(-600px)
|
||||
}
|
||||
55% {
|
||||
transform: translateX(-985px)
|
||||
transform: translateX(-1110px)
|
||||
}
|
||||
66% {
|
||||
transform: translateX(-985px)
|
||||
transform: translateX(-1110px)
|
||||
}
|
||||
77% {
|
||||
transform: translateX(-490px)
|
||||
transform: translateX(-1600px)
|
||||
}
|
||||
88% {
|
||||
transform: translateX(-490px)
|
||||
transform: translateX(-1600px)
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-40px)
|
||||
transform: translateX(-2050px)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
<template>
|
||||
<div class="menu-button" :class="[isActive ? 'active' : '']" @click="toggleClass()">
|
||||
<div class="bar1"></div>
|
||||
<div class="bar2"></div>
|
||||
<div class="bar3"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'menuButton',
|
||||
data() {
|
||||
return {
|
||||
isActive: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleClass: function(event){
|
||||
this.isActive = !this.isActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.menu-button {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0px 8px 2px rgba(0,0,0,0.2);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.bar1,
|
||||
.bar2,
|
||||
.bar3 {
|
||||
width: 14px;
|
||||
height: 2px;
|
||||
background-color: $blue-400;
|
||||
margin: 1px 0;
|
||||
transition: 0.25s;
|
||||
}
|
||||
&.active .bar1 {
|
||||
transform: rotate(-45deg) translate(-3px, 3px);
|
||||
}
|
||||
&.active .bar2 {opacity: 0;}
|
||||
&.active .bar3 {
|
||||
transform: rotate(45deg) translate(-3px, -3px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,139 +1,61 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import textboxQuestion from "./textbox-question";
|
||||
import { maska } from 'maska';
|
||||
|
||||
// Mock CMS content
|
||||
const questionText = "Question Text";
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn().mockImplementation(()=> {
|
||||
return questionText;
|
||||
})
|
||||
}
|
||||
}
|
||||
const maska = jest.fn();
|
||||
|
||||
describe("textboxQuestion.vue", () => {
|
||||
|
||||
it("Should return aria-disabled state", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
isDisabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Expect
|
||||
expect(input.attributes()["aria-disabled"]).toEqual("true");
|
||||
|
||||
});
|
||||
|
||||
it("Should render a text input", async () => {
|
||||
// Act
|
||||
// Arrange
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
name: "test",
|
||||
label: "unit test label",
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Assert
|
||||
wrapper.getCmsContent = jest.fn();
|
||||
|
||||
// Act
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Assert
|
||||
expect(input.exists()).toBe(true);
|
||||
|
||||
});
|
||||
|
||||
it("Should return input id", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
inputId: "input ID",
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Expect
|
||||
expect(input.attributes().id).toEqual("input ID");
|
||||
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value as the aria-label attribute.", async () => {
|
||||
// Arrange
|
||||
//Mock CMS content
|
||||
const questionText = "Question Text";
|
||||
const cmsContent = {
|
||||
QuestionText: questionText,
|
||||
};
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
});
|
||||
await wrapper.setData({
|
||||
questionText: questionText,
|
||||
});
|
||||
wrapper.vm.initializeComponent(cmsContent);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.find("label").attributes('aria-label')).toBe(questionText);
|
||||
wrapper.unmount();
|
||||
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => {
|
||||
// Arrange
|
||||
//Mock CMS content
|
||||
const questionText = "Question Text";
|
||||
const cmsContent = {
|
||||
QuestionText: questionText,
|
||||
};
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
await wrapper.setData({
|
||||
questionText: questionText,
|
||||
});
|
||||
wrapper.vm.initializeComponent(cmsContent);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.find("label").text()).toContain(questionText);
|
||||
wrapper.unmount();
|
||||
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value with '⁠' after the first character as the label text when disableAutoFill is true.", async () => {
|
||||
// Arrange
|
||||
//Mock CMS content
|
||||
const originalQuestionText = "Question Text";
|
||||
// Trust me, the below instance of the string "Question Text" actually has the ⁠ in it. You just can't see it
|
||||
// Don't believe me? Copy it and paste it into Google. Then inspect the search field element in Dev Tools,
|
||||
// you will see "Q&uestion Text"
|
||||
const expectedQuestionText = "Question Text";
|
||||
const cmsContent = {
|
||||
QuestionText: originalQuestionText,
|
||||
};
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// Assert
|
||||
expect(label.text()).toContain(questionText);
|
||||
|
||||
});
|
||||
|
||||
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(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
|
|
@ -143,15 +65,84 @@ describe("textboxQuestion.vue", () => {
|
|||
propsData: {
|
||||
disableAutoFill: true,
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
await wrapper.setData({
|
||||
questionText: originalQuestionText,
|
||||
});
|
||||
wrapper.vm.initializeComponent(cmsContent);
|
||||
|
||||
// Mock CMS content ...
|
||||
// Trust me, the below instance of the string "Question 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 = "Question Text";
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$el.children[0].innerHTML).toBe(expectedQuestionText);
|
||||
wrapper.unmount();
|
||||
expect(label.text()).toContain(expectedQuestionText);
|
||||
|
||||
});
|
||||
|
||||
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]
|
||||
});
|
||||
|
||||
// Act
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Assert
|
||||
expect(input.attributes().id).toEqual("input ID");
|
||||
|
||||
});
|
||||
|
||||
it("Should render the 'questionText' data value as the aria-label attribute.", async () => {
|
||||
|
||||
// Arrange
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Act
|
||||
const label = wrapper.find("label");
|
||||
|
||||
// Assert
|
||||
expect(label.attributes("aria-label")).toContain(questionText);
|
||||
|
||||
});
|
||||
|
||||
it("Should return aria-disabled state as disabled", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
isDisabled: true,
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
// Assert
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Expect
|
||||
expect(input.attributes("aria-disabled")).toEqual("true");
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -166,6 +157,7 @@ describe("textboxQuestion.vue", () => {
|
|||
propsData: {
|
||||
modelValue: "val",
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
await wrapper.find("input").setValue("val2");
|
||||
|
|
@ -175,4 +167,33 @@ describe("textboxQuestion.vue", () => {
|
|||
|
||||
});
|
||||
|
||||
it("Should call this.handleChange with new value when this.semiAggressiveValidation = true, the value is changed, and the new value is valid", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(textboxQuestion, {
|
||||
global: {
|
||||
directives: {
|
||||
maska: maska,
|
||||
}
|
||||
},
|
||||
propsData: {
|
||||
options: {},
|
||||
modelValue: "foo",
|
||||
semiAggressiveValidation: true,
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
const dynamicStrings = {
|
||||
GLOBAL_STATE: "globalState",
|
||||
CUSTOM: "custom",
|
||||
ROUTER_LINK: "routerLink"
|
||||
ROUTER_LINK: "routerLink:"
|
||||
};
|
||||
|
||||
export { dynamicStrings };
|
||||
|
|
@ -79,6 +79,10 @@ const endpoints = {
|
|||
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",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const storeActions = {
|
|||
LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
|
||||
LOG_PAGE_VIEW: "logPageView",
|
||||
LOG_CUSTOM_EVENT: "logCustomEvent",
|
||||
INITIALIZE_SESSION: "initializeSession",
|
||||
GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser",
|
||||
UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION: "updateServiceLocationWithVehicleRegistration",
|
||||
|
||||
|
|
|
|||
|
|
@ -120,4 +120,37 @@ function processWidgetItemForReplacement(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);
|
||||
}
|
||||
|
||||
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 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
|
||||
// <p ... >...</p>
|
||||
// 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(?:.*?)>)|(?:<\/p>)/g).filter(paragraph => paragraph !== "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,14 @@ export function getSessionIdValue(){
|
|||
return '00000000-0000-0000-0000-000000000000';
|
||||
}
|
||||
|
||||
export function setCookieProperties(properties) {
|
||||
if (typeof properties == "object") {
|
||||
Object.keys(properties).forEach(key => {
|
||||
document.cookie = `${key}=${properties[key]}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
= PRIVATE FUNCTIONS =
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import baseMixin from "@/mixins/base-mixin";
|
|||
export async function loadOrderIfPresent() {
|
||||
const funnelCookie = getFunnelCookie();
|
||||
|
||||
// Do nothing if there is no cookie or no correlation id.
|
||||
if (funnelCookie == null || funnelCookie.ReferralCorrelationId == null) {
|
||||
// Do nothing if there is no cookie, correlation id, or referral number.
|
||||
if (funnelCookie == null || funnelCookie.ReferralCorrelationId == null || !funnelCookie.ReferralNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ describe("loadOrderIfPresent", () => {
|
|||
|
||||
const testCookieValue = {
|
||||
ShouldResetState: testShouldResetState,
|
||||
ReferralCorrelationId: "xxx"
|
||||
ReferralCorrelationId: "xxx",
|
||||
ReferralNumber: "12345"
|
||||
}
|
||||
|
||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${JSON.stringify(testCookieValue)}; path=/; ${cookieHelper.getCookieDomainValue()}`;
|
||||
|
|
@ -33,7 +34,11 @@ describe("loadOrderIfPresent", () => {
|
|||
|
||||
test("ShouldResetState == true => reset store", () => {
|
||||
// Arrange
|
||||
cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce({ ShouldResetState: true, ReferralCorrelationId: "xxx-xxx-xxx" });
|
||||
cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValueOnce({
|
||||
ShouldResetState: true,
|
||||
ReferralCorrelationId: "xxx-xxx-xxx",
|
||||
ReferralNumber: "12345"
|
||||
});
|
||||
|
||||
const mockData = {
|
||||
actionList: [{
|
||||
|
|
|
|||
|
|
@ -24,14 +24,13 @@ export function getMountOptions(mockData) {
|
|||
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 > 0 && actionFilterResult.length === 1) {
|
||||
if (actionFilterResult.length === 1) {
|
||||
return Promise.resolve({
|
||||
data: actionFilterResult[0].data,
|
||||
});
|
||||
|
|
@ -56,6 +55,7 @@ export function getMountOptions(mockData) {
|
|||
mocks.$store = mockData.store;
|
||||
mocks.$router = mockData.router;
|
||||
mocks.$route = mockData.route;
|
||||
mocks.$loadScript = mockData.loadScript;
|
||||
|
||||
const global = {
|
||||
mocks: mocks,
|
||||
|
|
|
|||
777
src/layouts/address-lookup/address-lookup.spec.js
Normal file
777
src/layouts/address-lookup/address-lookup.spec.js
Normal file
|
|
@ -0,0 +1,777 @@
|
|||
// Components
|
||||
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
|
||||
|
||||
// Supporting Files
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
||||
import store from "@/store";
|
||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
|
||||
|
||||
jest.mock("@/helpers/damage-helper", () => ({
|
||||
isGlassAvailableForCarId: jest.fn().mockImplementation(() => true),
|
||||
getDamageString: jest.fn()
|
||||
}));
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||
navigateAfterSaveToHeritageFunnel: 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(addressLookup, {
|
||||
isZipServiceable: false
|
||||
});
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: true
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: false,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
},
|
||||
{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
})
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: true
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [] // Return no vehicles
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
|
||||
})
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
// Act
|
||||
await wrapper.vm.backButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigate).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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: true
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
},
|
||||
{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
})
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
},
|
||||
})
|
||||
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("if the car entered matches one of multiple vehicles found, update vehicle info and navigate to the heritage funnel", async () => {
|
||||
// Arrange
|
||||
const mockRegistrationAddress = {
|
||||
streetAddress: "1234 Main St",
|
||||
city: "Columbus",
|
||||
state: "OH",
|
||||
zipCode: "43215"
|
||||
}
|
||||
|
||||
const { wrapper } = setupMocks(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: true
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
},
|
||||
{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
|
||||
})
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
},
|
||||
})
|
||||
|
||||
wrapper.vm.updateVehicleInfo = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.updateVehicleInfo).toHaveBeenCalled();
|
||||
expect(navigateAfterSaveToHeritageFunnel).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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: true
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
},
|
||||
{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
|
||||
})
|
||||
|
||||
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.navigateAfterSave).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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.VALIDATE_ZIP) {
|
||||
data = {
|
||||
isServiceable: false
|
||||
}
|
||||
}
|
||||
else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
},
|
||||
{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
|
||||
})
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.dispatchStoreAction.mockImplementation((actionName, value) => {
|
||||
let data = {};
|
||||
if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
|
||||
data = {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve({ data });
|
||||
|
||||
})
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
},
|
||||
isCarIdDifferent: true,
|
||||
isGlassAvailableForCarId: false,
|
||||
})
|
||||
|
||||
let carEntered = [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
}];
|
||||
|
||||
let carsFound = [{
|
||||
vin: "TEST_VIN2",
|
||||
vehicle: {
|
||||
carId: "CARID2"
|
||||
}
|
||||
}];
|
||||
|
||||
// Act
|
||||
await wrapper.vm.navigateForward(carEntered, carsFound);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalledWith(navigationScenarios.CONTINUING_WITH_DIFFERENT_GLASS, undefined, {}, {"displayVehicleChangeAlert": true}, {});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("reseting dependent state", () => {
|
||||
test("when reseting dependent state, license plate is set to null and parts state and dependencies are reset", async () => {
|
||||
// Arrange
|
||||
const commitSpy = jest.spyOn(store, "commit");
|
||||
const dispatchSpy = jest.spyOn(store, "dispatch");
|
||||
const { wrapper } = setupMocks(addressLookup, {
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.resetDependentState();
|
||||
|
||||
// Assert
|
||||
expect(commitSpy).toBeCalledWith(storeMutations.UPDATE_REGISTRATION_LICENSE_PLATE, null);
|
||||
expect(dispatchSpy).toBeCalledWith(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
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(addressLookup,{
|
||||
isZipServiceable: true
|
||||
});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
}
|
||||
})
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION);
|
||||
});
|
||||
});
|
||||
|
||||
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(addressLookup, {
|
||||
isZipServiceable: false
|
||||
});
|
||||
|
||||
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 is provided user clicks continue => show service zip field on continue click", async () => {
|
||||
// Arrange
|
||||
const mockRegistrationAddress = {
|
||||
streetAddress: "1234 Main St",
|
||||
city: "Columbus",
|
||||
state: "OH",
|
||||
zipCode: "43215"
|
||||
}
|
||||
|
||||
const { wrapper } = setupMocks(addressLookup, {
|
||||
isZipServiceable: false
|
||||
}
|
||||
);
|
||||
|
||||
expect(wrapper.vm.showServiceZipField).toBeFalsy();
|
||||
expect(wrapper.findComponent({ ref: "serviceZip" }).exists()).toBe(false);
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
}
|
||||
})
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.showServiceZipField).toBe(true);
|
||||
expect(wrapper.findComponent({ ref: "serviceZip" }).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(addressLookup, {
|
||||
isZipServiceable: false
|
||||
}
|
||||
);
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
await wrapper.setData({
|
||||
customerQuestions: {
|
||||
addressQuestions: mockRegistrationAddress
|
||||
}
|
||||
})
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(baseMixin.methods.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(addressLookup, {});
|
||||
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, "CARID");
|
||||
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
baseMixin.methods.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(store.getters.order.serviceLocation.zipCode).not.toEqual(store.getters.vehicle.registration.zipCode);
|
||||
expect(store.getters.vehicle.registration.zipCode).toEqual("43215");
|
||||
expect(store.getters.order.serviceLocation.zipCode).toEqual("12345");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks(mountOptions, { isZipServiceable = true, lookupVinbyAddressResponse }) {
|
||||
store.commit(storeMutations.RESET_STATE);
|
||||
const wrapper = shallowMount(addressLookup, getMountOptions({
|
||||
...mountOptions,
|
||||
actionList: [
|
||||
{
|
||||
actionName: storeActions.VALIDATE_ZIP,
|
||||
data: {
|
||||
isServiceable: isZipServiceable
|
||||
}
|
||||
},
|
||||
{
|
||||
actionName: storeActions.LOOKUP_VIN_BY_ADDRESS,
|
||||
data: lookupVinbyAddressResponse ? lookupVinbyAddressResponse : {
|
||||
isStatePermissible: true,
|
||||
vinVehicles: [{
|
||||
vin: "TEST_VIN",
|
||||
vehicle: {
|
||||
carId: "CARID"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
],
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateAfterSave: jest.fn()
|
||||
},
|
||||
}));
|
||||
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||
|
||||
return { wrapper };
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
// Components
|
||||
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";
|
||||
import funnelHeader from "@/common-components/funnel-header/funnel-header";
|
||||
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
||||
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
|
||||
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
|
||||
|
||||
// Supporting Files
|
||||
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { mount, flushPromises } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { maska } from 'maska';
|
||||
import { nextTick } from "vue";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import store from "@/store";
|
||||
import { validate } from "vee-validate";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("address-lookup.vue", () => {
|
||||
test("Page header is initialized with api data", async (done) => {
|
||||
//Arrange
|
||||
const pageHeaderWidgetHeaderText = "Select Damage";
|
||||
const { wrapper, apiPromise } = setupMocks({
|
||||
pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText,
|
||||
});
|
||||
|
||||
//Act
|
||||
addressLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "address-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
//Assert
|
||||
apiPromise.finally(() => {
|
||||
expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith(
|
||||
pageHeaderWidgetHeaderText
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test("Customer Questions component is initialized with api data", async (done) => {
|
||||
//Arrange
|
||||
const StreetAddressQuestionWidget = { QuestionText: "test" };
|
||||
const CityQuestionWidget = { QuestionText: "test" };
|
||||
const StateQuestionWidget = { QuestionText: "test" };
|
||||
const ZipQuestionWidget = { QuestionText: "test" };
|
||||
const FirstNameQuestionWidget = { QuestionText: "test" };
|
||||
const LastNameQuestionWidget = { QuestionText: "test" };
|
||||
const EmailAddressQuestionWidget = { QuestionText: "test" };
|
||||
const AlertVerificationWarningWidget = { HeaderText: "test", BodyText: "test" };
|
||||
const AlertNoMatchWarningWidget = { HeaderText: "test", BodyText: "test" };
|
||||
|
||||
const widgets = [
|
||||
StreetAddressQuestionWidget,
|
||||
CityQuestionWidget,
|
||||
StateQuestionWidget,
|
||||
ZipQuestionWidget,
|
||||
AlertVerificationWarningWidget,
|
||||
AlertNoMatchWarningWidget,
|
||||
FirstNameQuestionWidget,
|
||||
LastNameQuestionWidget,
|
||||
EmailAddressQuestionWidget,
|
||||
];
|
||||
|
||||
const { wrapper, apiPromise } = setupMocks({
|
||||
cmsContent: widgets,
|
||||
});
|
||||
|
||||
//Act
|
||||
addressLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "address-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
//Assert
|
||||
apiPromise.finally(() => {
|
||||
expect(customerQuestions.methods.initializeComponent).toHaveBeenCalledWith(
|
||||
widgets
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
function setupMocks({
|
||||
pageHeaderWidgetHeaderText = {},
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
},
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}) {
|
||||
//Mock api responses
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
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",
|
||||
},
|
||||
StreetAddressQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
CityQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
StateQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
ZipQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
FirstNameQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
LastNameQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
EmailAddressQuestionWidget: {
|
||||
QuestionText:
|
||||
"test"
|
||||
},
|
||||
AlertVerificationWarningWidget: {
|
||||
HeaderText:
|
||||
"test",
|
||||
BodyText:
|
||||
"test",
|
||||
},
|
||||
AlertNoMatchWarningWidget: {
|
||||
HeaderText:
|
||||
"test",
|
||||
BodyText:
|
||||
"test",
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
const apiPromise = Promise.resolve(apiResponses);
|
||||
|
||||
settleAllPromises.mockImplementation(() => apiPromise);
|
||||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||
|
||||
//Mock damage initialize methods
|
||||
funnelHeader.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
vehicleBanner.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
funnelSubHeader.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
funnelFooter.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
customerQuestions.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
addressQuestions.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
setupAddressLookup: jest.fn(),
|
||||
};
|
||||
|
||||
const mountOptions = getMountOptions(mountOptionsMockData);
|
||||
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
||||
|
||||
mountOptions.global.directives = {
|
||||
maska: maska
|
||||
};
|
||||
|
||||
const wrapper = mount(addressLookup, mountOptions);
|
||||
|
||||
const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" });
|
||||
funnelHeaderWrapper.vm.initializeComponent =
|
||||
funnelHeader.methods.initializeComponent;
|
||||
|
||||
const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" });
|
||||
vehicleBannerWrapper.vm.initializeComponent =
|
||||
vehicleBanner.methods.initializeComponent;
|
||||
|
||||
const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" });
|
||||
funnelSubHeaderWrapper.vm.initializeComponent =
|
||||
funnelSubHeader.methods.initializeComponent;
|
||||
|
||||
const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" });
|
||||
funnelFooterWrapper.vm.initializeComponent =
|
||||
funnelFooter.methods.initializeComponent;
|
||||
|
||||
const customerQuestionsWrapper = wrapper.findComponent({ name: "customerQuestions" });
|
||||
customerQuestionsWrapper.vm.initializeComponent =
|
||||
customerQuestions.methods.initializeComponent;
|
||||
|
||||
const addressQuestionsWrapper = wrapper.findComponent({ name: "addressQuestions" });
|
||||
addressQuestionsWrapper.vm.initializeComponent =
|
||||
addressQuestions.methods.initializeComponent;
|
||||
addressQuestionsWrapper.vm.setupAddressLookup =
|
||||
addressQuestions.methods.setupAddressLookup;
|
||||
|
||||
return { wrapper, apiPromise };
|
||||
}
|
||||
|
|
@ -151,15 +151,15 @@ export default {
|
|||
);
|
||||
},
|
||||
attachCustomEvents() {
|
||||
this.prependActionToMethod(this, this.forwardButtonAction, () => {
|
||||
this.pushEventToGA(
|
||||
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||
this.GaActions.SUBMITTED,
|
||||
this.GaLabels.ADDRESS_LOOKUP,
|
||||
true
|
||||
);
|
||||
});
|
||||
},
|
||||
this.prependActionToMethod(this, this.forwardButtonAction, () => {
|
||||
this.pushEventToGA(
|
||||
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||
this.GaActions.SUBMITTED,
|
||||
this.GaLabels.ADDRESS_LOOKUP,
|
||||
true
|
||||
);
|
||||
});
|
||||
},
|
||||
getRegistrationAddressFromStore() {
|
||||
return store.getters.vehicle.registration.address;
|
||||
},
|
||||
|
|
@ -207,7 +207,7 @@ export default {
|
|||
this.$refs.funnelFooter.removeLoader();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// if the neither the registration zip code or service zip code are not serviceable
|
||||
this.isZipServicable = serviceZipValidationResponse.data.isServiceable;
|
||||
if (!this.isZipServicable) {
|
||||
|
|
@ -329,8 +329,8 @@ export default {
|
|||
{
|
||||
licenseLastName: lastName,
|
||||
licenseStreetAddress: streetAddress,
|
||||
licenseZip: zip,
|
||||
licenseState: state
|
||||
licenseZip: zip,
|
||||
licenseState: state,
|
||||
}, false
|
||||
);
|
||||
},
|
||||
|
|
@ -368,22 +368,22 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.attachCustomEvents();
|
||||
},
|
||||
this.attachCustomEvents();
|
||||
},
|
||||
computed: {
|
||||
AlertNonServiceableZipHeader(){
|
||||
AlertNonServiceableZipHeader() {
|
||||
const zipCode = this.serviceZipCode ? this.serviceZipCode : this.customerQuestions.addressQuestions.zipCode;
|
||||
const text = this.getCmsContent("AlertNonServiceableZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", zipCode);
|
||||
return text;
|
||||
},
|
||||
AlertNonServiceableZipBody(){
|
||||
AlertNonServiceableZipBody() {
|
||||
return this.getCmsContent("AlertNonServiceableZipWidget", "BodyText");
|
||||
},
|
||||
AlertMatchedDifferentVehicleHeader(){
|
||||
AlertMatchedDifferentVehicleHeader() {
|
||||
const text = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "HeadlineText").replaceAll("{custom:glassText}", getDamageString());
|
||||
return text;
|
||||
},
|
||||
AlertMatchedDifferentVehicleBody(){
|
||||
AlertMatchedDifferentVehicleBody() {
|
||||
|
||||
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
|
||||
const vinYmmExpected = `${store.getters.vehicle.year} ${store.getters.vehicle.make} ${store.getters.vehicle.model}`;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,630 @@
|
|||
// Components
|
||||
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
|
||||
// Supporting Files
|
||||
import { mount, shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
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);
|
||||
});
|
||||
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.setData({
|
||||
displayNoMatchWarning: true
|
||||
})
|
||||
expect(wrapper.vm.displayNoMatchWarning).toBeTruthy();
|
||||
|
||||
// Act
|
||||
wrapper.vm.$options.watch.addressModel.handler.call(wrapper.vm, wrapper.vm.addressModel);
|
||||
|
||||
// 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
|
||||
});
|
||||
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);
|
||||
|
||||
const resultingMountOptions = getMountOptions({
|
||||
...mountOptions,
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigateAfterSave: 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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return result ?? null;
|
||||
});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -185,11 +185,10 @@ export default ({
|
|||
},
|
||||
methods: {
|
||||
setupAddressLookup() {
|
||||
|
||||
if (this.addressModel.streetAddress !== null &
|
||||
this.addressModel.city !== null &
|
||||
this.addressModel.state !== null &
|
||||
this.addressModel.zipCode !== null) {
|
||||
if (this.addressModel.streetAddress &&
|
||||
this.addressModel.city &&
|
||||
this.addressModel.state &&
|
||||
this.addressModel.zipCode) {
|
||||
|
||||
this.showAddressFields = true;
|
||||
return;
|
||||
|
|
@ -215,12 +214,12 @@ export default ({
|
|||
// Standard place_changed event handling
|
||||
const autocompleteListener = window.google.maps.event.addListener(autocomplete, 'place_changed', fillInAddress);
|
||||
|
||||
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
||||
// will cause "autocomplete='off'" which Chrome completely ignores. This event
|
||||
// handler will set the value to something arbitrary so autofill doesn't work.
|
||||
// https://stackoverflow.com/a/30976223
|
||||
addressField1.addEventListener("focus", () => {
|
||||
addressField1.setAttribute("autocomplete", "do-not-autofill");
|
||||
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
||||
// will cause "autocomplete='off'" which Chrome completely ignores. This event
|
||||
// handler will set the value to something arbitrary so autofill doesn't work.
|
||||
// https://stackoverflow.com/a/30976223
|
||||
addressField1.addEventListener("focus", () => {
|
||||
addressField1.setAttribute("autocomplete", "do-not-autofill");
|
||||
|
||||
// Make place results box stick to the input on scroll
|
||||
const streetAddressField = document.getElementById("streetAddressField");
|
||||
|
|
@ -228,10 +227,9 @@ export default ({
|
|||
if (autocompleteResultsContainer) {
|
||||
streetAddressField.appendChild(autocompleteResultsContainer);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
addressField1.onchange = function() {
|
||||
addressField1.addEventListener("change", () => {
|
||||
const hover = document.querySelector(".pac-container .pac-item:hover");
|
||||
// if an item has been clicked, do nothing, otherwise get first solution and use Geocoder to get the place
|
||||
if (hover === null) {
|
||||
|
|
@ -258,7 +256,7 @@ export default ({
|
|||
self.displayNoMatchWarning = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function fillInAddress(place) {
|
||||
if (!place) {
|
||||
|
|
@ -310,7 +308,6 @@ export default ({
|
|||
addressField1.onchange = null;
|
||||
const pacContainer = document.querySelector(".pac-container");
|
||||
pacContainer.remove();
|
||||
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
@ -325,16 +322,10 @@ export default ({
|
|||
watch: {
|
||||
addressModel: {
|
||||
handler(newValue) {
|
||||
// The first time the address model changes is w
|
||||
if (!newValue.city &&
|
||||
!newValue.state &&
|
||||
!newValue.zipCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.displayNoMatchWarning === true) {
|
||||
// Clear no match warning on address change
|
||||
if (newValue.city || newValue.state || newValue.zipCode) {
|
||||
this.displayNoMatchWarning = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
|
||||
|
||||
const customerModel = {
|
||||
addressQuestions: {
|
||||
streetAddress: "",
|
||||
city: "",
|
||||
state: "",
|
||||
zipCode: "",
|
||||
},
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
emailAddress: "",
|
||||
}
|
||||
|
||||
describe("customerQuestions.vue", () => {
|
||||
|
||||
it("Should render customerQuestions sub-components (addressQuestions, first name, last name, and email textbox-questions)", async () => {
|
||||
// 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' });
|
||||
|
||||
// Assert
|
||||
expect(addressQuestions.exists()).toBe(true);
|
||||
expect(firstName.exists()).toBe(true);
|
||||
expect(lastName.exists()).toBe(true);
|
||||
expect(emailAddress.exists()).toBe(true);
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" :alertNotifications="alertNotifications" />
|
||||
<addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" />
|
||||
<div class="row mb-4">
|
||||
<div class="col">
|
||||
<textboxQuestion
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question";
|
||||
|
||||
|
||||
describe("addressVehiclesQuestion.vue", () => {
|
||||
|
||||
it("Should return content for differentVehicleAlertHeader", () => {
|
||||
// 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');
|
||||
});
|
||||
|
||||
it("Should emit a modelValue change when setting selectedVehicleVin", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(addressVehiclesQuestion, {
|
||||
mixins: [mockMixin],
|
||||
propsData: {
|
||||
vehicles: ["1", "2"],
|
||||
modelValue: ["1", "2"],
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
const localThis = { $emit: jest.fn() }
|
||||
addressVehiclesQuestion.computed.selectedVehicleVin.set.call(localThis, '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" }];
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import addressVehiclesQuestion from "@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
// import store from "@/store";
|
||||
|
||||
// jest.mock("@/store", () => { return {}; }, { virtual: true });
|
||||
|
||||
describe("addressVehiclesQuestion.vue", () => {
|
||||
|
||||
it("Should include button-question component", () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(addressVehiclesQuestion, {
|
||||
propsData: {
|
||||
// vehicles: [
|
||||
// {
|
||||
// "Name": "testname",
|
||||
// "Text": "testtext",
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
});
|
||||
|
||||
// console.log('wrapper.html: ', wrapper.html());
|
||||
|
||||
// Assert
|
||||
const buttonQuestion = wrapper.find('button-question-stub');
|
||||
expect(buttonQuestion).toBe;
|
||||
});
|
||||
|
||||
it("on initialize should pass in questionText", () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(addressVehiclesQuestion, {
|
||||
propsData: {},
|
||||
});
|
||||
|
||||
//Act
|
||||
addressVehiclesQuestion.methods.initializeComponent.call(wrapper.vm, {QuestionText: 'Testing question text'});
|
||||
|
||||
// console.log('wrapper.html: ', wrapper.html());
|
||||
// console.log('wrapper.vm.questionText: ', wrapper.vm.questionText);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.questionText).toEqual('Testing question text');
|
||||
});
|
||||
|
||||
// it("Alert should show if prop isCarIdDifferent is true", () => {
|
||||
// // Arrange
|
||||
// const wrapper = shallowMount(addressVehiclesQuestion, setupMountOptions({
|
||||
// propsData: {
|
||||
// isCarIdDifferent: true,
|
||||
// }
|
||||
// }));
|
||||
|
||||
// //Act
|
||||
// const alert = wrapper.find('alert');
|
||||
// console.log('wrapper.html: ', wrapper.html());
|
||||
// console.log('wrapper.vm.questionText: ', wrapper.vm.questionText);
|
||||
|
||||
// // Assert
|
||||
// // expect(wrapper.vm.questionText).toEqual('Testing question text');
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
function setupMountOptions(mountOptionsMockData = {}) {
|
||||
// //Mock store
|
||||
// store.dispatch = jest.fn(() => {});
|
||||
// store.getters = {};
|
||||
|
||||
// const mockMixin = {
|
||||
// methods: {
|
||||
// getCmsContent: jest.fn().mockImplementation(() => {
|
||||
// return '';
|
||||
// }),
|
||||
// getDamageString: jest.fn().mockImplementation(() => {
|
||||
// return '';
|
||||
// })
|
||||
// },
|
||||
// store: {
|
||||
// dispatch: store.dispatch,
|
||||
// getters: store.getters,
|
||||
// },
|
||||
// }
|
||||
|
||||
const mockGetCmsContent = jest.fn();
|
||||
mockGetCmsContent((cmsWidget, field) => {
|
||||
return field
|
||||
});
|
||||
const defaultMountOptions = {
|
||||
// route: { query: { fmgPage: 'page-name' } },
|
||||
mixins: {
|
||||
methods: {
|
||||
getCmsContent: mockGetCmsContent,
|
||||
},
|
||||
},
|
||||
global: {
|
||||
mocks: {
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData));
|
||||
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
||||
|
||||
console.log('what are allMountOptions??? ', allMountOptions);
|
||||
|
||||
return allMountOptions;
|
||||
}
|
||||
354
src/layouts/address-vehicles/address-vehicles.spec.js
Normal file
354
src/layouts/address-vehicles/address-vehicles.spec.js
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
// Components
|
||||
import addressVehicles from "@/layouts/address-vehicles/address-vehicles";
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/damage-helper", () => ({
|
||||
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({});
|
||||
wrapper.vm.$router.navigate = jest.fn();
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return false for valid page requisites if carId is missing", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.$router.navigate = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.vm.$store.getters.order.vehicle.carId = null;
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
//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.navigate = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
});
|
||||
wrapper.vm.backButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigate).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.navigateAfterSave = jest.fn();
|
||||
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {});
|
||||
wrapper.vm.navigateForward = jest.fn().mockImplementation(()=> {});
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
});
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.updateCustomerInfo).toBeCalled();
|
||||
expect(wrapper.vm.navigateForward).toBeCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should return out of forwardButtonAction if lookupVin returns with an error", async () => {
|
||||
// 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.navigateAfterSave = jest.fn();
|
||||
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(()=> {});
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
});
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.forwardButtonAction).toReturn;
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should send dispatch reset if carId is different and selected glass not available for vehicle on updateCustomerInfo", 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.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse));
|
||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
isSelectedGlassAvailableForVehicle: false,
|
||||
isCarIdDifferent: true,
|
||||
});
|
||||
await wrapper.vm.updateCustomerInfo(wrapper.vm.selectedVehicle.vin, wrapper.vm.selectedVehicle.vehicle);
|
||||
|
||||
//Assert
|
||||
expect(store.dispatch).toBeCalledWith("resetDamageAndDependencies");
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
// NOTE: this test is only here to meet code coverage; it does not test any logic in the original function
|
||||
test("Should send dispatch store action if lookupVin is called", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
await wrapper.vm.lookupVin('1234567890');
|
||||
|
||||
//Assert
|
||||
expect(store.dispatch).toBeCalledWith("lookupVehicleByVin", {"vin": "1234567890"});
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("If selectedVehicleVin changes, then should update isCarIdDifferent", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
isCarIdDifferent: false,
|
||||
});
|
||||
await wrapper.vm.resetDependentState();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.isCarIdDifferent).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("If selectedVehicleVin changes, then text on funnel footer should be updated", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
isCarIdDifferent: false,
|
||||
});
|
||||
await wrapper.vm.resetDependentState();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled();
|
||||
|
||||
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.navigateAfterSave = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
isSelectedGlassAvailableForVehicle: false,
|
||||
isCarIdDifferent: true,
|
||||
});
|
||||
await wrapper.vm.navigateForward();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigateAfterSave).toBeCalledTimes(1);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test("Should navigate to navigateAfterSaveToHeritageFunnel if carId is not different on navigateForward", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedVehicleVin: ['5NMS3CADXLH233004'],
|
||||
isSelectedGlassAvailableForVehicle: true,
|
||||
isCarIdDifferent: false,
|
||||
});
|
||||
await wrapper.vm.navigateForward();
|
||||
|
||||
//Assert
|
||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toBeCalledTimes(1);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
function setupMocks({
|
||||
// modelValueProp = "1900",
|
||||
cmsQuestionText = "CMS text goes here",
|
||||
// dataFromStoreApi = [],
|
||||
}) {
|
||||
//Mock store
|
||||
store.dispatch = jest.fn(() => {});
|
||||
store.getters = {
|
||||
pageData: jest.fn((pageName) => {
|
||||
// console.log('pageName: ', pageName) // address-vehicles
|
||||
return [
|
||||
{
|
||||
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"
|
||||
},
|
||||
];
|
||||
}),
|
||||
order: {
|
||||
vehicle: {
|
||||
carId: "123",
|
||||
},
|
||||
serviceLocation: {
|
||||
zipCode: "12345"
|
||||
},
|
||||
customer: {
|
||||
emailAddress: "qw@er.ty"
|
||||
}
|
||||
},
|
||||
damage: {
|
||||
glassToReplace: "Windshield"
|
||||
},
|
||||
vehicle: {
|
||||
carId: "456",
|
||||
}
|
||||
};
|
||||
|
||||
// baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
|
||||
|
||||
const mountOptions = getMountOptions({
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((contentName) => {
|
||||
if (contentName === "FoundMultipleVehicles") {
|
||||
return 'FoundMultipleVehiclesTestReturn';
|
||||
}
|
||||
if (contentName === "ProvideVinAlert") {
|
||||
return 'ProvideVinAlertTestReturn';
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
// dispatchStoreAction: jest.fn(() => {
|
||||
// console.log("23424243")
|
||||
// }),
|
||||
// isGlassAvailableForCarId: () => {
|
||||
// console.log("%%%%%%%%%%%%%%%")
|
||||
// return Promise.resolve(true)
|
||||
// }
|
||||
|
||||
// lookupVin: jest.fn(() => Promise.resolve(lookupVinResponse)),
|
||||
|
||||
},
|
||||
computed: {
|
||||
dynamicStrings() {
|
||||
return {ROUTER_LINK: "routerLink:"}
|
||||
}
|
||||
}
|
||||
}
|
||||
// mountOptions.propsData = {
|
||||
// modelValue: modelValueProp,
|
||||
// };
|
||||
|
||||
mountOptions.mixins = [mockMixin];
|
||||
|
||||
const wrapper = shallowMount(addressVehicles, mountOptions);
|
||||
|
||||
//Mock CMS content
|
||||
const cmsContent = {
|
||||
QuestionText: cmsQuestionText,
|
||||
};
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import addressVehicles from "@/layouts/address-vehicles/address-vehicles";
|
||||
|
||||
describe("addressVehicles.vue", () => {
|
||||
|
||||
it("Should include address-vehicles-question component", () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(addressVehicles, {
|
||||
propsData: {
|
||||
vehicles: [
|
||||
{
|
||||
"Name": "testname",
|
||||
"Text": "testtext",
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// console.log('wrapper.html: ', wrapper.html());
|
||||
|
||||
// Assert
|
||||
const addressVehiclesQuestion = wrapper.find('address-vehicles-question-stub');
|
||||
expect(addressVehiclesQuestion).toBe;
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -28,8 +28,8 @@
|
|||
/>
|
||||
<div class="alert-provide-vin my-3" v-if="splitAlertProvideVinBodyForLink.length">
|
||||
<span v-for="copy in splitAlertProvideVinBodyForLink" :key="copy">
|
||||
<span v-if="copy.includes('routerLink:')" class="text-body">
|
||||
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
||||
<span v-if="doesCopyContainRouterLink(copy)" class="text-body">
|
||||
<router-link :to="{query: {fmgPage: `${getRouterLinkRouteFromCopy(copy)}`}, name: 'root'}">{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link>
|
||||
</span>
|
||||
<span v-else class="m-0 text-body" v-html="copy"></span>
|
||||
</span>
|
||||
|
|
@ -68,6 +68,10 @@ import { required } from "@/helpers/validation-rules";
|
|||
import { Form, defineRule } from "vee-validate";
|
||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||
import { doesCopyContainRouterLink,
|
||||
splitCopyOnCMSPlaceHolder,
|
||||
getRouterLinkRouteFromCopy,
|
||||
getRouterLinkDisplayTextFromCopy, } from "@/helpers/cms-content-helper"
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("vehicle-required", required(errorMessages.VEHICLE_REQUIRED));
|
||||
|
|
@ -116,7 +120,7 @@ export default {
|
|||
},
|
||||
splitAlertProvideVinBodyForLink() {
|
||||
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
|
||||
return this.AlertProvideVinBody.split(/{(.*?)}/g);
|
||||
return this.splitCopyOnCMSPlaceHolder(this.AlertProvideVinBody);
|
||||
},
|
||||
VehiclesForQuestions() {
|
||||
const vehiclesData = this.VehiclesFromApi;
|
||||
|
|
@ -145,6 +149,10 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
doesCopyContainRouterLink,
|
||||
splitCopyOnCMSPlaceHolder,
|
||||
getRouterLinkRouteFromCopy,
|
||||
getRouterLinkDisplayTextFromCopy,
|
||||
arePagePrerequisitesValid() {
|
||||
if (
|
||||
store.getters.order.vehicle.carId
|
||||
|
|
@ -162,8 +170,10 @@ export default {
|
|||
async forwardButtonAction() {
|
||||
const vinLookup = await this.lookupVin(this.selectedVehicle.vin).catch(() => {
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
return;
|
||||
});
|
||||
if (!vinLookup) {
|
||||
return;
|
||||
}
|
||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.carId);
|
||||
this.updateCustomerInfo(this.selectedVehicle.vin, this.selectedVehicle.vehicle);
|
||||
this.navigateForward();
|
||||
|
|
@ -210,7 +220,7 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
selectedVehicleVin(vehicleVin) {
|
||||
selectedVehicleVin() {
|
||||
// does this vehicle match the previously selected carId?
|
||||
this.isCarIdDifferent = this.selectedVehicle.vehicle.carId !== store.getters.vehicle.carId;
|
||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col">
|
||||
<menuButton/>
|
||||
<menuModal/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-4">
|
||||
|
|
@ -1089,7 +1089,7 @@
|
|||
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
||||
import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question";
|
||||
import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information";
|
||||
import menuButton from "@/common-components/menu-button/menu-button";
|
||||
import menuModal from "@/common-components/funnel-header/menu-modal/menu-modal";
|
||||
export default {
|
||||
name: "App",
|
||||
components: {
|
||||
|
|
@ -1104,7 +1104,7 @@
|
|||
textboxQuestion,
|
||||
dropdownQuestion,
|
||||
vinInformation,
|
||||
menuButton,
|
||||
menuModal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ import { settleAllPromises } from "@/helpers/layout-helper.js";
|
|||
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { shallowMount, flushPromises } from "@vue/test-utils";
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { nextTick } from "vue";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import store from "@/store";
|
||||
|
||||
jest.mock('@/assets/img/loader.gif', () => 'loader.gif')
|
||||
|
|
@ -24,416 +25,502 @@ jest.mock("@/helpers/cms-content-helper", () => ({
|
|||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock Store
|
||||
jest.mock("@/store", () => ({
|
||||
commit: jest.fn(),
|
||||
dispatch: jest.fn(),
|
||||
getters: {
|
||||
order: {
|
||||
customer: { emailAddress: "test@test.com"},
|
||||
serviceLocation: {zip: "11111"},
|
||||
},
|
||||
vehicle: {
|
||||
carId: "TESTID",
|
||||
registration: {
|
||||
licensePlate: "TESTPLATE",
|
||||
zipCode: "12345",
|
||||
},
|
||||
},
|
||||
eventBusItem: jest.fn(),
|
||||
damage: {
|
||||
glassToReplace: []
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("CarId set, arePagePrerequisitesValid should be true ", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
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
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
// Act
|
||||
const licensePlate = wrapper.vm.getLicensePlateFromStore();
|
||||
|
||||
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||
await nextTick();
|
||||
|
||||
//Assert
|
||||
expect(arePagePrerequisitesValid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("BackButtonAction triggers a router.navigate 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.navigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("getLicensePlateFromStore returns store license plate", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// ACT
|
||||
const licensePlate = wrapper.vm.getLicensePlateFromStore();
|
||||
|
||||
// Assert
|
||||
expect(licensePlate).toEqual("TESTPLATE");
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("getRegistrationZipFromStore returns store registration zip", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// ACT
|
||||
const registrationZip = wrapper.vm.getRegistrationZipFromStore();
|
||||
|
||||
// Assert
|
||||
expect(registrationZip).toEqual("12345");
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("getEmailFromStore returns store customer email", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// ACT
|
||||
const customerEmail = wrapper.vm.getEmailFromStore();
|
||||
|
||||
// Assert
|
||||
expect(customerEmail).toEqual("test@test.com");
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("getServiceZipFromStore returns store service zip", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// ACT
|
||||
const serviceZip = wrapper.vm.getServiceZipFromStore();
|
||||
|
||||
// Assert
|
||||
expect(serviceZip).toEqual("11111");
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("Navigate forward should be called and isCarId should be set to false when data entered matches store data on forwardButtonAction click", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return {data: {isServiceable: true}};
|
||||
// Assert
|
||||
expect(licensePlate).toEqual(mockLicensePlate);
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
const vinLookup = {data: {vehicle: {carId: "TESTID"}}}
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return {catch: () => vinLookup};
|
||||
|
||||
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);
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
//Act
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
test("getEmailFromStore returns store customer email", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const mockEmail = "test@test.com";
|
||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, mockEmail);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
expect(wrapper.vm.isCarIdDifferent).toEqual(false);
|
||||
});
|
||||
});
|
||||
// ACT
|
||||
const customerEmail = wrapper.vm.getEmailFromStore();
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("Function should stop and datam isRegistrationZipServicable should be set to false when service zip entered returns false on forwardButtonAction click", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return {data: {isServiceable: false}};
|
||||
// Assert
|
||||
expect(customerEmail).toEqual(mockEmail);
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||
//Act
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.isRegistrationZipServicable).toEqual(false);
|
||||
});
|
||||
});
|
||||
test("getServiceZipFromStore returns store service zip", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const mockServiceZip = "11111";
|
||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, mockServiceZip);
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
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 () => {
|
||||
// ACT
|
||||
const serviceZip = wrapper.vm.getServiceZipFromStore();
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return {data: {isServiceable: true}};
|
||||
// Assert
|
||||
expect(serviceZip).toEqual(mockServiceZip);
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
const vinLookup = {data: {vehicle: {carId: "TESTID1"}}}
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return {catch: () => vinLookup};
|
||||
});
|
||||
|
||||
describe("navigation", () => {
|
||||
test("BackButtonAction triggers a router.navigate 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.navigate).toHaveBeenCalled();
|
||||
});
|
||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
|
||||
//Act
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
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 { wrapper } = setupMocks({});
|
||||
const mockCarId = "TESTID";
|
||||
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, mockCarId);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.isCarIdDifferent).toEqual(true);
|
||||
});
|
||||
});
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return { data: { isServiceable: true } };
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
||||
const vinLookup = { data: { vehicle: { carId: mockCarId } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return new Promise(resolve => resolve(vinLookup));
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
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 () => {
|
||||
//Act
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return {data: {isServiceable: true}};
|
||||
//Assert
|
||||
expect(wrapper.vm.isCarIdDifferent).toEqual(false);
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("Function should stop and datam isRegistrationZipServicable should be set to false when service zip entered returns false on forwardButtonAction click", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return { data: { isServiceable: false } };
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
//Act
|
||||
licensePlateLookup.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "license-plate-lookup" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.isRegistrationZipServicable).toEqual(false);
|
||||
});
|
||||
|
||||
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
|
||||
const { wrapper } = setupMocks({});
|
||||
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return { data: { isServiceable: true } };
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
const vinLookup = { data: { vehicle: { carId: "TESTID1" } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return new Promise(resolve => resolve(vinLookup));
|
||||
});
|
||||
|
||||
//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({});
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => {
|
||||
return { data: { isServiceable: true } };
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
const vinLookup = { data: { vehicle: { carId: "TESTID1" } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return new Promise(resolve => resolve(vinLookup));
|
||||
});
|
||||
wrapper.vm.previouslyEnteredCarId = "TESTID1";
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
//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);
|
||||
});
|
||||
});
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
const vinLookup = {data: {vehicle: {carId: "TESTID1"}}}
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return {catch: () => vinLookup};
|
||||
|
||||
describe("navigateForward", () => {
|
||||
test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = true;
|
||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
store.dispatch = jest.fn();
|
||||
|
||||
await wrapper.vm.navigateForward();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("navigateAfterSaveToHeritageFunnel should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = false;
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
await wrapper.vm.navigateForward();
|
||||
|
||||
//Assert
|
||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
wrapper.vm.previouslyEnteredCarId = "TESTID1";
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
//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("license-plate-lookup.vue", () => {
|
||||
test("Button Text should revert to initial value when licensePlate 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.vm.licensePlate = "NEWPLATE";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
//Act
|
||||
wrapper.vm.licensePlate = "NEWPLATE";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("Button Text should revert to initial value when registrationZip textfield has new text", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.registrationZip = "55555";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("Button Text should revert to initial value when serviceZip textfield has new text", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.serviceZip = "55555";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("Dispatch reset damage and dependencies should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when updateCustomerInfo is called", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = true;
|
||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
store.commit = jest.fn();
|
||||
store.dispatch = jest.fn();
|
||||
|
||||
const vehicleInfo = {year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue"}
|
||||
await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState');
|
||||
test("Button Text should revert to initial value when registrationZip textfield has new text", async () => {
|
||||
|
||||
//Assert
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("NavigateAfterSave should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when navigateForward is called", async () => {
|
||||
//Act
|
||||
wrapper.vm.registrationZip = "55555";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = true;
|
||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
||||
wrapper.vm.$router.navigateAfterSave = jest.fn();
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
store.dispatch = jest.fn();
|
||||
|
||||
await wrapper.vm.navigateForward();
|
||||
test("Button Text should revert to initial value when serviceZip textfield has new text", async () => {
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.$router.navigateAfterSave).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("navigateAfterSaveToHeritageFunnel should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => {
|
||||
//Act
|
||||
wrapper.vm.serviceZip = "55555";
|
||||
wrapper.vm.getCmsContent = jest.fn();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = false;
|
||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
//Assert
|
||||
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled();
|
||||
});
|
||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
await wrapper.vm.navigateForward();
|
||||
})
|
||||
|
||||
//Assert
|
||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).toHaveBeenCalled();
|
||||
});
|
||||
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({});
|
||||
const mockCarId = "TESTID";
|
||||
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, mockCarId)
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => {
|
||||
if (zip)
|
||||
return { data: { isServiceable: true, state: "OH" } };
|
||||
return
|
||||
});
|
||||
const vinLookup = { data: { vehicle: { carId: mockCarId } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => new Promise(resolve => resolve(vinLookup)));
|
||||
|
||||
await wrapper.setData({ registrationZip: "00000" });
|
||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(store.getters.order.serviceLocation.zipCode).toEqual(store.getters.vehicle.registration.zipCode);
|
||||
expect(store.getters.vehicle.registration.zipCode).toEqual("00000");
|
||||
expect(store.getters.order.serviceLocation.zipCode).toEqual("00000");
|
||||
})
|
||||
|
||||
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.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZip']");
|
||||
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({ registrationZip: "00000" });
|
||||
navigateToHeritage.navigateAfterSaveToHeritageFunnel = jest.fn();
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
wrapper.vm.$router.navigateAfterSave = 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='ServiceZip']");
|
||||
expect(serviceZipField.exists()).toBe(true);
|
||||
expect(serviceZipField.isVisible()).toBe(true); 3
|
||||
expect(navigateToHeritage.navigateAfterSaveToHeritageFunnel).not.toHaveBeenCalled();
|
||||
expect(wrapper.vm.$router.navigateAfterSave).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("registrationZip is not serviceable so serviceZip field is shown, user enters serviceZip => user can continue", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const registrationZip = "00000";
|
||||
const serviceZip = "99999";
|
||||
const mockCarId = "TestCarId";
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, mockCarId);
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => {
|
||||
return { data: { isServiceable: zip == registrationZip ? false : true, state: "XX" } };
|
||||
});
|
||||
const vinLookup = { data: { vehicle: { carId: mockCarId } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return new Promise(resolve => resolve(vinLookup));
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
await wrapper.setData({ registrationZip: registrationZip });
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
// At this point, serviceZip field is shown
|
||||
|
||||
await wrapper.setData({ serviceZip: serviceZip });
|
||||
|
||||
// Act
|
||||
// Continue after entering input into service zip field
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
const serviceZipField = wrapper.findComponent("[cmsWidgetName='ServiceZip']");
|
||||
expect(serviceZipField.exists()).toBe(true);
|
||||
expect(serviceZipField.isVisible()).toBe(true);
|
||||
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({});
|
||||
const registrationZip = "00000";
|
||||
const serviceZip = "99999";
|
||||
const mockCarId = "TestCarId";
|
||||
store.commit(storeMutations.UPDATE_CAR_ID, mockCarId);
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation((zip) => {
|
||||
return { data: { isServiceable: zip == registrationZip ? false : true, state: "XX" } };
|
||||
});
|
||||
const vinLookup = { data: { vehicle: { carId: mockCarId } } }
|
||||
wrapper.vm.lookupVin = jest.fn().mockImplementation(() => {
|
||||
return new Promise(resolve => resolve(vinLookup));
|
||||
});
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
await wrapper.setData({ registrationZip: 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(store.getters.vehicle.registration.zipCode).toEqual(registrationZip);
|
||||
expect(store.getters.order.serviceLocation.zipCode).toEqual(serviceZip);
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
});
|
||||
})
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
test("Dispatch reset damage and dependencies should be called if isCarIdDifferent is true and isSelectedGlassAvailableForVehicle is false when updateCustomerInfo is called", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
wrapper.vm.isCarIdDifferent = true;
|
||||
wrapper.vm.isSelectedGlassAvailableForVehicle = false;
|
||||
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
store.commit = jest.fn();
|
||||
store.dispatch = jest.fn();
|
||||
|
||||
const vehicleInfo = { year: "2020", make: "honda", model: "civic", style: "2 door", carId: "TestId", category: "testCat", imageUrl: "image.jpg", imageVifNumber: "123", imageColor: "blue" }
|
||||
await wrapper.vm.updateCustomerInfo('vin', vehicleInfo, 'registrationState');
|
||||
|
||||
//Assert
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
test("dispatch non blocking store action called on validate zip", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
await wrapper.vm.validateZip("12345");
|
||||
|
||||
|
||||
//Assert
|
||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("dispatch non blocking store action called on lookup vin", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
await wrapper.vm.lookupVin("zzz123fqsfwg");
|
||||
|
||||
|
||||
//Assert
|
||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("dispatch non blocking store action called on validate zip", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
await wrapper.vm.validateZip("12345");
|
||||
|
||||
|
||||
//Assert
|
||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("license-plate-lookup.vue", () => {
|
||||
test("dispatch non blocking store action called on lookup vin", async () => {
|
||||
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
await wrapper.vm.lookupVin("zzz123fqsfwg");
|
||||
|
||||
|
||||
//Assert
|
||||
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function setupMocks({
|
||||
pageHeaderWidgetHeaderText = {},
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
},
|
||||
licensePlate: "TESTPLATE",
|
||||
registrationZip: "12345"
|
||||
},
|
||||
}) {
|
||||
store.commit(storeMutations.RESET_STATE);
|
||||
//Mock api responses
|
||||
baseMixin.methods.dispatchStoreAction = jest.fn();
|
||||
const apiResponses = {
|
||||
|
|
@ -455,13 +542,16 @@ function setupMocks({
|
|||
settleAllPromises.mockImplementation(() => apiPromise);
|
||||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||
|
||||
|
||||
const mountOptions = getMountOptions(mountOptionsMockData);
|
||||
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
||||
|
||||
const wrapper = shallowMount(licensePlateLookup, mountOptions);
|
||||
|
||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||
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 };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,19 +220,18 @@ export default {
|
|||
return store.getters.order.customer.emailAddress;
|
||||
},
|
||||
getServiceZipFromStore() {
|
||||
return store.getters.order.serviceLocation.zip;
|
||||
return store.getters.order.serviceLocation.zipCode;
|
||||
},
|
||||
backButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
|
||||
//Call zip validation services
|
||||
const registrationZipValidationPromise = this.validateZip(this.registrationZip);
|
||||
const serviceZipValidationPromise = this.serviceZip ? this.validateZip(this.serviceZip) : null;
|
||||
const registrationZipValidationResults = await registrationZipValidationPromise;
|
||||
const serviceZipValidationResults = serviceZipValidationPromise !== null ? (await serviceZipValidationPromise) : registrationZipValidationResults;
|
||||
|
||||
|
||||
//Handle service zip validations
|
||||
if (!serviceZipValidationResults.data.isServiceable) {
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
|
|
@ -255,6 +254,7 @@ export default {
|
|||
this.isCarIdDifferent = false;
|
||||
return;
|
||||
});
|
||||
|
||||
this.isCarIdDifferent =
|
||||
vinLookup.data.vehicle.carId !== store.getters.vehicle.carId;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -405,7 +405,7 @@ export default {
|
|||
shouldDisplayVehicleChangeAlert() {
|
||||
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
|
||||
},
|
||||
shouldHideBackButton(){
|
||||
shouldHideBackButton() {
|
||||
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1 +1,112 @@
|
|||
test.todo("some test to be written in the future");
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import vinLookup from "./vin-lookup.vue";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
|
||||
import store from "@/store";
|
||||
|
||||
jest.mock("@/store", () => ({
|
||||
commit: jest.fn(),
|
||||
dispatch: jest.fn(),
|
||||
getters: {
|
||||
vehicle: {
|
||||
year: 2019,
|
||||
carId: 'initial carId'
|
||||
},
|
||||
order: {
|
||||
serviceLocation: {
|
||||
zipCode: "45253"
|
||||
},
|
||||
customer: {
|
||||
emailAddress: "builddigitaltest@safelite.com"
|
||||
}
|
||||
},
|
||||
payment: {
|
||||
insuranceCoverage: {
|
||||
isVerified: true
|
||||
}
|
||||
},
|
||||
damage: {
|
||||
glassToReplace: "windshield"
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
import { getDamageString, getIsWindshieldOnly,isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||
|
||||
jest.mock("@/helpers/damage-helper", () => ({
|
||||
isGlassAvailableForCarId: jest.fn(() => {
|
||||
return Promise.resolve();
|
||||
}),
|
||||
getIsWindshieldOnly: jest.fn(),
|
||||
getDamageString: jest.fn(),
|
||||
}));
|
||||
|
||||
|
||||
describe("vin-lookup.vue", () => {
|
||||
it("Should update the funnel-footer forward button when VIN is changed", (done) => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({ });
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
//Act
|
||||
wrapper.setData({vin: "newValue"});
|
||||
//Assert
|
||||
wrapper.vm.$nextTick(() => {
|
||||
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 () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({ });
|
||||
const zipValidationApiResponse = {
|
||||
data: {
|
||||
isServiceable: true
|
||||
}
|
||||
};
|
||||
const vehicleLookupApiResponse = {
|
||||
data: {
|
||||
carId: 'initial carId'
|
||||
}
|
||||
};
|
||||
|
||||
const zipPromise = Promise.resolve(zipValidationApiResponse);
|
||||
const vinPromise = Promise.resolve(vehicleLookupApiResponse);
|
||||
|
||||
wrapper.vm.validateZip = jest.fn().mockImplementation(() => zipPromise);
|
||||
wrapper.vm.lookupVehicle = jest.fn().mockImplementation(() => vinPromise);
|
||||
|
||||
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn();
|
||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||
wrapper.vm.navigateForward = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function setupMocks({ customMountOptions }) {
|
||||
|
||||
|
||||
const mountOptions = getMountOptions({});
|
||||
|
||||
const finalMountOptions = Object.assign(mountOptions, customMountOptions);
|
||||
// Modify/augment default mount options
|
||||
finalMountOptions.global.mocks["$store"] = store;
|
||||
finalMountOptions.global.mixins = [mockMixin];
|
||||
finalMountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
||||
|
||||
const wrapper = shallowMount(vinLookup, finalMountOptions);
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(() => "placeholder CMS content"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +1,42 @@
|
|||
import { storeActions } from "@/constants/store-actions";
|
||||
import { getDeviceIdValue, getSessionIdValue, getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { setCookieProperties, getDeviceIdValue, getSessionIdValue, getSessionKeyValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics";
|
||||
import { cookieNames } from "@/constants/cookie-names";
|
||||
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
logPageView(pageEvent) {
|
||||
// if the user does not have a session id from the content site, do not log.
|
||||
const sid = getSessionIdValue();
|
||||
if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPageName = getPageNameByQueryString();
|
||||
var payload = {
|
||||
userId: getDeviceIdValue(),
|
||||
sessionKey: getSessionKeyValue(),
|
||||
pageName: currentPageName,
|
||||
sessionId: sid,
|
||||
sessionId: getSessionIdValue(),
|
||||
action: '',
|
||||
event: pageEvent,
|
||||
shouldUseSessionId: true,
|
||||
shouldUseSessionId: false,
|
||||
};
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.LOG_PAGE_VIEW, payload, false);
|
||||
},
|
||||
|
||||
logCustomEvent(category, action, label, value) {
|
||||
// if the user does not have a session id from the content site, do not log.
|
||||
const sid = getSessionIdValue();
|
||||
if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPageName = getPageNameByQueryString();
|
||||
|
||||
var payload = {
|
||||
userId: getDeviceIdValue(),
|
||||
sessionKey: getSessionKeyValue(),
|
||||
pageName: currentPageName,
|
||||
sessionId: sid,
|
||||
sessionId: getSessionIdValue(),
|
||||
category: category,
|
||||
action: action,
|
||||
label: label,
|
||||
value: value,
|
||||
shouldUseSessionId: true,
|
||||
shouldUseSessionId: false,
|
||||
};
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.LOG_CUSTOM_EVENT, payload, false);
|
||||
|
|
@ -66,7 +56,7 @@ export default {
|
|||
pushToDataLayerIfDefined(eventToBePushed);
|
||||
|
||||
if (pushToLogApp) {
|
||||
this.logCustomEvent(category, action, label, undefined);
|
||||
this.logCustomEvent(category, action, label, undefined);
|
||||
}
|
||||
|
||||
},
|
||||
|
|
@ -116,6 +106,32 @@ export default {
|
|||
return baseMethod.apply(object, arguments);
|
||||
};
|
||||
},
|
||||
|
||||
async initSession() {
|
||||
const sid = getSessionIdValue();
|
||||
const skey = getSessionKeyValue();
|
||||
var payload = {
|
||||
userId: getDeviceIdValue(),
|
||||
sessionId: sid,
|
||||
userAgent: navigator.userAgent,
|
||||
referrer: document.referrer,
|
||||
};
|
||||
|
||||
const response = await baseMixin.methods.dispatchStoreAction(storeActions.INITIALIZE_SESSION, payload, false);
|
||||
|
||||
if (response.data) {
|
||||
if (response.data.sessionKey && skey === 0) {
|
||||
setCookieProperties({ [cookieNames.SESSION_KEY]: response.data.sessionKey});
|
||||
}
|
||||
if (response.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') {
|
||||
setCookieProperties({ [cookieNames.SESSION_ID]: response.data.sessionId});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
noSession() {
|
||||
return getSessionKeyValue() === 0 || getSessionIdValue() === '00000000-0000-0000-0000-000000000000';
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
analyticsPageEvents() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||
import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics";
|
||||
|
||||
describe("analyticsMixin.js", () => {
|
||||
test("logPageView: calls dispatch with type and payload", () => {
|
||||
|
|
@ -26,9 +27,6 @@ describe("analyticsMixin.js", () => {
|
|||
});
|
||||
|
||||
test("logCustomEvent: calls dispatch with type and payload", () => {
|
||||
const type = "";
|
||||
const payload = {};
|
||||
|
||||
const mockData = {
|
||||
actionList: [{
|
||||
actionName: storeActions.LOG_CUSTOM_EVENT
|
||||
|
|
@ -36,7 +34,7 @@ describe("analyticsMixin.js", () => {
|
|||
}
|
||||
const mocks = setupMocksForJsFiles(mockData);
|
||||
|
||||
analyticsMixin.methods.logCustomEvent(type, payload);
|
||||
analyticsMixin.methods.logCustomEvent("someCat", "someAction", "someLabel", "someVal");
|
||||
|
||||
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
|
||||
});
|
||||
|
|
@ -152,4 +150,37 @@ describe("analyticsMixin.js", () => {
|
|||
//Assert
|
||||
expect(action.startsWith("bound ")).toBe(false);
|
||||
});
|
||||
|
||||
test("analyticsPageEvents returns constants analyticsPageEvents", () => {
|
||||
//Act
|
||||
const analyticsPE = analyticsMixin.computed.analyticsPageEvents();
|
||||
|
||||
//Assert
|
||||
expect(analyticsPE).toEqual(analyticsPageEvents);
|
||||
});
|
||||
|
||||
test("GaActions returns constants GaActions", () => {
|
||||
//Act
|
||||
const gaActions = analyticsMixin.computed.GaActions();
|
||||
|
||||
//Assert
|
||||
expect(gaActions).toEqual(GaActions);
|
||||
});
|
||||
|
||||
test("GaCategories returns constants GaCategories", () => {
|
||||
//Act
|
||||
const gaCategories = analyticsMixin.computed.GaCategories();
|
||||
|
||||
//Assert
|
||||
expect(gaCategories).toEqual(GaCategories);
|
||||
});
|
||||
|
||||
test("GaLabels returns constants GaLabels", () => {
|
||||
//Act
|
||||
const gaLabels = analyticsMixin.computed.GaLabels();
|
||||
|
||||
//Assert
|
||||
expect(gaLabels).toEqual(GaLabels);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -5,6 +5,7 @@ import { navigationScenarios } from "@/router/router-constants/navigation-scenar
|
|||
import { vehicleCategories } from "@/constants/vehicle-categories.js";
|
||||
import { routerParams } from "@/router/router-constants/router-params";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { dynamicStrings } from "@/constants/dynamic-strings";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
|
@ -43,9 +44,9 @@ export default {
|
|||
}
|
||||
},
|
||||
getFooterInfoBoxHeight() {
|
||||
const footerInfoBox = document.querySelector(".footer #infoBox");
|
||||
const footerInfoBox = document.querySelector(".footer#infoBox");
|
||||
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
storeActions() {
|
||||
|
|
@ -65,6 +66,9 @@ export default {
|
|||
},
|
||||
queryStrings(){
|
||||
return queryStrings;
|
||||
},
|
||||
dynamicStrings(){
|
||||
return dynamicStrings;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ const routes = [
|
|||
async beforeEnter(to, from, next) {
|
||||
// If we have no query string, or we don't have the FmgPage query string.
|
||||
try {
|
||||
if (analyticsMixin.methods.noSession()) {
|
||||
await analyticsMixin.methods.initSession();
|
||||
}
|
||||
|
||||
// If the saved session has timed out, clear the session, execute 404 logic.
|
||||
if (getFunnelCookie() !== null && !isSavedSessionStillActive()) {
|
||||
await GoToFunnelStartOn404(next);
|
||||
|
|
|
|||
|
|
@ -509,6 +509,26 @@ export const actions = {
|
|||
});
|
||||
},
|
||||
|
||||
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
|
||||
var payload = {
|
||||
applicationName: 'SafeliteDotCom',
|
||||
userId: userId,
|
||||
deviceId: userId,
|
||||
sessionId: sessionId,
|
||||
userAgent: userAgent,
|
||||
operatorId: "WEB",
|
||||
userName: "SafeliteConceptFunnel",
|
||||
referrer: referrer
|
||||
};
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.InitializeSession.method,
|
||||
endpoint: endpoints.InitializeSession.url,
|
||||
payload: payload,
|
||||
logApiCall: false
|
||||
});
|
||||
},
|
||||
|
||||
GetExperimentsByUser(context, { userId }){
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetExperimentsByUser.method,
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ describe("Actions", () => {
|
|||
});
|
||||
|
||||
// Assert
|
||||
const response = await actions.logPageView(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", pageEvent: pageEvent, shouldUseSessionId: true });
|
||||
const response = await actions.logPageView(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", pageEvent: pageEvent, shouldUseSessionId: false });
|
||||
expect(response).toEqual({});
|
||||
});
|
||||
|
||||
|
|
@ -663,7 +663,22 @@ describe("Actions", () => {
|
|||
});
|
||||
|
||||
// Assert
|
||||
const response = await actions.logCustomEvent(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", customEvent: customEvent, shouldUseSessionId: true });
|
||||
const response = await actions.logCustomEvent(context, { userId: "userId", sessionKey: "sessionKey", pageName: "pageName", sessionId: "sessionId", customEvent: customEvent, shouldUseSessionId: false });
|
||||
expect(response).toEqual({});
|
||||
});
|
||||
|
||||
it("initializeSession action, should return nothing", async () => {
|
||||
|
||||
// Arrange
|
||||
const context = state;
|
||||
|
||||
// Act
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ });
|
||||
});
|
||||
|
||||
// Assert
|
||||
const response = await actions.initializeSession(context, { userId: "userId", sessionId: "", userAgent: "", referrer: "", shouldUseSessionId: false });
|
||||
expect(response).toEqual({});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -47,4 +47,13 @@ body {
|
|||
.page-container-grouped-styles {
|
||||
@extend .container-fluid, .shadow, .rounded-3, .p-2, .position-relative, .make-tall, .px-5;
|
||||
}
|
||||
}
|
||||
|
||||
//Footer modal backdrop adjustments for positioning
|
||||
.modal-backdrop {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: 576px;
|
||||
height: calc(100% - 72px);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,3 +180,7 @@ $box-shadow-inset: inset 0 1px 2px rgba($black, .075);
|
|||
$alert-bg-scale: -90%;
|
||||
$alert-border-scale: -100%;
|
||||
$alert-color-scale: 40%;
|
||||
|
||||
//Modal animation
|
||||
$modal-fade-transform: translate(0, 0);
|
||||
$modal-backdrop-opacity: 0;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import alert from "./alert";
|
||||
|
||||
describe("alert.vue", () => {
|
||||
|
||||
it("Should add class 'alert-dismissible' if isDismissible is true", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(alert, {
|
||||
const wrapper = shallowMount(alert, setupMocks({
|
||||
propsData: {
|
||||
isDismissible: true
|
||||
isDismissible: true,
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy'
|
||||
},
|
||||
computed: {
|
||||
splitAlertCopyForLink: {
|
||||
get() {
|
||||
return "TEST";
|
||||
},
|
||||
}
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
}));
|
||||
|
||||
const wrapperDiv = wrapper.find('div');
|
||||
|
||||
|
|
@ -27,19 +22,13 @@ describe("alert.vue", () => {
|
|||
|
||||
it("Should add specified alert class", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(alert, {
|
||||
const wrapper = shallowMount(alert, setupMocks({
|
||||
propsData: {
|
||||
alertClass: 'warning'
|
||||
alertClass: 'warning',
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy'
|
||||
},
|
||||
computed: {
|
||||
splitAlertCopyForLink: {
|
||||
get() {
|
||||
return "TEST";
|
||||
},
|
||||
}
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
}));
|
||||
|
||||
const wrapperDiv = wrapper.find('div');
|
||||
|
||||
|
|
@ -49,24 +38,171 @@ describe("alert.vue", () => {
|
|||
|
||||
it("Should update alert Headline to manualHeadline datam entered and alert copy to manualCopy datam entered when no cmsWidgetName entered", async () => {
|
||||
// Arrange
|
||||
const wrapper = shallowMount(alert, {
|
||||
propsData: {
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy'
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
|
||||
const wrapper = shallowMount(alert, setupMocks({}));
|
||||
// Assert
|
||||
expect(wrapper.vm.alertHeadline).toBe("testHeader");
|
||||
expect(wrapper.vm.alertCopy).toBe("testCopy");
|
||||
});
|
||||
|
||||
it("Should container a <router-link> tag if the manualCopy contains a {routerLink: testName, testLink} placeholder", () =>{
|
||||
// Arrange & Act
|
||||
const wrapper = shallowMount(alert, setupMocks({
|
||||
propsData: {
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy with a {routerLink: testName, testLink} inside of it'
|
||||
},
|
||||
stubs: ['router-link'],
|
||||
}));
|
||||
// Assert
|
||||
expect(wrapper.find('router-link').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("Should contain 'n+1' <p> tags if the body copy has 'n' <p> tags", () =>{
|
||||
// Arrange & Act
|
||||
const wrapper = shallowMount(alert, setupMocks({
|
||||
propsData: {
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: '<p>testCopy with a {routerLink: testName, testLink} inside of it</p><p>and two paragraphs</p>'
|
||||
},
|
||||
stubs: ['router-link'],
|
||||
}));
|
||||
// Assert
|
||||
expect(wrapper.findAll('p').length === 3).toBe(true);
|
||||
});
|
||||
|
||||
it("Should call scrollIntoView() when the clientBoundingRect is not entirely in the viewport (out of view top)", () => {
|
||||
// Arrange
|
||||
var viewPortHeight = 200;
|
||||
setUpViewPort(viewPortHeight);
|
||||
|
||||
Element.prototype.getBoundingClientRect = jest.fn(()=> {
|
||||
return {top: -100, bottom: 200}
|
||||
});
|
||||
|
||||
var mockScrollIntoView = jest.fn();
|
||||
Element.prototype.scrollIntoView = mockScrollIntoView;
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(alert, setupMocks({}));
|
||||
|
||||
// Assert
|
||||
// This is an implementation detail - we just need to test that the final step of snapping
|
||||
// the window to the alert is working. If using a different function to accomplish that
|
||||
// just swap this out with the new function
|
||||
expect(mockScrollIntoView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Should call scrollIntoView() when the clientBoundingRect is not entirely in the viewport (bottom is hidden behind footer)", () => {
|
||||
// Arrange
|
||||
var viewPortHeight = 240;
|
||||
setUpViewPort(viewPortHeight);
|
||||
|
||||
Element.prototype.getBoundingClientRect = jest.fn(()=> {
|
||||
return {top: 100, bottom: 200}
|
||||
});
|
||||
|
||||
var mockScrollIntoView = jest.fn();
|
||||
Element.prototype.scrollIntoView = mockScrollIntoView;
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(alert, setupMocks({}));
|
||||
|
||||
// Assert
|
||||
// This is an implementation detail - we just need to test that the final step of snapping
|
||||
// the window to the alert is working. If using a different function to accomplish that
|
||||
// just swap this out with the new function
|
||||
expect(mockScrollIntoView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Should not call scrollIntoView() when the clientBoundingRect is not entirely in the viewport but 'shouldScrollToOnMount' is false", () => {
|
||||
// Arrange
|
||||
var viewPortHeight = 200;
|
||||
setUpViewPort(viewPortHeight);
|
||||
|
||||
Element.prototype.getBoundingClientRect = jest.fn(()=> {
|
||||
return {top: -100, bottom: 200}
|
||||
});
|
||||
|
||||
var mockScrollIntoView = jest.fn();
|
||||
Element.prototype.scrollIntoView = mockScrollIntoView;
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(alert, setupMocks({
|
||||
propsData: {
|
||||
shouldScrollToOnMount: false,
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy'
|
||||
},
|
||||
}));
|
||||
|
||||
// Assert
|
||||
// This is an implementation detail - we just need to test that the final step of snapping
|
||||
// the window to the alert is working. If using a different function to accomplish that
|
||||
// just swap this out with the new function
|
||||
expect(mockScrollIntoView).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
it("Should not call scrollIntoView() when the clientBoundingRect is entirely in the viewport", () => {
|
||||
// Arrange
|
||||
var viewPortHeight = 500;
|
||||
setUpViewPort(viewPortHeight);
|
||||
|
||||
Element.prototype.getBoundingClientRect = jest.fn(()=> {
|
||||
return {top: 100, bottom: 200}
|
||||
});
|
||||
|
||||
var mockScrollIntoView = jest.fn();
|
||||
Element.prototype.scrollIntoView = mockScrollIntoView;
|
||||
|
||||
// Act
|
||||
const wrapper = shallowMount(alert, setupMocks({}));
|
||||
|
||||
// Assert
|
||||
// This is an implementation detail - we just need to test that the final step of snapping
|
||||
// the window to the alert is working. If using a different function to accomplish that
|
||||
// just swap this out with the new function
|
||||
expect(mockScrollIntoView).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(),
|
||||
getFooterInfoBoxHeight: jest.fn(()=> 80),
|
||||
getFooterInfoBoxHeight: jest.fn(()=> 50),
|
||||
},
|
||||
computed: {
|
||||
dynamicStrings: jest.fn(()=> {
|
||||
return {ROUTER_LINK: 'routerLink:'}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function setUpViewPort(height) {
|
||||
Object.defineProperty(global.window, 'innerHeight', {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: height,
|
||||
});
|
||||
|
||||
Object.defineProperty(window.document.documentElement, 'clientHeight', {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: height
|
||||
});
|
||||
}
|
||||
|
||||
function setupMocks(mountOptionsMockData = {}) {
|
||||
const defaultMountOptions = {
|
||||
propsData: {
|
||||
manualHeadline: 'testHeader',
|
||||
manualCopy: 'testCopy'
|
||||
},
|
||||
mixins: [mockMixin]
|
||||
};
|
||||
const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData));
|
||||
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
||||
return allMountOptions;
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<template v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">
|
||||
<p class="m-0 text-body small" v-if="!doesCopyContainRouterLink(paragraph)" v-html="paragraph"></p>
|
||||
<p class="m-0 text-body small" v-else>
|
||||
<template v-for="copy in splitCopyForRouterLink(paragraph)" :key="copy">
|
||||
<template v-for="copy in splitCopyOnCMSPlaceHolder(paragraph)" :key="copy">
|
||||
<span v-if="!doesCopyContainRouterLink(copy)" v-html="copy"></span>
|
||||
<span v-else>
|
||||
<router-link :to="{query: {fmgPage: `${getRouterLinkRouteFromCopy(copy)}`}, name: 'root'}">{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link>
|
||||
|
|
@ -36,6 +36,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { doesCopyContainRouterLink,
|
||||
splitCopyOnCMSPlaceHolder,
|
||||
getRouterLinkRouteFromCopy,
|
||||
getRouterLinkDisplayTextFromCopy,
|
||||
splitCMSCopyOnParagraphTag } from "@/helpers/cms-content-helper"
|
||||
|
||||
export default {
|
||||
name: "alert",
|
||||
|
|
@ -65,36 +70,19 @@ export default {
|
|||
return this.cmsWidgetName ? this.getCmsContent(this.cmsWidgetName, 'BodyText') : this.manualCopy;
|
||||
},
|
||||
splitAlertCopyForParagraphTag(){
|
||||
// splits the alertCopy on <p ... > (with or without attributes) and </p>
|
||||
// filter removes empty strings that are a result of string.split with regex
|
||||
return this.alertCopy.split(/(?:<p(?:.*?)>)|(?:<\/p>)/g).filter(paragraph => paragraph !== "");
|
||||
return splitCMSCopyOnParagraphTag(this.alertCopy);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
doesCopyContainRouterLink(copy) {
|
||||
return copy.includes('routerLink:');
|
||||
},
|
||||
splitCopyForRouterLink(copy){
|
||||
// splits copy on { ... } such as {routerlink: ...}
|
||||
return copy.split(/{(.*?)}/g);
|
||||
},
|
||||
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];
|
||||
},
|
||||
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];
|
||||
},
|
||||
doesCopyContainRouterLink,
|
||||
splitCopyOnCMSPlaceHolder,
|
||||
getRouterLinkRouteFromCopy,
|
||||
getRouterLinkDisplayTextFromCopy,
|
||||
ensureAlertIsInViewPort() {
|
||||
if (this.shouldScrollToOnMount && this.$el.style.display != 'none') {
|
||||
var footerHeight = this.getFooterInfoBoxHeight();
|
||||
if (!this.isAlertInViewport(footerHeight)) {
|
||||
this.scrollContainerToAlert(footerHeight);
|
||||
this.$el.scrollIntoView(true); // 'true' attempts to scroll element to top of viewport
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -106,14 +94,6 @@ export default {
|
|||
rect.bottom <= (window.innerHeight - footerHeight || document.documentElement.clientHeight - footerHeight)
|
||||
);
|
||||
},
|
||||
scrollContainerToAlert(footerHeight) {
|
||||
// alert position on page + height of alert + footer height
|
||||
var scrollToHeight = this.$el.scrollHeight + this.$el.offsetHeight + footerHeight;
|
||||
// find the div wrapped by the form element - this is the scrollable container
|
||||
// should be a more future-proof selector in case of CSS class changes
|
||||
var pageContainerScrollable = document.querySelector('form > div');
|
||||
pageContainerScrollable.scrollTo(0, scrollToHeight);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.ensureAlertIsInViewPort();
|
||||
|
|
|
|||
Loading…
Reference in a new issue