diff --git a/.eslintrc.js b/.eslintrc.js index cba6075a..4f01a690 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,6 +23,7 @@ module.exports = { 'comma-dangle': ['error', 'never'], indent: ['error', 4], 'max-len': ['error', { code: 140 }], + 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], 'vue/html-indent': 'off', 'vue/html-closing-bracket-newline': ['error', { singleline: 'never', diff --git a/src/constants/application-config.js b/src/constants/application-config.js index ca427254..9dbc7ac3 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -1,5 +1,5 @@ const applicationConfig = { - CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" + CURRENT_ENVIRONMENT: process.env.VUE_APP_CURRENT_ENVIRONMENT, // "Localhost", "Dev", "QA", and "Prod" CONSUMER_CF_DISTRO: process.env.VUE_APP_CONSUMER_CF_DISTRO, ANALYTICS_SESSION_TIMEOUT_MINUTES: 30, SAVED_SESSION_TIMEOUT_DAYS: 45, @@ -8,7 +8,7 @@ const applicationConfig = { SITE_ENTRY_TRIGGER_VALUE: 'SelfService', APPLICATION_ABBREVIATION: 'iss', PAGE_QUERYSTRING: 'issPage', - CLIENTTAG_QUERYSTRING: 'CientTag', + CLIENTTAG_QUERYSTRING: 'ClientTag', GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY, ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io', CASH_PARENT_ACCOUNT_NUMBER: 167132 diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue index d2405cf4..13c7d235 100644 --- a/src/digital-components/button-question/button-question.vue +++ b/src/digital-components/button-question/button-question.vue @@ -81,7 +81,7 @@ import listButtonHorizontal from '@/ux-components/list-button-horizontal/list-bu import listCard from '@/ux-components/list-card/list-card'; import radio from '@/ux-components/radio/radio'; import { ErrorMessage } from 'vee-validate'; -import providerPrefRadio from '@/layouts/provider-preference/provider-pref-radio/provider-pref-radio.vue'; +import providerPrefRadio from '@/layouts/provider-preference/provider-pref-radio/provider-pref-radio'; export default { name: 'button-question', diff --git a/src/digital-components/dropdown-question/dropdown-question.spec.js b/src/digital-components/dropdown-question/dropdown-question.spec.js index bc38a04d..f254f7a3 100644 --- a/src/digital-components/dropdown-question/dropdown-question.spec.js +++ b/src/digital-components/dropdown-question/dropdown-question.spec.js @@ -7,7 +7,7 @@ const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => questionText) } -} +}; // TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''" // It is not being used. diff --git a/src/digital-components/dropdown-question/dropdown-question.vue b/src/digital-components/dropdown-question/dropdown-question.vue index 9e02c2c5..002edcae 100644 --- a/src/digital-components/dropdown-question/dropdown-question.vue +++ b/src/digital-components/dropdown-question/dropdown-question.vue @@ -58,6 +58,7 @@ export default { hasError: Boolean, placeHolderText: String }, + emits: ['update:modelValue'], setup(props) { const propsClone = { ...props }; const { modelValue } = propsClone; diff --git a/src/digital-components/question-chain/question-chain.vue b/src/digital-components/question-chain/question-chain.vue index 6af79506..cad2ca97 100644 --- a/src/digital-components/question-chain/question-chain.vue +++ b/src/digital-components/question-chain/question-chain.vue @@ -50,7 +50,7 @@ export default { // NOTE: needs to have async/await here; tested and won't work without it await useValidateForm(); - this.questionData.map((q, i) => { + this.questionData.map((q) => { const question = { questionText: q.questionText, questionSequence: q.questionSequence, @@ -78,6 +78,7 @@ export default { if (!q.suppressThisQuestion) { this.questions.push(question); } + return q; }); if (!this.modelValue?.length > 0 && this.questions.length > 0) { diff --git a/src/digital-components/text-block/text-block.spec.js b/src/digital-components/text-block/text-block.spec.js index 2404460e..5aad4b83 100644 --- a/src/digital-components/text-block/text-block.spec.js +++ b/src/digital-components/text-block/text-block.spec.js @@ -1,44 +1,9 @@ import { shallowMount } from '@vue/test-utils'; import TextBlock from './text-block'; -describe('modal.vue', () => { - it("Should display 'Text' when 'Text' is defined in the CMS", async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['Text'])); - }); - - it('Should contain the typeStyle class as defined by the prop', async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['typeStyle'])); - }); - it('Should contain the justifyText class as defined by the prop', async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['justifyText'])); - }); - it('Should contain the fontWeight class as defined by the prop', async () => { - // Act - const wrapper = shallowMount(TextBlock, { - mixins: [mockMixin], - propsData: mockProps, - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockProps['fontWeight'])); - }); -}); - -/////////////// -// Constants // -/////////////// +const mockCmsContent = { + Text: 'Sample text here.' +}; const mockMixin = { methods: { @@ -52,6 +17,37 @@ const mockProps = { justifyText: 'mockJustifyText' }; -const mockCmsContent = { - Text: 'Sample text here.' -}; +describe('modal.vue', () => { + it("Should display 'Text' when 'Text' is defined in the CMS", async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin] + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.Text)); + }); + + it('Should contain the typeStyle class as defined by the prop', async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps.typeStyle)); + }); + it('Should contain the justifyText class as defined by the prop', async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps.justifyText)); + }); + it('Should contain the fontWeight class as defined by the prop', async () => { + // Act + const wrapper = shallowMount(TextBlock, { + mixins: [mockMixin], + propsData: mockProps + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockProps.fontWeight)); + }); +}); diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 03538e54..a2e8c80c 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -1,5 +1,7 @@ @@ -107,12 +116,12 @@ export default { let initialValue; switch (typeof modelValue) { - case 'number': - initialValue = modelValue; - break; - default: - initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; - break; + case 'number': + initialValue = modelValue; + break; + default: + initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; + break; } const fieldOptions = { @@ -122,11 +131,9 @@ export default { }; // eslint-disable-next-line no-shadow - const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( - props.inputId, + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(props.inputId, props.validationRules, - fieldOptions - ); + fieldOptions); return { errorMessage, diff --git a/src/helpers/button-question-focus-helper.js b/src/helpers/button-question-focus-helper.js index 9388a505..855fcf5b 100644 --- a/src/helpers/button-question-focus-helper.js +++ b/src/helpers/button-question-focus-helper.js @@ -8,6 +8,12 @@ let lastFocusedInputGroupName = ''; let onButtonQuestionLostFocusCallback = null; +const invokeButtonQuestionLostFocusCallback = () => { + if (onButtonQuestionLostFocusCallback) { + onButtonQuestionLostFocusCallback(); + } +}; + const handleAnyComponentFocus = (e) => { const targetType = e.target.type; if (targetType !== 'radio' && targetType !== 'checkbox') { @@ -28,10 +34,4 @@ const handleInputComponentBlur = (e) => { } }; -const invokeButtonQuestionLostFocusCallback = () => { - if (onButtonQuestionLostFocusCallback) { - onButtonQuestionLostFocusCallback(); - } -}; - export { handleAnyComponentFocus, handleButtonComponentFocus, handleInputComponentBlur }; diff --git a/src/helpers/clientauth-helper.js b/src/helpers/clientauth-helper.js index 5e061f5c..27aec8dc 100644 --- a/src/helpers/clientauth-helper.js +++ b/src/helpers/clientauth-helper.js @@ -1,13 +1,12 @@ import { useMainStore } from '@/store'; export function validateISSClientTag(clientTag) { - const store = useMainStore() + const store = useMainStore(); return store.validateClientTag(clientTag) .then((response) => // Success - response - , + response, (error) => // Error null); diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 24a64ca8..02e6863e 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -3,34 +3,31 @@ import { useMainStore } from '@/store'; export function fetchCmsContentForPage(issPage) { const store = useMainStore(); - const clientName = store.issConfig.clientName; - const accountNumber = store.issConfig.accountNumber; + const { clientName } = store.issConfig; + const { accountNumber } = store.issConfig; const clientOverride = (clientName.length > 0 && accountNumber > 0); return store.getPageData(issPage) - .then( - // Get the base/default page first. - (baseResponse) => { - if (!clientOverride) { - // Return the base page if there are no client override. - return processPageData(baseResponse, null); - } else { - // Else get the client override page. - const pageName = issPage + '_' + clientName.toLowerCase().replace(/ /g, ''); + // Get the base/default page first. + .then((baseResponse) => { + if (!clientOverride) { + // Return the base page if there are no client override. + return processPageData(baseResponse, null); + } + // Else get the client override page. + const pageName = `${issPage}_${clientName.toLowerCase().replace(/ /g, '')}`; - return store.getPageData(pageName) - .then((clientResponse) => { - // Process the client override if it exists. - return processPageData(baseResponse, clientResponse); - }, - (error) => { - console.error(error); - // Process the just the base if no client override exists. - return processPageData(baseResponse, null); - }); - } - }); -}; + return store.getPageData(pageName) + .then((clientResponse) => + // Process the client override if it exists. + processPageData(baseResponse, clientResponse), + (error) => { + console.error(error); + // Process the just the base if no client override exists. + return processPageData(baseResponse, null); + }); + }); +} // Support method for processing the page data from the CMS call. // widgets = current widget collection used by page. @@ -41,8 +38,8 @@ function processPageData(baseResponse, clientResponse) { let widgets = []; if (!baseResponse?.data?.Result) { - console.error('No result data found'); // Something has gone terribly wrong. - return {} + console.error('No result data found'); // Something has gone terribly wrong. + return {}; } if (!clientResponse?.data?.Result) { widgets = baseResponse.data.Result; @@ -111,7 +108,7 @@ function findAndReplaceGlobalStateValues(widgetModel, widgetName) { }; Object.keys(widgetModel).forEach((key) => { - let modelWithReplacements = processWidgetItemForReplacement(widgetModel, + const modelWithReplacements = processWidgetItemForReplacement(widgetModel, key); objWithReplacements.Model[key] = modelWithReplacements; @@ -144,8 +141,8 @@ function processWidgetItemForReplacement(widgetModel, key) { } // If we have an object. array, etc - if (typeof widgetModel[key] === 'object' && - Object.keys(widgetModel[key]).length) { + if (typeof widgetModel[key] === 'object' + && Object.keys(widgetModel[key]).length) { Object.keys(widgetModel[key]).forEach((item) => { processWidgetItemForReplacement(widgetModel[key], item); }); @@ -158,14 +155,14 @@ function processWidgetItemForReplacement(widgetModel, key) { } function mapStringToModal(str) { - const startIndex = str.indexOf('{' + dynamicStrings.MODAL_LINK); + const startIndex = str.indexOf(`{${dynamicStrings.MODAL_LINK}`); let linkToReplace = str.substring(startIndex, str.length); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); const params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length - 1); const splitParams = params.split(','); - const bodyText = '' + splitParams[1] + ''; + const bodyText = `${splitParams[1]}`; let returnVal = str.replace(linkToReplace, bodyText); @@ -176,14 +173,14 @@ function mapStringToModal(str) { } function mapStringToLink(str) { - const startIndex = str.indexOf('{' + dynamicStrings.EXTERNAL_LINK); + const startIndex = str.indexOf(`{${dynamicStrings.EXTERNAL_LINK}`); let linkToReplace = str.substring(startIndex, str.length); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); const params = linkToReplace.substring((dynamicStrings.EXTERNAL_LINK).length + 2, linkToReplace.length - 1); const splitParams = params.split(','); - const bodyText = '' + splitParams[1] + ''; + const bodyText = `${splitParams[1]}`; let returnVal = str.replace(linkToReplace, bodyText); @@ -196,21 +193,19 @@ function mapStringToLink(str) { // Function to convert a string, into a matching global state item. function mapStringToState(str) { // Pull all matches out of the string. - const regexExp = new RegExp('{([^{}]*?):([^{}]*?)}', 'g'); + const regexExp = /{([^{}]*?):([^{}]*?)}/g; const regexMatches = [...str.matchAll(regexExp)]; - const globalStateMatches = regexMatches.filter(match => { - return match[1] === dynamicStrings.GLOBAL_STATE; - }); + const globalStateMatches = regexMatches.filter((match) => match[1] === dynamicStrings.GLOBAL_STATE); // Our final string value that will be built from the matches. - let stringBuilder = ''; + const stringBuilder = ''; for (const match of globalStateMatches) { // Reset store state for each match. - const valueFromStore = getStoreValueFromString(match[2]); + const valueFromStore = getStoreValueFromString(match[2]); if (!valueFromStore) { console.warning('Unable to resolve global state data.'); - return '' // if we can't map our string to state data, return an empty string. + return ''; // if we can't map our string to state data, return an empty string. } const stringWithReplacement = str.replace(match[0], valueFromStore); @@ -231,7 +226,7 @@ function getStoreValueFromString(str) { let storeOrStateObject = useMainStore(); for (const s of str.split('.')) { - if (s === 'getters') continue; //For backward compatibility + if (s === 'getters') continue; // For backward compatibility if (storeOrStateObject[s] != undefined) { storeOrStateObject = storeOrStateObject[s]; } else { @@ -241,9 +236,9 @@ function getStoreValueFromString(str) { return storeOrStateObject ?? ''; } -/////////////////////////////////// +/// //////////////////////////////// // If Statement Processing Logic // -/////////////////////////////////// +/// //////////////////////////////// /** * Recursive function - replaces all instances of if statements from the CMS that utilize the specified ifConditionKeyword @@ -253,23 +248,22 @@ function getStoreValueFromString(str) { * @returns The processed string */ export function processIfStatements(str, ifConditionKeyword, replacePlaceholderCallback) { - const containsRelevantIfStatement = new RegExp('{if:' + ifConditionKeyword + ':.+?}', 'g').test(str); + const containsRelevantIfStatement = new RegExp(`{if:${ifConditionKeyword}:.+?}`, 'g').test(str); const hasEmbeddedCrLf = /\r?\n|\r/g.test(str); if (!containsRelevantIfStatement) { return str; - } else { - const ifStatementRegexExpression = getIfStatementRegexExpression(); - const ifStatementRegexMatches = [...str.matchAll(ifStatementRegexExpression)]; - const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(ifStatementRegexMatches, - ifConditionKeyword); - executeIfStatementAndSetProcessedStrings(completeIfStatementArray, - replacePlaceholderCallback); - const reconstructedPostProcessedString = joinProcessedRegexArray(ifStatementRegexMatches); - return processIfStatements(reconstructedPostProcessedString, - ifConditionKeyword, - replacePlaceholderCallback); } + const ifStatementRegexExpression = getIfStatementRegexExpression(); + const ifStatementRegexMatches = [...str.matchAll(ifStatementRegexExpression)]; + const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(ifStatementRegexMatches, + ifConditionKeyword); + executeIfStatementAndSetProcessedStrings(completeIfStatementArray, + replacePlaceholderCallback); + const reconstructedPostProcessedString = joinProcessedRegexArray(ifStatementRegexMatches); + return processIfStatements(reconstructedPostProcessedString, + ifConditionKeyword, + replacePlaceholderCallback); } function getAndFlagFirstNonNestedIfStatementWithKeyword(matches, ifConditionKeyword) { @@ -342,20 +336,18 @@ function executeIfStatementAndSetProcessedStrings(ifStatementArray, replacePlace function setProcessedStringOnEntry(entry, isInsideDesiredBlock) { if (!isInsideDesiredBlock) { entry.groups.processedString = ''; + } else if (entry.groups.isIfStatement) { + entry.groups.processedString = entry.isFlaggedForProcessing + ? entry.groups.ifTrailingString + : entry[0]; + } else if (entry.groups.isElseStatement) { + entry.groups.processedString = entry.isFlaggedForProcessing + ? entry.groups.elseTrailingString + : entry[0]; } else { - if (entry.groups.isIfStatement) { - entry.groups.processedString = entry.isFlaggedForProcessing - ? entry.groups.ifTrailingString - : entry[0]; - } else if (entry.groups.isElseStatement) { - entry.groups.processedString = entry.isFlaggedForProcessing - ? entry.groups.elseTrailingString - : entry[0]; - } else { - entry.groups.processedString = entry.isFlaggedForProcessing - ? entry.groups.endTrailingString - : entry[0]; - } + entry.groups.processedString = entry.isFlaggedForProcessing + ? entry.groups.endTrailingString + : entry[0]; } } @@ -364,43 +356,43 @@ function getIfStatementRegexExpression() { // {if:...} or {else} or {end} const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})'; // NOTE: ? syntax stores the captured match like so: match.groups.variableName - const matchStartOfString = - '(?^.+?)' + // Match and Capture all characters (lazy), cannot be empty - '(?=(?:{if))'; // Looks ahead but does not capture {if - const matchIfOperator = - '(?{if:)' + // Match & Capture {if: - '(?.*?):' + // Match all chars up to and including next ':' - Capture all chars up to ':' - '(?.*?)}' + // Match all chars up to and including next '}' - Capture all chars up to '}' - '(?.*?)' + // Match and Capture all characters (lazy), can be empty - '(?=' + - anyLogicOperatorNonCapture + - ')'; // Looks ahead but does not capture the next logic operator - const matchElseOperator = - '(?{else})' + // Match & Capture {else} - '(?.*?)' + // Match & Capture all characters (lazy), can be empty - '(?=' + - anyLogicOperatorNonCapture + - ')'; // Looks ahead but does not capture the next logic operator - const matchEndOperator = - '(?{end})' + // Match & Capture {end} - '(?.*?)' + // Match & Capture all chracters (lazy), can be empty - '(?=' + - anyLogicOperatorNonCapture + - '|$)'; // Looks ahead but does not capture the next logic operator + const matchStartOfString + = '(?^.+?)' // Match and Capture all characters (lazy), cannot be empty + + '(?=(?:{if))'; // Looks ahead but does not capture {if + const matchIfOperator + = '(?{if:)' // Match & Capture {if: + + '(?.*?):' // Match all chars up to and including next ':' - Capture all chars up to ':' + + '(?.*?)}' // Match all chars up to and including next '}' - Capture all chars up to '}' + + '(?.*?)' // Match and Capture all characters (lazy), can be empty + + `(?=${ + anyLogicOperatorNonCapture + })`; // Looks ahead but does not capture the next logic operator + const matchElseOperator + = '(?{else})' // Match & Capture {else} + + '(?.*?)' // Match & Capture all characters (lazy), can be empty + + `(?=${ + anyLogicOperatorNonCapture + })`; // Looks ahead but does not capture the next logic operator + const matchEndOperator + = '(?{end})' // Match & Capture {end} + + '(?.*?)' // Match & Capture all characters (lazy), can be empty + + `(?=${ + anyLogicOperatorNonCapture + }|$)`; // Looks ahead but does not capture the next logic operator // Combine all matching patterns, separated by 'or' pipes - return new RegExp(matchStartOfString + - '|' + - matchIfOperator + - '|' + - matchElseOperator + - '|' + - matchEndOperator, + return new RegExp(`${matchStartOfString + }|${ + matchIfOperator + }|${ + matchElseOperator + }|${ + matchEndOperator}`, 'g'); } -////////////////////////////////////////// +/// /////////////////////////////////////// // End of If Statement Processing Logic // -////////////////////////////////////////// +/// /////////////////////////////////////// export function doesCopyContainTextLink(copy) { return copy.includes(dynamicStrings.TEXT_LINK); @@ -409,12 +401,12 @@ export function doesCopyContainTextLink(copy) { export function setupModalLinks(context) { context.$nextTick(() => { const elements = document.getElementsByClassName('modal-text'); - for (let element of elements){ + for (const element of elements) { const target = element.getAttribute('modalTarget'); if (target) { - element.addEventListener('click', () => context.$refs[target].openModal() ); + element.addEventListener('click', () => context.$refs[target].openModal()); } - }; + } }); } diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index 489e7753..e4abd6a7 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -106,11 +106,9 @@ export function updateSessionIdCookie() { createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 }); } -export function setCookieProperties( - properties, - { useDefaultISSCookieAttributes = true, maxAge, isSecure } -) { - if (typeof properties == 'object') { +export function setCookieProperties(properties, + { useDefaultISSCookieAttributes = true, maxAge, isSecure }) { + if (typeof properties === 'object') { Object.keys(properties).forEach((key) => { createOrUpdateCookie(key, properties[key], { useDefaultISSCookieAttributes, @@ -132,8 +130,8 @@ export function setCookieProperties( Takes an object with properties to set. Will overwrite existing properties. */ function setISSCookieProperties(properties) { - if (typeof properties == 'object') { - let cookie = getISSCookie(); + if (typeof properties === 'object') { + const cookie = getISSCookie(); if (cookie !== null) { Object.keys(properties).forEach((key) => { @@ -150,11 +148,8 @@ function setISSCookieProperties(properties) { Used to create a cookie. `useDefaultISSCookieAttributes` will set the path and domain to our defaults */ -function createOrUpdateCookie( - key, - value = '', - { useDefaultISSCookieAttributes = true, maxAge, isSecure = true } -) { +function createOrUpdateCookie(key, value = '', + { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }) { let cookieToAdd = `${key}=${value}; `; if (useDefaultISSCookieAttributes) { @@ -163,7 +158,7 @@ function createOrUpdateCookie( if (isSecure && !isLocalhost()) { cookieToAdd += 'secure; '; } - if (!isNaN(maxAge)) { + if (!Number.isNaN(maxAge)) { cookieToAdd += `max-age=${maxAge};`; } @@ -174,7 +169,7 @@ function createOrUpdateCookie( Gets current domain without the subdomain for cookie. */ function getDomainWithoutSubdomain() { - let url = location.hostname; + const url = location.hostname; if (isLocalhost()) { return 'localhost'; } @@ -191,8 +186,8 @@ function getDomainWithoutSubdomain() { Gets cookie value by name, returns empty string if not found. */ function getCookieValueByName(name) { - const value = '; ' + document.cookie; - const parts = value.split('; ' + name + '='); + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); if (parts.length === 2) { return parts.pop().split(';').shift(); diff --git a/src/helpers/data-generation.js b/src/helpers/data-generation.js index 2553246f..c2d2323a 100644 --- a/src/helpers/data-generation.js +++ b/src/helpers/data-generation.js @@ -1,16 +1,5 @@ import { randomUUID } from 'crypto'; -export function getRandomString(minLength = 1, maxLength = 100) { - const length = getRandomInt(minLength, maxLength + 1); - let result = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - export function getRandomInt(min = 0, max = 1000) { min = Math.ceil(min); max = Math.floor(max); @@ -26,3 +15,14 @@ export function getRandomBoolean() { const index = getRandomInt(0, 2); return bools[index]; } + +export function getRandomString(minLength = 1, maxLength = 100) { + const length = getRandomInt(minLength, maxLength + 1); + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} diff --git a/src/helpers/event-bus/event-bus.js b/src/helpers/event-bus/event-bus.js index f374e019..f7b3b6bf 100644 --- a/src/helpers/event-bus/event-bus.js +++ b/src/helpers/event-bus/event-bus.js @@ -4,9 +4,9 @@ export default { // Adds event to the bus given its category, subcategory, and eventValue; addEventToBus(category, subCategory, eventValue) { useMainStore().addEventToBus({ - category: category, - subCategory: subCategory, - eventValue: eventValue, + category, + subCategory, + eventValue }); }, @@ -16,8 +16,8 @@ export default { if (event) { useMainStore().removeEventFromBus({ - category: category, - subCategory: subCategory, + category, + subCategory }); } diff --git a/src/helpers/event-bus/event-bus.spec.js b/src/helpers/event-bus/event-bus.spec.js index 53dbfaee..e6aa9557 100644 --- a/src/helpers/event-bus/event-bus.spec.js +++ b/src/helpers/event-bus/event-bus.spec.js @@ -11,7 +11,7 @@ useMainStore().removeEventFromBus = jest.fn(); useMainStore().eventBusItem = jest.fn(); describe('event-bus.js', () => { - let event = { + const event = { isDismissible: true, messageCopy: 'You can get a quote by starting on this page.', messageHeadline: "We're sorry, something went wrong.", @@ -20,15 +20,13 @@ describe('event-bus.js', () => { afterEach(() => { jest.resetAllMocks(); - }) + }); it('removes items when readandpop is called', () => { useMainStore().eventBusItem.mockReturnValueOnce(event); - const eventValue = eventBus.readAndPopEventFromBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ); + const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND); expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().removeEventFromBus).toBeCalledTimes(1); @@ -37,10 +35,8 @@ describe('event-bus.js', () => { it("doesn't try to remove items when readandpop is called and item doesn't exist", () => { useMainStore().eventBusItem.mockReturnValueOnce(undefined); - const eventValue = eventBus.readAndPopEventFromBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ); + const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND); expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().removeEventFromBus).toBeCalledTimes(0); @@ -49,21 +45,17 @@ describe('event-bus.js', () => { it('returns event from bus', () => { useMainStore().eventBusItem.mockReturnValueOnce(event); - const eventValue = eventBus.readEventFromBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND - ); + const eventValue = eventBus.readEventFromBus(globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND); expect(eventValue).toBe(event); }); it('Reads event from bus, should have event value.', () => { // Arrange / Act - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, + eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND, - event - ); + event); expect(useMainStore().addEventToBus).toHaveBeenCalled(); }); diff --git a/src/helpers/layout-helper.js b/src/helpers/layout-helper.js index a21c7f43..d13bbc2b 100644 --- a/src/helpers/layout-helper.js +++ b/src/helpers/layout-helper.js @@ -2,11 +2,7 @@ export function settleAllPromises(promiseResultMap) { // Pull our keys out of the promise 'table' const promiseNames = Object.entries(promiseResultMap); - return Promise.allSettled( - promiseNames.map((e) => - e[1]).map((n) => - n.promise) - ).then((results) => { + return Promise.allSettled(promiseNames.map((e) => e[1]).map((n) => n.promise)).then((results) => { const resultMap = {}; // Build a map of the results diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index e784e4eb..362f3d22 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -1,20 +1,16 @@ import { useMainStore } from '@/store'; export async function getServiceabilityDetails(serviceZipCode, lineItems) { - const serviceabilityDetails = await useMainStore().getServiceabilityDetails( - { - serviceZipCode: serviceZipCode, - lineItems: lineItems, - }, - false - ); + const serviceabilityDetails = await useMainStore().getServiceabilityDetails({ + serviceZipCode, + lineItems + }, + false); return Promise.resolve(serviceabilityDetails); } export async function getZipCodeData(zipCode) { - const serviceZipValidationResponse = await useMainStore().validateZip( - { zip: zipCode } - ); + const serviceZipValidationResponse = await useMainStore().validateZip({ zip: zipCode }); return { containsMilitaryBase: serviceZipValidationResponse.data.containsMilitaryBase, diff --git a/src/helpers/session-helper.js b/src/helpers/session-helper.js index 4216f75c..c6b57dff 100644 --- a/src/helpers/session-helper.js +++ b/src/helpers/session-helper.js @@ -10,8 +10,7 @@ export function isAnalyticsSessionStillActive() { const lastTouchedValue = getISSCookie().LastTouched; const timeoutAmount = applicationConfig.ANALYTICS_SESSION_TIMEOUT_MINUTES; - const isMoreThanHalfHourAgo = - (new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount; + const isMoreThanHalfHourAgo = (new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount; if (isMoreThanHalfHourAgo) { return false; @@ -19,6 +18,7 @@ export function isAnalyticsSessionStillActive() { return true; } + return false; } /* @@ -35,6 +35,7 @@ export function isSavedSessionStillActive() { return !isSavedSessionTimedOut; } + return false; } /* diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 52d87fb7..cbeb6cda 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -9,15 +9,7 @@ import { getCookieDomainValue, setCookieProperties } from '@/helpers/cookie-helper'; -import { - analyticsPageEvents, - GaCategories, - GaActions, - GaLabels, - GaEvents, - ValueToLogTypes -} from '@/constants/analytics'; -import { routerParams } from '@/router/router-constants/router-params'; +import { GaActions } from '@/constants/analytics'; import { queryStrings } from '@/constants/query-strings'; import { useMainStore } from '@/store'; import { mapStores } from 'pinia'; @@ -53,7 +45,7 @@ export function getMountOptions(mockData) { mocks.prependActionToMethod = jest.fn(); const global = { - mocks: mocks, + mocks, mixins: [mockMixin], plugins: [pinia], stubs: { @@ -78,10 +70,10 @@ export const cookies = { export function setupCookies({ ISSCookieValue = '', includeHeritageCookie = true }) { Object.keys(cookies).forEach((key) => { - const cookieValue = - key == cookieNames.ISS_SESSION_INFO ? ISSCookieValue : cookies[key]; - if (includeHeritageCookie || key != cookieNames.ISS_SESSION_INFO) + const cookieValue = key === cookieNames.ISS_SESSION_INFO ? ISSCookieValue : cookies[key]; + if (includeHeritageCookie || key !== cookieNames.ISS_SESSION_INFO) { setCookieProperties({ [key]: cookieValue }, { isSecure: false }); + } }); } diff --git a/src/helpers/validation-rules.js b/src/helpers/validation-rules.js index b708eb2d..0ef03cbe 100644 --- a/src/helpers/validation-rules.js +++ b/src/helpers/validation-rules.js @@ -20,5 +20,5 @@ export function regex(expression, errorMessage) { } return true; - } + }; } diff --git a/src/iss-components/address-questions/address-questions.spec.js b/src/iss-components/address-questions/address-questions.spec.js index a0c93388..27274bbf 100644 --- a/src/iss-components/address-questions/address-questions.spec.js +++ b/src/iss-components/address-questions/address-questions.spec.js @@ -161,18 +161,19 @@ describe('address-questions.vue', () => { autocompleteElement.addEventListener = jest .fn() .mockImplementation((eventName, callbackFunction) => { - if (eventName == 'change') { + if (eventName === 'change') { changeEventCallbackFunction = callbackFunction; } }); const { wrapper } = setupMocks({ querySelectorFunction(query) { - if (query == '.pac-container .pac-item') { + if (query === '.pac-container .pac-item') { const element = document.createElement('div'); element.textContent = '123 Test Street'; return element; } + return null; }, geocoderResult: { address_components: [ @@ -276,7 +277,7 @@ describe('address-questions.vue', () => { autocompleteElement.addEventListener = jest .fn() .mockImplementation((eventName, callbackFunction) => { - if (eventName == 'change') { + if (eventName === 'change') { changeEventCallbackFunction = callbackFunction; } }); @@ -306,18 +307,19 @@ describe('address-questions.vue', () => { autocompleteElement.addEventListener = jest .fn() .mockImplementation((eventName, callbackFunction) => { - if (eventName == 'change') { + if (eventName === 'change') { changeEventCallbackFunction = callbackFunction; } }); const { wrapper } = setupMocks({ querySelectorFunction(query) { - if (query == '.pac-container .pac-item') { + if (query === '.pac-container .pac-item') { const element = document.createElement('div'); element.textContent = '123 Test Street'; return element; } + return null; } }); @@ -474,7 +476,6 @@ function setupMocks({ const resultingMountOptions = getMountOptions({ ...mountOptions, router: { - navigate: jest.fn(), navigate: jest.fn() }, loadScript: jest.fn().mockResolvedValue() @@ -522,7 +523,7 @@ function setupMocks({ : mount(addressQuestions, resultingMountOptions); document.querySelector = jest.fn().mockImplementation((query) => { let result = null; - if (query == '.pac-container') result = document.createElement('div'); + if (query === '.pac-container') result = document.createElement('div'); else if (querySelectorFunction) { result = querySelectorFunction(query); } diff --git a/src/iss-components/button-question-modal/button-question-modal.spec.js b/src/iss-components/button-question-modal/button-question-modal.spec.js index 0cae2dd1..f5633a0e 100644 --- a/src/iss-components/button-question-modal/button-question-modal.spec.js +++ b/src/iss-components/button-question-modal/button-question-modal.spec.js @@ -1,40 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import ButtonQuestionModal from './button-question-modal'; -describe('button-question-modal.vue', () => { - it('Should display header text when QuestionText is defined in the CMS', async () => { - // Act - const wrapper = shallowMount(ButtonQuestionModal, { - mixins: [mockMixin], - props: { - cmsWidgetName: 'test' - }, - attachTo: document.body - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['QuestionText'])); - }); - - it('Should display subheader text when ButtonText is defined in the CMS', async () => { - // Act - const wrapper = shallowMount(ButtonQuestionModal, { - mixins: [mockMixin], - props: { - cmsWidgetName: 'test' - }, - attachTo: document.body - }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['ButtonText'])); - }); -}); - -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }) - } -}; - const mockCmsContent = { QuestionText: 'What caused damage.', ButtonText: 'Select an option.', @@ -49,3 +15,35 @@ const mockCmsContent = { } ] }; + +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => mockCmsContent[cmsFieldName]) + } +}; + +describe('button-question-modal.vue', () => { + it('Should display header text when QuestionText is defined in the CMS', async () => { + // Act + const wrapper = shallowMount(ButtonQuestionModal, { + mixins: [mockMixin], + props: { + cmsWidgetName: 'test' + }, + attachTo: document.body + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.QuestionText)); + }); + + it('Should display subheader text when ButtonText is defined in the CMS', async () => { + // Act + const wrapper = shallowMount(ButtonQuestionModal, { + mixins: [mockMixin], + props: { + cmsWidgetName: 'test' + }, + attachTo: document.body + }); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.ButtonText)); + }); +}); diff --git a/src/iss-components/content-group-modal/content-group-modal.spec.js b/src/iss-components/content-group-modal/content-group-modal.spec.js index d994c073..74f09ed4 100644 --- a/src/iss-components/content-group-modal/content-group-modal.spec.js +++ b/src/iss-components/content-group-modal/content-group-modal.spec.js @@ -1,9 +1,23 @@ import { mount } from '@vue/test-utils'; -import contentGroupModal from './content-group-modal'; import crypto from 'crypto'; +import contentGroupModal from './content-group-modal'; global.crypto = crypto; +const mockCmsContent = { + HeaderText: 'Sample header text here.', + SubheaderText: 'Sample subheader text here.', + Image: 'https://www.sampleImage.sample', + BodyText: 'Sample body text here.', + FooterText: 'Sample footer text here.' +}; + +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => mockCmsContent[cmsFieldName]) + } +}; + describe('content-group-modal.vue', () => { it('Should display header text when HeaderText is defined in the CMS', async () => { const wrapper = mount(contentGroupModal, { @@ -13,7 +27,7 @@ describe('content-group-modal.vue', () => { }, attachTo: document.body }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['HeaderText'])); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.HeaderText)); }); it('Should display subheader text when SubheaderText is defined in the CMS', async () => { @@ -24,7 +38,7 @@ describe('content-group-modal.vue', () => { }, attachTo: document.body }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['SubheaderText'])); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.SubheaderText)); }); it('Should insert image url when Image is defined in the CMS', async () => { @@ -35,7 +49,7 @@ describe('content-group-modal.vue', () => { }, attachTo: document.body }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['Image'])); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.Image)); }); it('Should display body text when BodyText is defined in the CMS', async () => { @@ -46,22 +60,6 @@ describe('content-group-modal.vue', () => { }, attachTo: document.body }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['BodyText'])); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.BodyText)); }); }); - -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }) - } -}; - -const mockCmsContent = { - HeaderText: 'Sample header text here.', - SubheaderText: 'Sample subheader text here.', - Image: 'https://www.sampleImage.sample', - BodyText: 'Sample body text here.', - FooterText: 'Sample footer text here.' -}; diff --git a/src/iss-components/loading-modal/loading-modal.spec.js b/src/iss-components/loading-modal/loading-modal.spec.js index 849ba0c9..67767bc8 100644 --- a/src/iss-components/loading-modal/loading-modal.spec.js +++ b/src/iss-components/loading-modal/loading-modal.spec.js @@ -5,6 +5,14 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js'; jest.mock('@/assets/img/loader.gif', () => 'loader.gif'); jest.mock('@/assets/img/windshield.png', () => 'windshield.png'); +function setupMocks() { + const mountOptions = getMountOptions({ + }); + + const wrapper = shallowMount(loadingModal, mountOptions); + return { wrapper }; +} + describe('loadingModal', () => { test('showModal sets modal visible', async () => { // Arrange @@ -19,11 +27,3 @@ describe('loadingModal', () => { wrapper.unmount(); }); }); - -function setupMocks() { - const mountOptions = getMountOptions({ - }); - - const wrapper = shallowMount(loadingModal, mountOptions); - return { wrapper }; -} diff --git a/src/iss-components/nav-button/nav-button.spec.js b/src/iss-components/nav-button/nav-button.spec.js index 9ef1f568..66080fb3 100644 --- a/src/iss-components/nav-button/nav-button.spec.js +++ b/src/iss-components/nav-button/nav-button.spec.js @@ -1,6 +1,5 @@ -import navButton from './nav-button' - import { shallowMount } from '@vue/test-utils'; +import navButton from './nav-button'; describe('NavButton', () => { it('should display input when type is button', () => { diff --git a/src/iss-components/questions-page-layout/questions-page-layout.spec.js b/src/iss-components/questions-page-layout/questions-page-layout.spec.js index 1615fae1..3ba9d02c 100644 --- a/src/iss-components/questions-page-layout/questions-page-layout.spec.js +++ b/src/iss-components/questions-page-layout/questions-page-layout.spec.js @@ -4,8 +4,8 @@ import questionsPageLayout from '@/iss-components/questions-page-layout/question // Supporting Files import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import baseMixin from '../../mixins/base-mixin'; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; +import baseMixin from '../../mixins/base-mixin'; // Mock our module for promises. jest.mock('@/helpers/layout-helper.js', () => ({ @@ -182,63 +182,59 @@ describe('questionsPageLayout.vue', () => { }); function setupMocks() { - const baseStoreGettersPageData = () => { - return { - partsOrQuestions: [ - { - parts: null, - partQuestions: [ - { - questionSequence: 1, - questionText: + const baseStoreGettersPageData = () => ({ + partsOrQuestions: [ + { + parts: null, + partQuestions: [ + { + questionSequence: 1, + questionText: 'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?', - answers: [ - { - answerResult: '', - answerText: 'Yes', - nextQuestionSequence: 2 - }, - { - answerResult: '', - answerText: 'No', - nextQuestionSequence: 3 - } - ] - } - ], - glassLocation: 'Windshield', - glassName: 'Single', - answerKey: 'Windshield-Single', - answerData: null - } - ] - }; - }; - const baseStoreGettersDamage = () => { - return { - partsQuestionAnswers: [ - { - glassLocation: 'Windshield', - glassName: 'Single', - result: 'FW04848', - answeredQuestions: [ - { - questionText: + answers: [ + { + answerResult: '', + answerText: 'Yes', + nextQuestionSequence: 2 + }, + { + answerResult: '', + answerText: 'No', + nextQuestionSequence: 3 + } + ] + } + ], + glassLocation: 'Windshield', + glassName: 'Single', + answerKey: 'Windshield-Single', + answerData: null + } + ] + }); + const baseStoreGettersDamage = () => ({ + partsQuestionAnswers: [ + { + glassLocation: 'Windshield', + glassName: 'Single', + result: 'FW04848', + answeredQuestions: [ + { + questionText: 'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?', - selectedAnswerText: 'Yes', - questionNum: 1 - }, - { - questionText: + selectedAnswerText: 'Yes', + questionNum: 1 + }, + { + questionText: 'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?', - selectedAnswerText: 'Yes', - questionNum: 2 - } - ] - } - ] - }; - }; + selectedAnswerText: 'Yes', + questionNum: 2 + } + ] + } + ] + }); const mountOptions = getMountOptions({ mixins: [baseMixin, vehicleQuestionsMixin] }); diff --git a/src/iss-components/questions-page-layout/questions-page-layout.vue b/src/iss-components/questions-page-layout/questions-page-layout.vue index d471a015..f16cbed7 100644 --- a/src/iss-components/questions-page-layout/questions-page-layout.vue +++ b/src/iss-components/questions-page-layout/questions-page-layout.vue @@ -57,7 +57,7 @@ import alert from '@/ux-components/alert/alert'; import questionChain from '@/digital-components/question-chain/question-chain'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header'; import siteFooter from '@/iss-components/site-footer/site-footer'; -import loadingModal from '@/iss-components/loading-modal/loading-modal.vue'; +import loadingModal from '@/iss-components/loading-modal/loading-modal'; export default { name: 'questions-page', diff --git a/src/iss-components/site-footer/site-footer.spec.js b/src/iss-components/site-footer/site-footer.spec.js index f361b63a..0f44c830 100644 --- a/src/iss-components/site-footer/site-footer.spec.js +++ b/src/iss-components/site-footer/site-footer.spec.js @@ -1,39 +1,6 @@ import { mount } from '@vue/test-utils'; import siteFooter from './site-footer'; -describe('site-footer.vue', () => { - it('Should emit ForwardClicked on button click', async () => { - // Act - const wrapper = mount(siteFooter, { - mixins: [mockMixin], - }); - wrapper.vm.buttonClick(); - // Assert - expect(wrapper.emitted()['forwardClicked'][0]).toHaveBeenCalled; - }); - - it('Should emit BackClicked on link click', async () => { - // Act - const wrapper = mount(siteFooter, { - mixins: [mockMixin], - }); - wrapper.vm.linkClick(); - // Assert - expect(wrapper.emitted()['backClicked'][0]).toHaveBeenCalled; - }); - - it('Should change button text when update button text is called', async () => { - // Act - const wrapper = mount(siteFooter, { - mixins: [mockMixin], - }); - wrapper.vm.updateButtonText('newText'); - - // Assert - expect(wrapper.componentVM.customButtontext).toBe('newText'); - }); -}); - const mockMixin = { methods: { getCmsContent: jest.fn(), @@ -41,3 +8,36 @@ const mockMixin = { getFooterInfoBoxHeight: jest.fn(() => 80) } }; + +describe('site-footer.vue', () => { + it('Should emit ForwardClicked on button click', async () => { + // Act + const wrapper = mount(siteFooter, { + mixins: [mockMixin] + }); + wrapper.vm.buttonClick(); + // Assert + expect(wrapper.emitted().forwardClicked[0]).toHaveBeenCalled; + }); + + it('Should emit BackClicked on link click', async () => { + // Act + const wrapper = mount(siteFooter, { + mixins: [mockMixin] + }); + wrapper.vm.linkClick(); + // Assert + expect(wrapper.emitted().backClicked[0]).toHaveBeenCalled; + }); + + it('Should change button text when update button text is called', async () => { + // Act + const wrapper = mount(siteFooter, { + mixins: [mockMixin] + }); + wrapper.vm.updateButtonText('newText'); + + // Assert + expect(wrapper.componentVM.customButtontext).toBe('newText'); + }); +}); diff --git a/src/iss-components/site-header/site-header.spec.js b/src/iss-components/site-header/site-header.spec.js index 7a078b6f..a9d17aed 100644 --- a/src/iss-components/site-header/site-header.spec.js +++ b/src/iss-components/site-header/site-header.spec.js @@ -2,15 +2,6 @@ import siteHeader from '@/iss-components/site-header/site-header'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; -describe('site-header', () => { - test('renders the logo image', () => { - const wrapper = setupMocks({mountOptionsMockData: {}}); - - expect(wrapper.find('img')).toBeTruthy(); - wrapper.unmount(); - }); -}); - function setupMocks({ mountOptionsMockData = {} }) { @@ -19,3 +10,12 @@ function setupMocks({ return wrapper; } + +describe('site-header', () => { + test('renders the logo image', () => { + const wrapper = setupMocks({mountOptionsMockData: {} }); + + expect(wrapper.find('img')).toBeTruthy(); + wrapper.unmount(); + }); +}); diff --git a/src/iss-components/site-sub-header/site-sub-header.spec.js b/src/iss-components/site-sub-header/site-sub-header.spec.js index 55992894..6b8571a8 100644 --- a/src/iss-components/site-sub-header/site-sub-header.spec.js +++ b/src/iss-components/site-sub-header/site-sub-header.spec.js @@ -5,9 +5,7 @@ describe('site sub header', () => { const subHeaderText = "let's fix your glass"; const mockMixin = { methods: { - getCmsContent: jest.fn().mockImplementation(() => { - return subHeaderText; - }) + getCmsContent: jest.fn().mockImplementation(() => subHeaderText) } }; diff --git a/src/iss-components/steering-text/steering-text.spec.js b/src/iss-components/steering-text/steering-text.spec.js index 62394db5..a16ec74a 100644 --- a/src/iss-components/steering-text/steering-text.spec.js +++ b/src/iss-components/steering-text/steering-text.spec.js @@ -4,6 +4,17 @@ import { createPinia } from 'pinia'; import { createApp } from 'vue'; import steeringTextModal from './steering-text'; +const mockCmsContent = { + BodyText: 'MASteeringText' + +}; + +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => mockCmsContent[cmsFieldName]) + } +}; + describe('steering-text.vue', () => { test('Should display steering text from CMS for state MA', async () => { // Act @@ -15,26 +26,10 @@ describe('steering-text.vue', () => { }, attachTo: document.body }); - expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['BodyText'])); + expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.BodyText)); }); }); const vueApp = createApp(App); const pinia = createPinia(); vueApp.use(pinia); -/////////////// -// Constants // -/////////////// - -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return mockCmsContent[cmsFieldName]; - }) - } -}; - -const mockCmsContent = { - BodyText: 'MASteeringText' - -}; diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index f3dd4ef7..3e6a6930 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -24,13 +24,12 @@ export default { if (params.has(queryStrings.ISS_PAGE)) { return params.get(queryStrings.ISS_PAGE); - } else { - return ''; } + return ''; }, logPageView(pageEvent) { const currentPageName = this.getPageNameByQueryString(); - var payload = { + const payload = { userId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), pageName: currentPageName, @@ -47,15 +46,15 @@ export default { logCustomEvent(category, action, label, value) { const currentPageName = this.getPageNameByQueryString(); - var payload = { + const payload = { userId: getDeviceIdValue(), sessionKey: getSessionKeyValue(), pageName: currentPageName, sessionId: getSessionIdValue(), - category: category, - action: action, - label: label, - value: value, + category, + action, + label, + value, shouldUseSessionId: false, experimentsForUser: useMainStore().applicationUser.experiments }; @@ -69,8 +68,8 @@ export default { const eventToBePushed = { event: GaEvents.GENERIC_EVENT, - category: category, - action: action, + category, + action, label: labelToLog, value: undefined, path: `/iss/?${queryStrings.ISS_PAGE}=${currentPageName}` @@ -97,14 +96,14 @@ export default { }, pushExperimentsToDataLayer() { - const experiments = useMainStore().applicationUser.experiments; + const { experiments } = useMainStore().applicationUser; experiments?.forEach((exp) => { // Set Google Dimension Index based on experiment settings. let googleDimensionIndex = 99; if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) { - googleDimensionIndex = - exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX]; + googleDimensionIndex + = exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX]; } // Create object with dimension index and value. @@ -113,7 +112,7 @@ export default { [`variationId_${googleDimensionIndex}`]: exp.variationId, [`experimentName_${googleDimensionIndex}`]: exp.universeName, [`variationName_${googleDimensionIndex}`]: exp.variationName, - [`customDimension_${googleDimensionIndex}`]: `${exp.universeId}_${exp.variationId}_${exp.universeName}_${exp.variationName}`, + [`customDimension_${googleDimensionIndex}`]: `${exp.universeId}_${exp.variationId}_${exp.universeName}_${exp.variationName}` }; // Push to the data layer with the Google Custom Dimension Index. @@ -135,7 +134,7 @@ export default { async initSession() { const sid = getSessionIdValue(); const skey = getSessionKeyValue(); - var payload = { + const payload = { userId: getDeviceIdValue(), sessionId: sid, userAgent: navigator.userAgent, @@ -146,28 +145,24 @@ export default { if (response?.data) { if (response?.data.sessionKey && skey === 0) { - setCookieProperties( - { [cookieNames.SESSION_KEY]: response?.data.sessionKey }, + setCookieProperties({ [cookieNames.SESSION_KEY]: response?.data.sessionKey }, { useDefaultFunnelCookieAttributes: false - } - ); + }); } if (response?.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') { - setCookieProperties( - { [cookieNames.SESSION_ID]: response?.data.sessionId }, + setCookieProperties({ [cookieNames.SESSION_ID]: response?.data.sessionId }, { maxAge: 60 * 30 // 30 minutes - } - ); + }); } } }, noSession() { return ( - getSessionKeyValue() === 0 || - getSessionIdValue() === '00000000-0000-0000-0000-000000000000' + getSessionKeyValue() === 0 + || getSessionIdValue() === '00000000-0000-0000-0000-000000000000' ); } }, diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index 2d0f640d..e250f527 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -5,20 +5,14 @@ import { GaCategories, GaActions, GaLabels, - GaEvents, ValueToLogTypes } from '@/constants/analytics'; import { useMainStore } from '@/store'; describe('analyticsMixin.js', () => { test('logPageView: calls dispatch with type and payload', () => { - const type = ''; const payload = {}; - const mockData = { - }; - const mocks = setupMocksForJsFiles(mockData); - const testCookieValue = { sid: '10000000-0000-0000-0000-000000000001' }; @@ -31,9 +25,6 @@ describe('analyticsMixin.js', () => { }); test('logCustomEvent: calls dispatch with type and payload', () => { - const mockData = {}; - const mocks = setupMocksForJsFiles(mockData); - useMainStore().logCustomEvent('someCat', 'someAction', 'someLabel', 'someVal'); expect(useMainStore().logCustomEvent).toBeCalled(); @@ -42,9 +33,7 @@ describe('analyticsMixin.js', () => { test('pushEventToGA, should call dataLayer push and logCustomEvent too', () => { // Arrange window.dataLayer = []; - const mockData = {}; - const mocks = setupMocksForJsFiles(mockData); - var mockDataLayer = []; + const mockDataLayer = []; mockDataLayer.push({ event: 'event', category: 'category', @@ -64,7 +53,7 @@ describe('analyticsMixin.js', () => { test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 only logs last 5 of label', () => { // Arrange window.dataLayer = []; - var expectedDataLayer = []; + const expectedDataLayer = []; expectedDataLayer.push({ event: 'event', category: 'category', @@ -75,13 +64,11 @@ describe('analyticsMixin.js', () => { }); // Act - analyticsMixin.methods.pushEventToGA( - 'category', + analyticsMixin.methods.pushEventToGA('category', 'action', '1111122222333333', false, - ValueToLogTypes.LAST_5 - ); + ValueToLogTypes.LAST_5); // Assert expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer)); @@ -90,7 +77,7 @@ describe('analyticsMixin.js', () => { test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 logs only the last 3 characters for a 3 character string', () => { // Arrange window.dataLayer = []; - var expectedDataLayer = []; + const expectedDataLayer = []; expectedDataLayer.push({ event: 'event', category: 'category', @@ -101,13 +88,11 @@ describe('analyticsMixin.js', () => { }); // Act - analyticsMixin.methods.pushEventToGA( - 'category', + analyticsMixin.methods.pushEventToGA('category', 'action', '111', false, - ValueToLogTypes.LAST_5 - ); + ValueToLogTypes.LAST_5); // Assert expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer)); diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index 79a932cd..132d5697 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -24,11 +24,11 @@ export default { return footerInfoBox ? footerInfoBox.offsetHeight : 0; }, savePageDataToStore(page, data) { - useMainStore().updatePageData({ page: page, data: data}); + useMainStore().updatePageData({ page, data }); } }, computed: { - // store will be accessible globally as its id + 'Store' + // store will be accessible globally as its id + 'Store' ...mapStores(useMainStore), navigationScenarios() { @@ -44,10 +44,10 @@ export default { return dynamicStrings; }, cssClassNameForCmsWidget() { - return 'widget-name-' + this.cmsWidgetName; + return `widget-name-${this.cmsWidgetName}`; }, routerParams() { return routerParams; } } -} +}; diff --git a/src/mixins/base-mixin.spec.js b/src/mixins/base-mixin.spec.js index 4c821216..30f2ff0c 100644 --- a/src/mixins/base-mixin.spec.js +++ b/src/mixins/base-mixin.spec.js @@ -1,5 +1,5 @@ import baseMixin from '@/mixins/base-mixin'; -import { shallowMount, mount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; describe('base-mixin', () => { it('should set and get cms content', () => { diff --git a/src/mixins/experiment-mixin.js b/src/mixins/experiment-mixin.js index 46408d30..5b1f7142 100644 --- a/src/mixins/experiment-mixin.js +++ b/src/mixins/experiment-mixin.js @@ -3,7 +3,7 @@ import { useMainStore } from '@/store'; export default { methods: { hasSettingEqualTo(settingName, settingValue) { - return useMainStore().experimentSettings[settingName] == settingValue; + return useMainStore().experimentSettings[settingName] === settingValue; }, hasSetting(settingName) { return Object.hasOwn(useMainStore().experimentSettings, settingName); diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 43030cfc..b5dbf1d1 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -11,14 +11,10 @@ export default { return partsOrQuestions?.some((pq) => pq.parts?.length > 1); }, hasChildPartQuestions(partsOrQuestions) { - return partsOrQuestions?.some((pq) => { - return pq.parts?.some((part) => part.childPartQuestions?.length > 0); - }); + return partsOrQuestions?.some((pq) => pq.parts?.some((part) => part.childPartQuestions?.length > 0)); }, hasCapabilityQuestions(partsOrQuestions) { - return partsOrQuestions?.some((pq) => { - return pq.parts?.some((part) => part.requiresCapabilityQuestions === true); - }); + return partsOrQuestions?.some((pq) => pq.parts?.some((part) => part.requiresCapabilityQuestions === true)); }, // method to only include keys listed for lineItems.glassParts in @@ -54,8 +50,8 @@ export default { ]; return ( - orderedVehicleQuestionPages.indexOf(currentPage) - - orderedVehicleQuestionPages.indexOf(issPage) + orderedVehicleQuestionPages.indexOf(currentPage) + - orderedVehicleQuestionPages.indexOf(issPage) ); }, currentPageComesBeforePage(currentPage = this.$route.query.issPage, issPage) { @@ -75,18 +71,18 @@ export default { alreadyAnsweredQuestions?.forEach((answeredGlass) => { // if answeredGlass lacks any of these properties then exit if ( - !answeredGlass.glassLocation || - !answeredGlass.glassName || - !answeredGlass.answeredQuestions || - (!answeredGlass.result && !answeredGlass.partNum) + !answeredGlass.glassLocation + || !answeredGlass.glassName + || !answeredGlass.answeredQuestions + || (!answeredGlass.result && !answeredGlass.partNum) ) { return; } // test if glass parts match if ( - glass.glassLocation === answeredGlass.glassLocation && - glass.glassName === answeredGlass.glassName + glass.glassLocation === answeredGlass.glassLocation + && glass.glassName === answeredGlass.glassName ) { let answerString = ''; @@ -98,12 +94,10 @@ export default { // determine which answer was previously chosen const chosenAns = glass.questions[ answeredQuestion.questionNum - 1 - ].answers.find((a) => { - return ( - a.answerText.toUpperCase() === - answeredQuestion.selectedAnswerText.toUpperCase() - ); - }); + ].answers.find((a) => ( + a.answerText.toUpperCase() + === answeredQuestion.selectedAnswerText.toUpperCase() + )); // set the answerString to use for answerSelected if (chosenAns.nextQuestionSequence) { answerString = `${answeredQuestion.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`; @@ -112,8 +106,8 @@ export default { } // mark this question as answered (question-chain will read this) - glass.questions[answeredQuestion.questionNum - 1].answerSelected = - answerString; + glass.questions[answeredQuestion.questionNum - 1].answerSelected + = answerString; // mark this question as suppressed if needed (question-chain uses this) if (answeredQuestion.suppressThisQuestion) { glass.questions[ @@ -132,8 +126,8 @@ export default { // add answerData to current glass glass.answerData = { - answerResult: answerResult, - answeredQuestions: answeredGlass.answeredQuestions, + answerResult, + answeredQuestions: answeredGlass.answeredQuestions }; } }); @@ -252,8 +246,8 @@ export default { // if the duplicate is 1ST question in array, set indexToSuppressTo if (questionIndex === 0) { if ( - !indexToSuppressTo || - matchedAnswer.nextQuestionSequence < indexToSuppressTo + !indexToSuppressTo + || matchedAnswer.nextQuestionSequence < indexToSuppressTo ) { indexToSuppressTo = matchedAnswer.nextQuestionSequence; } @@ -265,8 +259,8 @@ export default { q.answers.forEach((a) => { // revert any previously set nextQuestion logic modifications if ( - a.originalNextQuestionSequence === - question.questionSequence + a.originalNextQuestionSequence + === question.questionSequence ) { // restore original nextQuestionSequence a.nextQuestionSequence = a.originalNextQuestionSequence; @@ -283,16 +277,16 @@ export default { // update questions that lead to duplicated question if (matchedAnswer.nextQuestionSequence) { - a.originalNextQuestionSequence = - a.nextQuestionSequence; - a.nextQuestionSequence = - matchedAnswer.nextQuestionSequence; + a.originalNextQuestionSequence + = a.nextQuestionSequence; + a.nextQuestionSequence + = matchedAnswer.nextQuestionSequence; } else { - a.originalNextQuestionSequence = - a.nextQuestionSequence; + a.originalNextQuestionSequence + = a.nextQuestionSequence; a.nextQuestionSequence = null; - a.originalAnswerResult = - a.originalAnswerResult || a.answerResult; + a.originalAnswerResult + = a.originalAnswerResult || a.answerResult; a.answerResult = matchedAnswer.answerResult; } } @@ -303,9 +297,7 @@ export default { question.suppressThisQuestion = true; // are there any questions left that are not suppressed? - const remainingQuestions = glass.questions.filter((q) => { - return !q.suppressThisQuestion; - }); + const remainingQuestions = glass.questions.filter((q) => !q.suppressThisQuestion); if (remainingQuestions.length < 1) { // this is the final answer for this glass piece @@ -315,14 +307,14 @@ export default { questionText: question.questionText, selectedAnswerText: matchedAnswer.answerText, questionNum: question.questionSequence, - suppressThisQuestion: question.suppressThisQuestion, + suppressThisQuestion: question.suppressThisQuestion }; // set the answerData (used as indicator that it has been already answered) glass.answerData = { answerResult: matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence : matchedAnswer.answerResult, - answeredQuestions: [answeredQuestionObj], + answeredQuestions: [answeredQuestionObj] }; // suppress this glass piece because it has an answer @@ -332,8 +324,7 @@ export default { }); // Update key to force re-render of glass piece with duplicate question in case user changes previous related answer in the chain - self.questionsData[glassIndex].key = - self.questionsData[glassIndex].key + Date.now().toString(); + self.questionsData[glassIndex].key += Date.now().toString(); } }); }); @@ -341,7 +332,7 @@ export default { // set final answer data for the current answered glass part self.questionsData[answer.index].answerData = { answerResult: answer.answerResult, - answeredQuestions: answer.answeredQuestions, + answeredQuestions: answer.answeredQuestions }; // this part has been fully answered, so advance to next part's question chain @@ -360,74 +351,60 @@ export default { const currentPage = self.$route.query.issPage; const hasPartQuestions = this.hasPartQuestions(partsOrQuestions); - const hasGlassLocationWithMultipleParts = - this.hasGlassLocationWithMultipleParts(partsOrQuestions); + const hasGlassLocationWithMultipleParts + = this.hasGlassLocationWithMultipleParts(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); - if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, issPageValues.PART_QUESTIONS)) - { - self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, self.$route, - {}, - {}, - { partsOrQuestions: partsOrQuestions } - ); - } else if (hasGlassLocationWithMultipleParts && this.currentPageComesBeforePage(currentPage, issPageValues.VEHICLE_PARTS)) - { + if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, issPageValues.PART_QUESTIONS)) { + self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, self.$route, {}, {}, { partsOrQuestions }); + } else if (hasGlassLocationWithMultipleParts && this.currentPageComesBeforePage(currentPage, issPageValues.VEHICLE_PARTS)) { // if multiple parts on any glass // go to vehicle-parts page and pass the partsData - self.$router.navigate( - self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, self.$route, {}, {}, - { partsOrQuestions: partsOrQuestions } - ); + { partsOrQuestions }); } else if ( - hasChildPartQuestions && - this.currentPageComesBeforePage(currentPage, issPageValues.MOLDING_QUESTIONS) + hasChildPartQuestions + && this.currentPageComesBeforePage(currentPage, issPageValues.MOLDING_QUESTIONS) ) { // if any childpart questions // go to molding-questions page and pass the partsData - self.$router.navigate( - self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, self.$route, {}, {}, - { partsOrQuestions: partsOrQuestions } - ); + { partsOrQuestions }); } else if ( - hasCapabilityQuestions && - this.currentPageComesBeforePage(currentPage, issPageValues.CAPABILITY_QUESTIONS) + hasCapabilityQuestions + && this.currentPageComesBeforePage(currentPage, issPageValues.CAPABILITY_QUESTIONS) ) { // if has capability questions // go to capability-questions page and pass the partsData // mimic part-questions page data for consistency - for (let partOrQuestion of partsOrQuestions) { + for (const partOrQuestion of partsOrQuestions) { if (this.hasCapabilityQuestions([partOrQuestion])) { - let capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)).data; + const capabilityQuestionsForGlassLocation = (await useMainStore().getCapabilityQuestions(useMainStore().vehicle.carId, partOrQuestion.parts[0].partNumber)).data; capabilityQuestionsForGlassLocation.forEach((question) => { - question.answers = question.answers.map((answer) => { - return { - ...answer, - answerResult: answer.answerResult1 - }; - }); + question.answers = question.answers.map((answer) => ({ + ...answer, + answerResult: answer.answerResult1 + })); }); partOrQuestion.capabilityQuestions = capabilityQuestionsForGlassLocation; } } - self.$router.navigate( - self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, self.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); } else { // if single parts only const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); @@ -435,28 +412,27 @@ export default { // save to store lineItems.glassParts useMainStore().updateGlassParts(collectedGlassParts); - self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,self.$route); + self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, self.$route); } }, navigateBack(vm) { const self = vm ?? this; const partsOrQuestions = ( - self.mainStore.pageData(issPageValues.CAPABILITY_QUESTIONS) ?? - self.mainStore.pageData(issPageValues.MOLDING_QUESTIONS) ?? - self.mainStore.pageData(issPageValues.VEHICLE_PARTS) ?? - self.mainStore.pageData(issPageValues.PART_QUESTIONS) + self.mainStore.pageData(issPageValues.CAPABILITY_QUESTIONS) + ?? self.mainStore.pageData(issPageValues.MOLDING_QUESTIONS) + ?? self.mainStore.pageData(issPageValues.VEHICLE_PARTS) + ?? self.mainStore.pageData(issPageValues.PART_QUESTIONS) )?.partsOrQuestions; const hasPartQuestions = this.hasPartQuestions(partsOrQuestions); - const hasGlassLocationWithMultipleParts = - this.hasGlassLocationWithMultipleParts(partsOrQuestions); + const hasGlassLocationWithMultipleParts + = this.hasGlassLocationWithMultipleParts(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); let backNavigationScenario = ''; if (self.mainStore.order.damage.isRepair) { backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_REPAIR; - } - else { + } else { backNavigationScenario = self.mainStore.vehicle.vin ? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS : navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS; @@ -464,24 +440,24 @@ export default { const currentPage = self.$route.query.issPage; if ( - hasCapabilityQuestions && - this.currentPageComesAfterPage(currentPage, issPageValues.CAPABILITY_QUESTIONS) + hasCapabilityQuestions + && this.currentPageComesAfterPage(currentPage, issPageValues.CAPABILITY_QUESTIONS) ) { backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS; } else if ( - hasChildPartQuestions && - this.currentPageComesAfterPage(currentPage, issPageValues.MOLDING_QUESTIONS) + hasChildPartQuestions + && this.currentPageComesAfterPage(currentPage, issPageValues.MOLDING_QUESTIONS) ) { backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS; } else if ( - hasGlassLocationWithMultipleParts && - this.currentPageComesAfterPage(currentPage, issPageValues.VEHICLE_PARTS) + hasGlassLocationWithMultipleParts + && this.currentPageComesAfterPage(currentPage, issPageValues.VEHICLE_PARTS) ) { - backNavigationScenario = - navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE; + backNavigationScenario + = navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE; } else if ( - hasPartQuestions && - this.currentPageComesAfterPage(currentPage, issPageValues.PART_QUESTIONS) + hasPartQuestions + && this.currentPageComesAfterPage(currentPage, issPageValues.PART_QUESTIONS) ) { backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS; } diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index cc69f962..c597411f 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import { setupMocksForJsFiles, getMountOptions } from '@/helpers/unit-test-helper.js'; import { issPageValues } from '@/router/router-constants/issPage-values'; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios'; -import {useMainStore} from '@/store'; +import { useMainStore } from '@/store'; describe('vehicle-questions-mixin', () => { afterEach(() => { @@ -290,8 +290,7 @@ describe('vehicle-questions-mixin', () => { [issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true], [issPageValues.MOLDING_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true] ]; - test.each(testCases)( - '%s comes before %s is %s', + test.each(testCases)('%s comes before %s is %s', (currentPage, nextPage, expectedResult) => { // Arrange const { wrapper } = setupMocks({}); @@ -301,8 +300,7 @@ describe('vehicle-questions-mixin', () => { // Assert expect(result).toEqual(expectedResult); - } - ); + }); }); describe('currentPageComesAfterPage', () => { @@ -390,11 +388,9 @@ describe('vehicle-questions-mixin', () => { const { wrapper } = setupMocks({}); // Act - const returnedGlass = await wrapper.vm.setupInitialData( - glass, + const returnedGlass = await wrapper.vm.setupInitialData(glass, i, - alreadyAnsweredQuestions - ); + alreadyAnsweredQuestions); // Assert expect(returnedGlass.answerData).toMatchObject({ answerResult: 'WKT D1106 C' }); @@ -963,22 +959,12 @@ describe('vehicle-questions-mixin', () => { // Act wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); const duplicatedQuestion = wrapper.vm.questionsData[1].questions[2]; - const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter((a) => { - return a.selected; - }); - const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter( - (a) => { - return a.originalNextQuestionSequence; - } - ); + const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter((a) => a.selected); + const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter((a) => a.originalNextQuestionSequence); // Assert - expect(answerToTest[0].originalNextQuestionSequence).toEqual( - duplicatedQuestion.questionSequence - ); - expect(answerToTest[0].nextQuestionSequence).toEqual( - duplicatedQuestionAnswer[0].nextQuestionSequence - ); + expect(answerToTest[0].originalNextQuestionSequence).toEqual(duplicatedQuestion.questionSequence); + expect(answerToTest[0].nextQuestionSequence).toEqual(duplicatedQuestionAnswer[0].nextQuestionSequence); }); describe('and the duplicate was the first question for that part', () => { @@ -1080,15 +1066,9 @@ describe('vehicle-questions-mixin', () => { wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); // Assert - expect( - wrapper.vm.questionsData[1].questions[0].suppressThisQuestion - ).toBeTruthy(); - expect( - wrapper.vm.questionsData[1].questions[1].suppressThisQuestion - ).toBeTruthy(); - expect( - wrapper.vm.questionsData[1].questions[2].suppressThisQuestion - ).toBeFalsy(); + expect(wrapper.vm.questionsData[1].questions[0].suppressThisQuestion).toBeTruthy(); + expect(wrapper.vm.questionsData[1].questions[1].suppressThisQuestion).toBeTruthy(); + expect(wrapper.vm.questionsData[1].questions[2].suppressThisQuestion).toBeFalsy(); }); }); }); @@ -1194,19 +1174,13 @@ describe('vehicle-questions-mixin', () => { const questionsToTest = wrapper.vm.questionsData[1].questions; const answerLeadingToDuplicate = questionsToTest[0].answers[1]; const duplicateQuestion = questionsToTest[2]; - const answerInDuplicateQuestion = duplicateQuestion.answers.filter((a) => { - return a.selected; - }); + const answerInDuplicateQuestion = duplicateQuestion.answers.filter((a) => a.selected); // Assert - expect(answerLeadingToDuplicate.answerResult).toEqual( - answerInDuplicateQuestion[0].answerResult - ); + expect(answerLeadingToDuplicate.answerResult).toEqual(answerInDuplicateQuestion[0].answerResult); expect(answerLeadingToDuplicate.originalAnswerResult).toBeFalsy(); expect(answerLeadingToDuplicate.nextQuestionSequence).toEqual(null); - expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual( - duplicateQuestion.questionSequence - ); + expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual(duplicateQuestion.questionSequence); }); }); }); @@ -1244,7 +1218,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1252,13 +1226,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); test('multiple glass locations have part questions => go to parts-questions', async () => { @@ -1359,7 +1331,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1367,13 +1339,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); test('multiple glass locations selected, one has part question => go to parts-questions', async () => { @@ -1466,7 +1436,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1474,13 +1444,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); test('a selected glass location has part questions and multiple parts => go to parts-questions', async () => { @@ -1621,7 +1589,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1629,13 +1597,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); }); @@ -1669,7 +1635,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1677,13 +1643,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); test('multiple glass locations selected, one of them has multiple parts => go to vehicle parts', async () => { @@ -1781,7 +1745,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1789,13 +1753,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); test('multiple glass locations selected, multiple have multiple parts => go to vehicle-parts', async () => { @@ -1959,7 +1921,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -1967,13 +1929,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); }); @@ -2018,7 +1978,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -2026,13 +1986,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); }); @@ -2060,7 +2018,7 @@ describe('vehicle-questions-mixin', () => { ]; const { wrapper } = setupMocks({ - partsOrQuestions: partsOrQuestions + partsOrQuestions }); // Act @@ -2068,13 +2026,11 @@ describe('vehicle-questions-mixin', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS, wrapper.vm.$route, {}, {}, - { partsOrQuestions } - ); + { partsOrQuestions }); }); }); }); @@ -2089,10 +2045,8 @@ describe('vehicle-questions-mixin', () => { wrapper.vm.navigateBack(); // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_BACK_WITH_REPAIR, - { query: { issPage: issPageValues.COVERAGE_STATEMENT } } - ); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_REPAIR, + { query: { issPage: issPageValues.COVERAGE_STATEMENT } }); }); test('current page is molding questions and there are part questions, multiple parts to choose, and capability questions => go to vehicle-parts', () => { @@ -2107,10 +2061,8 @@ describe('vehicle-questions-mixin', () => { wrapper.vm.navigateBack(); // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, - { query: { issPage: issPageValues.MOLDING_QUESTIONS } } - ); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, + { query: { issPage: issPageValues.MOLDING_QUESTIONS } }); }); test('current page is molding questions and there are part questions and capability questions => go to part-questions', () => { @@ -2125,15 +2077,13 @@ describe('vehicle-questions-mixin', () => { wrapper.vm.navigateBack(); // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, - { query: { issPage: issPageValues.MOLDING_QUESTIONS } } - ); + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, + { query: { issPage: issPageValues.MOLDING_QUESTIONS } }); }); }); }); -function setupMocks({ issPage = issPageValues.VIN_LOOKUP, hasVin, carId }) { +function setupMocks({ issPage = issPageValues.VIN_LOOKUP }) { const baseMixin = setupMocksForJsFiles({ actionList: [ { @@ -2168,8 +2118,8 @@ function setupMocks({ issPage = issPageValues.VIN_LOOKUP, hasVin, carId }) { }; const store = useMainStore(); - let actionResult = []; - store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({data: actionResult})); + const actionResult = []; + store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({ data: actionResult })); const wrapper = shallowMount(mockVehicleQuestionComponent, mocks); diff --git a/src/mixins/vin-pages-mixin.js b/src/mixins/vin-pages-mixin.js index e3541644..94ffbe4c 100644 --- a/src/mixins/vin-pages-mixin.js +++ b/src/mixins/vin-pages-mixin.js @@ -5,7 +5,7 @@ export default { methods: { async navigateForwardWithSingleCarMatch() { const result = await useMainStore().getPartsOrQuestions(); - const partsOrQuestions = result.data.partsOrQuestions; + const { partsOrQuestions } = result.data; vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this); } diff --git a/src/mixins/vin-pages-mixin.spec.js b/src/mixins/vin-pages-mixin.spec.js index b22c905d..7f66f9cf 100644 --- a/src/mixins/vin-pages-mixin.spec.js +++ b/src/mixins/vin-pages-mixin.spec.js @@ -4,27 +4,6 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js'; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; import { useMainStore } from '@/store'; -describe('vin-pages-mixin', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('navigateForwardWithSingleCarMatch', () => { - test('should navigateForward', async () => { - // Arrange - useMainStore().getPartsOrQuestions = () => { return { data: {partsOrQuestions: {}}} }; - const { wrapper } = setupMocks({}); - vehicleQuestionsMixin.methods.navigateForward = jest.fn(); - - // Act - await wrapper.vm.navigateForwardWithSingleCarMatch(); - - // Assert - expect(vehicleQuestionsMixin.methods.navigateForward).toHaveBeenCalled(); - }); - }); -}); - function setupMocks() { const mocks = getMountOptions({ router: { @@ -40,3 +19,24 @@ function setupMocks() { return { wrapper }; } + +describe('vin-pages-mixin', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('navigateForwardWithSingleCarMatch', () => { + test('should navigateForward', async () => { + // Arrange + useMainStore().getPartsOrQuestions = () => ({ data: { partsOrQuestions: {} } }); + const { wrapper } = setupMocks({}); + vehicleQuestionsMixin.methods.navigateForward = jest.fn(); + + // Act + await wrapper.vm.navigateForwardWithSingleCarMatch(); + + // Assert + expect(vehicleQuestionsMixin.methods.navigateForward).toHaveBeenCalled(); + }); + }); +});