Merge branch 'develop' into feature/CSR-638

This commit is contained in:
Leah Schumann 2022-05-24 16:31:40 -04:00
commit 7d885d4184
24 changed files with 378 additions and 111 deletions

View file

@ -1,6 +1,7 @@
<template> <template>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition :duration="{ enter: 800, leave: 300 }" name="route-fade" mode="out-in"> <transition :duration="{ enter: 200, leave: 200 }" name="route-fade" mode="out-in">
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
<component :is="Component" /> <component :is="Component" />
</transition> </transition>
</router-view> </router-view>

View file

@ -52,7 +52,6 @@ import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-bu
import listCard from "@/ux-components/list-card/list-card"; import listCard from "@/ux-components/list-card/list-card";
import { ErrorMessage } from 'vee-validate'; import { ErrorMessage } from 'vee-validate';
import radio from "@/ux-components/radio/radio"; import radio from "@/ux-components/radio/radio";
import { queryStrings } from "@/constants/query-strings";
export default { export default {
name: "buttonQuestion", name: "buttonQuestion",
@ -135,8 +134,6 @@ export default {
}, },
handleCheckedChanged(val) { handleCheckedChanged(val) {
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, val.value, true);
if(this.isMultiSelect && this.selectedValues) { if(this.isMultiSelect && this.selectedValues) {
// Add or remove item to array of data to emit // Add or remove item to array of data to emit
const newSelectedValues = this.selectedValues; const newSelectedValues = this.selectedValues;

View file

@ -1,91 +1,237 @@
<template> <template>
<div v-if="isModalVisible" class="loading-modal-backdrop"> <div v-if="isModalVisible" class="container-fluid modal-loader">
<div class="loading-modal"> <div class="row g-2 h-100 d-flex align-items-center">
<section class="loading-modal-body"> <div class="container-fluid overflow-hidden">
<div class="modal-icon-container text-center"> <div class="row h-100">
<object type="image/svg+xml" :data="fmgAnimatedTransition"/> <div class="col text-center tagbg mb-2">
<div class="spinner-border text-danger" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div> </div>
</section> <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
<span class="dot-1">.</span>
<span class="dot-2">.</span>
<span class="dot-3">.</span>
</p>
<p>Finding your glass
<span class="dot-1">.</span>
<span class="dot-2">.</span>
<span class="dot-3">.</span>
</p>
<p>Assessing your damage
<span class="dot-1">.</span>
<span class="dot-2">.</span>
<span class="dot-3">.</span>
</p>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
// load the path like this - <object> data attribute doesn't load the relative path correctly export default {
const FMGAnimatedTransition = require("@/assets/img/FMGTransitionAnimation.svg"); name: 'Modal',
export default { data() {
name: 'Modal', return {
data() { isModalVisible: false,
return { };
isModalVisible: false, },
fmgAnimatedTransition: FMGAnimatedTransition, methods: {
}; showModal() {
}, //Display modal
methods: { this.isModalVisible = true;
showModal() { //Force page reload on back button
//Display modal window.addEventListener("pageshow", function(evt) {
this.isModalVisible = true; if(evt.persisted){
//Force page reload on back button
window.addEventListener("pageshow", function(evt) {
if(evt.persisted){
setTimeout(function(){ setTimeout(function(){
window.location.reload(); window.location.reload();
}, 10); }, 10);
} }
}, false); }, false);
},
}, },
}; },
};
</script> </script>
<style lang="scss"> <style lang="scss">
.loading-modal-backdrop { .modal-loader {
position: fixed; position: fixed;
top: 0; top: 0;
bottom: 0; left: 0;
left: 0; right: 0;
right: 0; bottom: 0;
background-color: #e5e5e5; z-index: 1055;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
outline: 0;
background: $gray-100;
.tagbg {
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 84 32'%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' fill='%23fff'/%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' fill='%23fff'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06.8c8.08 0 11.89.935 11.89.935 3.58.576 5.696 7.207 5.696 7.207h.727c0-2.427 1.302-2.397 2.341-2 .723.292 1.363.76 1.86 1.361 1.319 1.547.465 1.674.465 1.674h-5.067l3.846 3.01v12.016c0 2.41-2.029 2.31-2.029 2.31H22.338s-2.029.1-2.029-2.31V12.996l3.84-3.009H19.07s-.853-.127.466-1.674a4.693 4.693 0 0 1 1.86-1.361c1.032-.397 2.341-.427 2.341 2h.736s2.117-6.64 5.696-7.21c0 0 3.81-.942 11.89-.942Z' fill='%23fff' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06 8.847c7.924 0 14.685.511 14.685.511 0-2.585-2.38-6.011-2.38-6.011S50.4 2.519 42.06 2.519s-12.303.828-12.303.828-2.38 3.426-2.38 6.011c0 0 6.76-.51 14.683-.51Z' fill='%23DA291C' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M35.277 16.523a62.558 62.558 0 0 1 13.277 0m3.276-.439s2.384-2.257 8.608-2.257c0 0 1.179 2.657-2.54 3.37m-25.894-1.113s-2.387-2.257-8.611-2.257c0 0-1.16 2.579 2.543 3.37m-3.546 5.856s21.52 3.647 39.123 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center center;
background-size: 96px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
z-index: 1050;
width: 100vw;
height: 100vh;
} }
.loading-modal { .spinner-border {
width: 6.5rem;
height: 6.5rem;
border: 0.45em solid currentColor;
border-right-color: transparent;
}
.text-container {
display: flex;
width: 350px;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
position: relative;
&:after {
content: '';
background: rgb(245,245,245);
background: linear-gradient(270deg, rgba(245,245,245,1) 0%, rgba(245,245,245,0) 5%, rgba(245,245,245,0) 95%, rgba(245,245,245,1) 100%);
position: absolute; position: absolute;
background: #ffffff; width: 100%;
padding: 0 0 32px 0; height: 100%;
box-shadow: 2px 2px 20px 1px; z-index: 2;
overflow: hidden; top: 0;
display: flex; left: 0;
flex-direction: column; right: 0;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); bottom: 0;
border-radius: 4px;
top: 48px;
height: 186px;
width: 327px;
} }
.loading-modal-text { &.slide p {
padding: 0 24px 0 24px; animation: slide-in 20s ease-in-out 1s forwards 1;
} }
.modal-icon-container {
margin: 15px auto; p {
padding-bottom: 26px; margin: 0 175px;
transform: translateX(-2346px);
} }
.modal-icon-container img { @keyframes slide-in {
position: absolute; 0% {
vertical-align: middle; transform: translateX(-2346px)
border: 0; }
width: 327px; 11% {
height: 186px; transform: translateX(-2010px)
left: 50%; }
top: 50%; 22% {
transform: translate(-50%, -50%); transform: translateX(-2010px)
}
33% {
transform: translateX(-1490px)
}
44% {
transform: translateX(-1490px)
}
55% {
transform: translateX(-985px)
}
66% {
transform: translateX(-985px)
}
77% {
transform: translateX(-490px)
}
88% {
transform: translateX(-490px)
}
100% {
transform: translateX(-40px)
}
} }
.dot-1 {
animation: blinking-elipsis .75s linear infinite;
@keyframes blinking-elipsis {
0% {
opacity: 1;
}
65% {
opacity: 1;
}
66% {
opacity: 0;
}
100% {
opacity: 0;
}
}
}
.dot-2 {
animation: blinking-elipsis-2 .75s linear infinite;
@keyframes blinking-elipsis-2 {
0% {
opacity: 0;
}
21% {
opacity: 0;
}
22% {
opacity: 1;
}
65% {
opacity: 1;
}
66% {
opacity: 0;
}
100% {
opacity: 0;
}
}
}
.dot-3 {
animation: blinking-elipsis-3 .75s linear infinite;
@keyframes blinking-elipsis-3 {
0% {
opacity: 0;
}
43% {
opacity: 0;
}
44% {
opacity: 1;
}
65% {
opacity: 1;
}
66% {
opacity: 0;
}
100% {
opacity: 0;
}
}
}
}
}
</style> </style>

View file

@ -3,17 +3,18 @@ import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
export function getDamageString() { export function getDamageString() {
const damageLocations = store.getters.damage.glassToReplace; // If it's a repair it's always a windshield.
const isRepair = store.getters.damage.isRepair; const isRepair = store.getters.damage.isRepair;
if(isRepair){
return "windshield"
}
const damageLocations = store.getters.damage.glassToReplace;
let returnString; let returnString;
if (!damageLocations) { if (!damageLocations) {
return; return;
} }
// If it's a repair it's always a windshield.
if(isRepair){
return "windshield"
}
if (damageLocations.length > 1) { if (damageLocations.length > 1) {
returnString = "match" returnString = "match"

View file

@ -6,6 +6,8 @@ import { applicationConfig } from "@/constants/application-config";
Will update the cookie if present, or create a new one if not. Will update the cookie if present, or create a new one if not.
*/ */
export function updateOrCreateFunnelCookie() { export function updateOrCreateFunnelCookie() {
const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration;
// Create the cookie // Create the cookie
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}={}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()};`; document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}={}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()};`;
@ -19,6 +21,7 @@ export function updateOrCreateFunnelCookie() {
ReferralDate: store.getters.order.referralDate, ReferralDate: store.getters.order.referralDate,
ReferralCorrelationId: store.getters.order.referralCorrelationId, ReferralCorrelationId: store.getters.order.referralCorrelationId,
ReferralParentAccountNumber: store.getters.order.accountNumber, ReferralParentAccountNumber: store.getters.order.accountNumber,
HasDelayedClaimRegistration: wasClaimRegistrationDelayed
}); });
} }

View file

@ -305,7 +305,7 @@ describe("getPageToRouteExistingOrderTo", () => {
describe("navigateToHeritageFunnel", () => { describe("navigateToHeritageFunnel", () => {
test("should save order", async () => { test("should save order", async () => {
// Arrange // Arrange
const mockReferralNumber = 2; const mockReferralNumber = "2";
const mockCorrelationId = "55"; const mockCorrelationId = "55";
const mockReferralDate = "2022"; const mockReferralDate = "2022";
@ -337,7 +337,7 @@ describe("navigateToHeritageFunnel", () => {
test("should go to heritage funnel", async () => { test("should go to heritage funnel", async () => {
// Arrange // Arrange
const mockReferralNumber = 2; const mockReferralNumber = "2";
const mockCorrelationId = "55"; const mockCorrelationId = "55";
const mockReferralDate = "2022"; const mockReferralDate = "2022";

View file

@ -38,10 +38,10 @@ export async function saveOrder() {
// Save the referral information back from the store. // Save the referral information back from the store.
await baseMixin.methods.dispatchStoreAction(storeActions.SET_REFERRAL_INFORMATION, { await baseMixin.methods.dispatchStoreAction(storeActions.SET_REFERRAL_INFORMATION, {
referralNumber: savedOrderInfo.data.referralNumber, referralNumber: savedOrderInfo.data.referralNumber.toString(),
referralCorrelationId: savedOrderInfo.data.referralCorrelationId, referralCorrelationId: savedOrderInfo.data.referralCorrelationId,
referralDate: savedOrderInfo.data.referralDate, referralDate: savedOrderInfo.data.referralDate,
accountNumber: savedOrderInfo.data.accountNumber accountNumber: savedOrderInfo.data.accountNumber.toString()
}, false); }, false);
// Update the cookie with the referral information when saved. // Update the cookie with the referral information when saved.

View file

@ -103,11 +103,12 @@ describe("saveOrder", () => {
test("saveOrder => should set state order values", async () => { test("saveOrder => should set state order values", async () => {
// Arrange // Arrange
const mockReferralNumber = 2; const mockReferralNumber = "2";
const mockCorrelationId = "55"; const mockCorrelationId = "55";
const mockReferralDate = "2022"; const mockReferralDate = "2022";
const mockAccountNumber = "5";
const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate); const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber);
const mockData = { const mockData = {
actionList: [ actionList: [
@ -131,7 +132,8 @@ describe("saveOrder", () => {
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SET_REFERRAL_INFORMATION, { expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SET_REFERRAL_INFORMATION, {
referralNumber: mockReferralNumber, referralNumber: mockReferralNumber,
referralDate: mockReferralDate, referralDate: mockReferralDate,
referralCorrelationId: mockCorrelationId referralCorrelationId: mockCorrelationId,
accountNumber: mockAccountNumber
}, false); }, false);
}); });

View file

@ -89,11 +89,12 @@ export function removeAllTestCookies() {
}); });
} }
export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate) { export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0") {
return { return {
referralNumber: mockReferralNumber, referralNumber: mockReferralNumber,
referralCorrelationId: mockCorrelationId, referralCorrelationId: mockCorrelationId,
referralDate: mockReferralDate referralDate: mockReferralDate,
accountNumber: accountNumber
} }
} }

View file

@ -18,6 +18,7 @@ import store from "@/store";
import { validate } from "vee-validate"; import { validate } from "vee-validate";
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js"; import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
import { routerParams } from "@/router/router-constants/router-params"; import { routerParams } from "@/router/router-constants/router-params";
import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper";
// Mock our module for promises. // Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({ jest.mock("@/helpers/layout-helper.js", () => ({
@ -29,6 +30,11 @@ jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(), fetchCmsContentForPage: jest.fn(),
})); }));
// Mock getFunnelCookie
jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({
getFunnelCookie: jest.fn(),
}));
// Mock Store // Mock Store
jest.mock("@/store", () => ({ jest.mock("@/store", () => ({
commit: jest.fn(), commit: jest.fn(),
@ -653,6 +659,10 @@ describe("vehicle-damage.vue", () => {
}) })
}); });
describe("vehicle-damage.vue wasDelayedClaimRegistration", () => {
test.todo("if wasDelayedClaimRegistration, should hide back button")
});
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE // THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST // BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
// //
@ -741,6 +751,7 @@ function setupMocks({pageHeaderWidgetHeaderText, mountOptionsMockData}) {
settleAllPromises.mockImplementation(() => apiPromise); settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValue({});
//Mock damage initialize methods //Mock damage initialize methods
damageLocationQuestion.methods = { damageLocationQuestion.methods = {

View file

@ -32,7 +32,7 @@
:selectedDamageLocations="selectedDamageLocations" :selectedDamageLocations="selectedDamageLocations"
/> />
<alert <alert
class="my-3" class="my-5"
cmsWidgetName="HasReplacementConflict" cmsWidgetName="HasReplacementConflict"
v-show="hasRepairReplaceConflict" v-show="hasRepairReplaceConflict"
alertClass="alert-danger" alertClass="alert-danger"
@ -87,6 +87,7 @@ import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import { damageLocationsCms } from "@/constants/damage-locations-cms.js"; import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js"; import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import store from "@/store"; import store from "@/store";
import baseMixin from "@/mixins/base-mixin"; import baseMixin from "@/mixins/base-mixin";
@ -405,7 +406,7 @@ export default {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]; return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}, },
shouldHideBackButton(){ shouldHideBackButton(){
return this.$store.getters.payment.insuranceCoverage.isVerified; return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
} }
}, },

View file

@ -30,7 +30,7 @@
isRequired isRequired
/> />
<alert <alert
class="my-3" class="mt-5"
cmsWidgetName="SplitSingleConflict" cmsWidgetName="SplitSingleConflict"
v-if="hasSplitSingleConflict" v-if="hasSplitSingleConflict"
alertClass="alert-danger" alertClass="alert-danger"

View file

@ -102,7 +102,7 @@
:manualHeadline="PerfectMatchNewVinAlertHeader" :manualHeadline="PerfectMatchNewVinAlertHeader"
:manualCopy="PerfectMatchNewVinAlertBody" :manualCopy="PerfectMatchNewVinAlertBody"
v-model="customAlertData" v-model="customAlertData"
v-if="perfectMatchNewVinAlert && !noServiceZip && !vinNotFound && meta.valid" v-if="perfectMatchNewVinAlert && !noServiceZip && !vinNotFound && meta.valid && !isVinFieldReadOnly"
alertClass="alert-success" alertClass="alert-success"
/> />
<funnelFooter <funnelFooter
@ -140,6 +140,7 @@ import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "
import { required, regex } from "@/helpers/validation-rules"; import { required, regex } from "@/helpers/validation-rules";
import { Form, defineRule } from "vee-validate"; import { Form, defineRule } from "vee-validate";
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
@ -189,6 +190,7 @@ export default {
}, },
watch: { watch: {
vin() { vin() {
this.vinNotFound = false;
this.$refs.funnelFooter.updateButtonText( this.$refs.funnelFooter.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
@ -236,7 +238,7 @@ export default {
getIsWindshieldOnly()) getIsWindshieldOnly())
}, },
isVinFieldReadOnly(){ isVinFieldReadOnly(){
return this.$store.getters.payment.insuranceCoverage.isVerified; return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
}, },
}, },
methods: { methods: {

View file

@ -9,12 +9,18 @@ import baseMixin from "@/mixins/base-mixin";
export default { export default {
methods: { methods: {
logPageView(pageEvent) { 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(); const currentPageName = getPageNameByQueryString();
var payload = { var payload = {
userId: getDeviceIdValue(), userId: getDeviceIdValue(),
sessionKey: getSessionKeyValue(), sessionKey: getSessionKeyValue(),
pageName: currentPageName, pageName: currentPageName,
sessionId: getSessionIdValue(), sessionId: sid,
action: '', action: '',
event: pageEvent, event: pageEvent,
shouldUseSessionId: true, shouldUseSessionId: true,
@ -24,12 +30,18 @@ export default {
}, },
logCustomEvent(category, action, label, value) { 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(); const currentPageName = getPageNameByQueryString();
var payload = { var payload = {
userId: getDeviceIdValue(), userId: getDeviceIdValue(),
sessionKey: getSessionKeyValue(), sessionKey: getSessionKeyValue(),
pageName: currentPageName, pageName: currentPageName,
sessionId: getSessionIdValue(), sessionId: sid,
category: category, category: category,
action: action, action: action,
label: label, label: label,

View file

@ -1,5 +1,5 @@
import analyticsMixin from "@/mixins/analytics-mixin"; import analyticsMixin from "@/mixins/analytics-mixin";
import { setupMocksForJsFiles } from "@/helpers/unit-test-helper.js"; import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
describe("analyticsMixin.js", () => { describe("analyticsMixin.js", () => {
@ -14,6 +14,12 @@ describe("analyticsMixin.js", () => {
} }
const mocks = setupMocksForJsFiles(mockData); const mocks = setupMocksForJsFiles(mockData);
const testCookieValue = {
sid: '10000000-0000-0000-0000-000000000001'
}
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
analyticsMixin.methods.logPageView(type, payload); analyticsMixin.methods.logPageView(type, payload);
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled(); expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();

View file

@ -21,6 +21,7 @@ import analyticsMixin from "@/mixins/analytics-mixin";
// Components // Components
import ComponentTest from "@/layouts/component-test/component-test.vue"; import ComponentTest from "@/layouts/component-test/component-test.vue";
import FormTest from "@/layouts/form-test/form-test.vue"; import FormTest from "@/layouts/form-test/form-test.vue";
import Modal from "@/common-components/loading-modal/loading-modal.vue";
const routes = [ const routes = [
@ -34,6 +35,11 @@ const routes = [
name: "FormTest", name: "FormTest",
component: FormTest, component: FormTest,
}, },
{
path: "/loading-modal", // This is a temporary route for testing.
name: "Modal",
component: Modal,
},
{ {
path: "/", path: "/",
name: "root", name: "root",

View file

@ -573,9 +573,9 @@ export const actions = {
state: order.serviceLocation.state, state: order.serviceLocation.state,
zipCode: order.serviceLocation.zipCode zipCode: order.serviceLocation.zipCode
}, },
referralNumber: order.referralNumber, referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
referralDate: order.referralDate, referralDate: order.referralDate,
accountNumber: order.accountNumber accountNumber: order.accountNumber?.toString()
}, },
}); });
}, },
@ -585,10 +585,10 @@ export const actions = {
method: endpoints.LoadOrder.method, method: endpoints.LoadOrder.method,
endpoint: endpoints.LoadOrder.url, endpoint: endpoints.LoadOrder.url,
payload: { payload: {
referralNumber: referralNumber, referralNumber: referralNumber?.toString(),
referralDate: referralDate, referralDate: referralDate,
referralCorrelationId: referralCorrelationId, referralCorrelationId: referralCorrelationId,
accountNumber: accountNumber accountNumber: accountNumber?.toString()
}, },
}).then((response) => { }).then((response) => {
context.commit(storeMutations.RESET_STATE); context.commit(storeMutations.RESET_STATE);

View file

@ -12,11 +12,11 @@
} }
.route-fade-enter-active .fade-on-route-transition { .route-fade-enter-active .fade-on-route-transition {
transition: opacity 0.8s ease; transition: opacity 0.2s ease-out; //This duration should be kept in sync with the app.vue <transition> element attribute
} }
.route-fade-leave-active .fade-on-route-transition { .route-fade-leave-active .fade-on-route-transition {
transition: opacity 0.3s ease; transition: opacity 0.2s ease-in; //This duration should be kept in sync with the app.vue <transition> element attribute
} }
.route-fade-enter-from .fade-on-route-transition, .route-fade-enter-from .fade-on-route-transition,

View file

@ -1,6 +1,7 @@
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from "@vue/test-utils";
import listButtonHorizontal from "./list-button-horizontal"; import listButtonHorizontal from "./list-button-horizontal";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { GaActions } from "@/constants/analytics";
describe("list-button-horizontal.vue", () => { describe("list-button-horizontal.vue", () => {
it("Should return input type checkbox if isMultiSelect is true", async () => { it("Should return input type checkbox if isMultiSelect is true", async () => {
@ -90,6 +91,13 @@ describe("list-button-horizontal.vue", () => {
it("Should return loader enabled true", async () => { it("Should return loader enabled true", async () => {
// Act // Act
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
selectingInitiatesLoad: true, selectingInitiatesLoad: true,
}, },
@ -112,6 +120,13 @@ describe("list-button-horizontal.vue", () => {
it("Should return loader color", async () => { it("Should return loader color", async () => {
// Act // Act
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
loaderColor: "blue", loaderColor: "blue",
selectingInitiatesLoad: true, selectingInitiatesLoad: true,
@ -135,6 +150,13 @@ describe("list-button-horizontal.vue", () => {
it("Should return loader position", async () => { it("Should return loader position", async () => {
// Act // Act
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
loaderPosition: "right", loaderPosition: "right",
selectingInitiatesLoad: true, selectingInitiatesLoad: true,

View file

@ -54,6 +54,7 @@
<script> <script>
import { useField } from "vee-validate"; import { useField } from "vee-validate";
import loader from "@/ux-components/loader/loader"; import loader from "@/ux-components/loader/loader";
import { queryStrings } from "@/constants/query-strings";
export default { export default {
name: "listButtonHorizontal", name: "listButtonHorizontal",
@ -91,6 +92,10 @@ export default {
: this.selectedValues[0]; : this.selectedValues[0];
} }
}, },
unmounted() { // needed to clear this button's selectedValues if it is removed
this.checkValue = false;
this.handleCheckChange();
},
methods: { methods: {
displayLoader() { displayLoader() {
this.isLoaderDisplayed = true; this.isLoaderDisplayed = true;
@ -116,6 +121,7 @@ export default {
this.handleCheckChange(); this.handleCheckChange();
} }
this.handleChange(this.value); this.handleChange(this.value);
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
}, },
handleCheckChange() { handleCheckChange() {
const emitEvent = { const emitEvent = {

View file

@ -1,6 +1,7 @@
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from "@vue/test-utils";
import listButton from "./list-button"; import listButton from "./list-button";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { GaActions } from "@/constants/analytics";
describe("list-button.vue", () => { describe("list-button.vue", () => {
it("Should return input type checkbox if isMultiSelect is true", async () => { it("Should return input type checkbox if isMultiSelect is true", async () => {
@ -90,6 +91,13 @@ describe("list-button.vue", () => {
it("Should return loader enabled true", async () => { it("Should return loader enabled true", async () => {
// Act // Act
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
selectingInitiatesLoad: true, selectingInitiatesLoad: true,
}, },
@ -109,6 +117,13 @@ describe("list-button.vue", () => {
it("Should return loader color", async () => { it("Should return loader color", async () => {
// Act // Act
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
loaderColor: "blue", loaderColor: "blue",
selectingInitiatesLoad: true, selectingInitiatesLoad: true,
@ -128,6 +143,13 @@ describe("list-button.vue", () => {
it("Should return loader position", async () => { it("Should return loader position", async () => {
// Act // Act
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
loaderPosition: "right", loaderPosition: "right",
selectingInitiatesLoad: true, selectingInitiatesLoad: true,

View file

@ -54,6 +54,7 @@
<script> <script>
import { useField } from "vee-validate"; import { useField } from "vee-validate";
import loader from "@/ux-components/loader/loader"; import loader from "@/ux-components/loader/loader";
import { queryStrings } from "@/constants/query-strings";
export default { export default {
name: "listButton", name: "listButton",
@ -91,6 +92,10 @@ export default {
: this.selectedValues[0]; : this.selectedValues[0];
} }
}, },
unmounted() { // needed to clear this button's selectedValues if it is removed
this.checkValue = false;
this.handleCheckChange();
},
methods: { methods: {
displayLoader() { displayLoader() {
this.isLoaderDisplayed = true; this.isLoaderDisplayed = true;
@ -116,6 +121,7 @@ export default {
this.handleCheckChange(); this.handleCheckChange();
} }
this.handleChange(this.value); this.handleChange(this.value);
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
}, },
handleCheckChange() { handleCheckChange() {
const emitEvent = { const emitEvent = {

View file

@ -1,6 +1,7 @@
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from "@vue/test-utils";
import listCard from "./list-card"; import listCard from "./list-card";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { GaActions } from "@/constants/analytics";
describe("list-card.vue", () => { describe("list-card.vue", () => {
it("Should return input type checkbox if isMultiSelect is true", async () => { it("Should return input type checkbox if isMultiSelect is true", async () => {
@ -292,8 +293,16 @@ describe("list-card.vue", () => {
}); });
it("Should run handleChange if triggerButton is triggered", async () => { it("Should run handleChange if triggerButton is triggered", async () => {
// Act // Act
const wrapper = shallowMount(listCard, { const wrapper = shallowMount(listCard, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
selectingInitiatesLoad: false, selectingInitiatesLoad: false,
}, },
@ -312,6 +321,13 @@ describe("list-card.vue", () => {
it("Should run handleCheckChange and displayLoader if triggerButton is triggered and seletingInitiatesLoad is true", async () => { it("Should run handleCheckChange and displayLoader if triggerButton is triggered and seletingInitiatesLoad is true", async () => {
// Act // Act
const wrapper = shallowMount(listCard, { const wrapper = shallowMount(listCard, {
global: {
mocks: {
'$route': { query: { fmgPage: 'page-name' } },
GaActions: GaActions,
pushEventToGA: jest.fn(),
}
},
propsData: { propsData: {
selectingInitiatesLoad: true, selectingInitiatesLoad: true,
}, },

View file

@ -61,6 +61,7 @@
<script> <script>
import { useField } from "vee-validate"; import { useField } from "vee-validate";
import { queryStrings } from "@/constants/query-strings";
export default { export default {
name: "listCard", name: "listCard",
@ -98,6 +99,10 @@ export default {
: this.selectedValues[0]; : this.selectedValues[0];
} }
}, },
unmounted() { // needed to clear this button's selectedValues if it is removed
this.checkValue = false;
this.handleCheckChange();
},
computed: { computed: {
getLabelClasses() { getLabelClasses() {
if (this.isWide) { if (this.isWide) {
@ -133,6 +138,7 @@ export default {
this.handleCheckChange(); this.handleCheckChange();
} }
this.handleChange(this.value); this.handleChange(this.value);
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
}, },
handleCheckChange() { handleCheckChange() {
const emitEvent = { const emitEvent = {