Merge pull request #380 from Safelite/refactor/linting5

Baseline linting of helpers & mixins
This commit is contained in:
DavidAtSafelite 2023-07-26 12:17:18 -04:00 committed by GitHub
commit 5fc43ab548
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 577 additions and 717 deletions

View file

@ -23,6 +23,7 @@ module.exports = {
'comma-dangle': ['error', 'never'], 'comma-dangle': ['error', 'never'],
indent: ['error', 4], indent: ['error', 4],
'max-len': ['error', { code: 140 }], 'max-len': ['error', { code: 140 }],
'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
'vue/html-indent': 'off', 'vue/html-indent': 'off',
'vue/html-closing-bracket-newline': ['error', { 'vue/html-closing-bracket-newline': ['error', {
singleline: 'never', singleline: 'never',

View file

@ -1,5 +1,5 @@
const applicationConfig = { 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, CONSUMER_CF_DISTRO: process.env.VUE_APP_CONSUMER_CF_DISTRO,
ANALYTICS_SESSION_TIMEOUT_MINUTES: 30, ANALYTICS_SESSION_TIMEOUT_MINUTES: 30,
SAVED_SESSION_TIMEOUT_DAYS: 45, SAVED_SESSION_TIMEOUT_DAYS: 45,
@ -8,7 +8,7 @@ const applicationConfig = {
SITE_ENTRY_TRIGGER_VALUE: 'SelfService', SITE_ENTRY_TRIGGER_VALUE: 'SelfService',
APPLICATION_ABBREVIATION: 'iss', APPLICATION_ABBREVIATION: 'iss',
PAGE_QUERYSTRING: 'issPage', PAGE_QUERYSTRING: 'issPage',
CLIENTTAG_QUERYSTRING: 'CientTag', CLIENTTAG_QUERYSTRING: 'ClientTag',
GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY, GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY,
ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io', ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io',
CASH_PARENT_ACCOUNT_NUMBER: 167132 CASH_PARENT_ACCOUNT_NUMBER: 167132

View file

@ -81,7 +81,7 @@ 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 radio from '@/ux-components/radio/radio'; import radio from '@/ux-components/radio/radio';
import { ErrorMessage } from 'vee-validate'; 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 { export default {
name: 'button-question', name: 'button-question',

View file

@ -7,7 +7,7 @@ const mockMixin = {
methods: { methods: {
getCmsContent: jest.fn().mockImplementation(() => questionText) getCmsContent: jest.fn().mockImplementation(() => questionText)
} }
} };
// TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''" // TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''"
// It is not being used. // It is not being used.

View file

@ -58,6 +58,7 @@ export default {
hasError: Boolean, hasError: Boolean,
placeHolderText: String placeHolderText: String
}, },
emits: ['update:modelValue'],
setup(props) { setup(props) {
const propsClone = { ...props }; const propsClone = { ...props };
const { modelValue } = propsClone; const { modelValue } = propsClone;

View file

@ -50,7 +50,7 @@ export default {
// NOTE: needs to have async/await here; tested and won't work without it // NOTE: needs to have async/await here; tested and won't work without it
await useValidateForm(); await useValidateForm();
this.questionData.map((q, i) => { this.questionData.map((q) => {
const question = { const question = {
questionText: q.questionText, questionText: q.questionText,
questionSequence: q.questionSequence, questionSequence: q.questionSequence,
@ -78,6 +78,7 @@ export default {
if (!q.suppressThisQuestion) { if (!q.suppressThisQuestion) {
this.questions.push(question); this.questions.push(question);
} }
return q;
}); });
if (!this.modelValue?.length > 0 && this.questions.length > 0) { if (!this.modelValue?.length > 0 && this.questions.length > 0) {

View file

@ -1,44 +1,9 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import TextBlock from './text-block'; import TextBlock from './text-block';
describe('modal.vue', () => { const mockCmsContent = {
it("Should display 'Text' when 'Text' is defined in the CMS", async () => { Text: 'Sample text here.'
// 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 mockMixin = { const mockMixin = {
methods: { methods: {
@ -52,6 +17,37 @@ const mockProps = {
justifyText: 'mockJustifyText' justifyText: 'mockJustifyText'
}; };
const mockCmsContent = { describe('modal.vue', () => {
Text: 'Sample text here.' 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));
});
});

View file

@ -1,5 +1,7 @@
<template> <template>
<div class="textbox-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''"> <div
class="textbox-question"
:class="(errors && errors.length) || hasError ? 'has-error' : ''">
<label <label
v-if="displayQuestionText" v-if="displayQuestionText"
:for="inputId" :for="inputId"
@ -43,7 +45,10 @@
@focus="$emit('focus', $event.target.value)" @focus="$emit('focus', $event.target.value)"
@paste="trimOnPaste" @paste="trimOnPaste"
@drop="trimOnPaste" /> @drop="trimOnPaste" />
<button v-if="includeSearchIcon" type="submit" aria-label="Search button" /> <button
v-if="includeSearchIcon"
type="submit"
aria-label="Search button" />
<button <button
v-if="includeSelectIcon" v-if="includeSelectIcon"
type="submit" type="submit"
@ -51,8 +56,12 @@
:data-bs-target="'#' + cmsWidgetName" :data-bs-target="'#' + cmsWidgetName"
aria-label="Select button" /> aria-label="Select button" />
</div> </div>
<div v-show="errorMessage" class="row my-1 form-test-error"> <div
<span class="d-inline-flex mt-0" role="alert">{{ errorMessage }}</span> v-show="errorMessage"
class="row my-1 form-test-error">
<span
class="d-inline-flex mt-0"
role="alert">{{ errorMessage }}</span>
</div> </div>
</div> </div>
</template> </template>
@ -107,12 +116,12 @@ export default {
let initialValue; let initialValue;
switch (typeof modelValue) { switch (typeof modelValue) {
case 'number': case 'number':
initialValue = modelValue; initialValue = modelValue;
break; break;
default: default:
initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; initialValue = modelValue && modelValue.length > 0 ? modelValue : '';
break; break;
} }
const fieldOptions = { const fieldOptions = {
@ -122,11 +131,9 @@ export default {
}; };
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(props.inputId,
props.inputId,
props.validationRules, props.validationRules,
fieldOptions fieldOptions);
);
return { return {
errorMessage, errorMessage,

View file

@ -8,6 +8,12 @@
let lastFocusedInputGroupName = ''; let lastFocusedInputGroupName = '';
let onButtonQuestionLostFocusCallback = null; let onButtonQuestionLostFocusCallback = null;
const invokeButtonQuestionLostFocusCallback = () => {
if (onButtonQuestionLostFocusCallback) {
onButtonQuestionLostFocusCallback();
}
};
const handleAnyComponentFocus = (e) => { const handleAnyComponentFocus = (e) => {
const targetType = e.target.type; const targetType = e.target.type;
if (targetType !== 'radio' && targetType !== 'checkbox') { if (targetType !== 'radio' && targetType !== 'checkbox') {
@ -28,10 +34,4 @@ const handleInputComponentBlur = (e) => {
} }
}; };
const invokeButtonQuestionLostFocusCallback = () => {
if (onButtonQuestionLostFocusCallback) {
onButtonQuestionLostFocusCallback();
}
};
export { handleAnyComponentFocus, handleButtonComponentFocus, handleInputComponentBlur }; export { handleAnyComponentFocus, handleButtonComponentFocus, handleInputComponentBlur };

View file

@ -1,13 +1,12 @@
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
export function validateISSClientTag(clientTag) { export function validateISSClientTag(clientTag) {
const store = useMainStore() const store = useMainStore();
return store.validateClientTag(clientTag) return store.validateClientTag(clientTag)
.then((response) => .then((response) =>
// Success // Success
response response,
,
(error) => (error) =>
// Error // Error
null); null);

View file

@ -3,34 +3,31 @@ import { useMainStore } from '@/store';
export function fetchCmsContentForPage(issPage) { export function fetchCmsContentForPage(issPage) {
const store = useMainStore(); const store = useMainStore();
const clientName = store.issConfig.clientName; const { clientName } = store.issConfig;
const accountNumber = store.issConfig.accountNumber; const { accountNumber } = store.issConfig;
const clientOverride = (clientName.length > 0 && accountNumber > 0); const clientOverride = (clientName.length > 0 && accountNumber > 0);
return store.getPageData(issPage) return store.getPageData(issPage)
.then( // Get the base/default page first.
// Get the base/default page first. .then((baseResponse) => {
(baseResponse) => { if (!clientOverride) {
if (!clientOverride) { // Return the base page if there are no client override.
// Return the base page if there are no client override. return processPageData(baseResponse, null);
return processPageData(baseResponse, null); }
} else { // Else get the client override page.
// Else get the client override page. const pageName = `${issPage}_${clientName.toLowerCase().replace(/ /g, '')}`;
const pageName = issPage + '_' + clientName.toLowerCase().replace(/ /g, '');
return store.getPageData(pageName) return store.getPageData(pageName)
.then((clientResponse) => { .then((clientResponse) =>
// Process the client override if it exists. // Process the client override if it exists.
return processPageData(baseResponse, clientResponse); processPageData(baseResponse, clientResponse),
}, (error) => {
(error) => { console.error(error);
console.error(error); // Process the just the base if no client override exists.
// Process the just the base if no client override exists. return processPageData(baseResponse, null);
return processPageData(baseResponse, null); });
}); });
} }
});
};
// Support method for processing the page data from the CMS call. // Support method for processing the page data from the CMS call.
// widgets = current widget collection used by page. // widgets = current widget collection used by page.
@ -41,8 +38,8 @@ function processPageData(baseResponse, clientResponse) {
let widgets = []; let widgets = [];
if (!baseResponse?.data?.Result) { if (!baseResponse?.data?.Result) {
console.error('No result data found'); // Something has gone terribly wrong. console.error('No result data found'); // Something has gone terribly wrong.
return {} return {};
} }
if (!clientResponse?.data?.Result) { if (!clientResponse?.data?.Result) {
widgets = baseResponse.data.Result; widgets = baseResponse.data.Result;
@ -111,7 +108,7 @@ function findAndReplaceGlobalStateValues(widgetModel, widgetName) {
}; };
Object.keys(widgetModel).forEach((key) => { Object.keys(widgetModel).forEach((key) => {
let modelWithReplacements = processWidgetItemForReplacement(widgetModel, const modelWithReplacements = processWidgetItemForReplacement(widgetModel,
key); key);
objWithReplacements.Model[key] = modelWithReplacements; objWithReplacements.Model[key] = modelWithReplacements;
@ -144,8 +141,8 @@ function processWidgetItemForReplacement(widgetModel, key) {
} }
// If we have an object. array, etc // If we have an object. array, etc
if (typeof widgetModel[key] === 'object' && if (typeof widgetModel[key] === 'object'
Object.keys(widgetModel[key]).length) { && Object.keys(widgetModel[key]).length) {
Object.keys(widgetModel[key]).forEach((item) => { Object.keys(widgetModel[key]).forEach((item) => {
processWidgetItemForReplacement(widgetModel[key], item); processWidgetItemForReplacement(widgetModel[key], item);
}); });
@ -158,14 +155,14 @@ function processWidgetItemForReplacement(widgetModel, key) {
} }
function mapStringToModal(str) { function mapStringToModal(str) {
const startIndex = str.indexOf('{' + dynamicStrings.MODAL_LINK); const startIndex = str.indexOf(`{${dynamicStrings.MODAL_LINK}`);
let linkToReplace = str.substring(startIndex, str.length); let linkToReplace = str.substring(startIndex, str.length);
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1);
const params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length - 1); const params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length - 1);
const splitParams = params.split(','); const splitParams = params.split(',');
const bodyText = '<a modalTarget="' + splitParams[0] + '" class="modal-text" aria-label="Modal window">' + splitParams[1] + '</a>'; const bodyText = `<a modalTarget="${splitParams[0]}" class="modal-text" aria-label="Modal window">${splitParams[1]}</a>`;
let returnVal = str.replace(linkToReplace, bodyText); let returnVal = str.replace(linkToReplace, bodyText);
@ -176,14 +173,14 @@ function mapStringToModal(str) {
} }
function mapStringToLink(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); let linkToReplace = str.substring(startIndex, str.length);
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1);
const params = linkToReplace.substring((dynamicStrings.EXTERNAL_LINK).length + 2, linkToReplace.length - 1); const params = linkToReplace.substring((dynamicStrings.EXTERNAL_LINK).length + 2, linkToReplace.length - 1);
const splitParams = params.split(','); const splitParams = params.split(',');
const bodyText = '<a href="' + splitParams[0] + '" class="external-text" target="_blank">' + splitParams[1] + '</a>'; const bodyText = `<a href="${splitParams[0]}" class="external-text" target="_blank">${splitParams[1]}</a>`;
let returnVal = str.replace(linkToReplace, bodyText); 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 to convert a string, into a matching global state item.
function mapStringToState(str) { function mapStringToState(str) {
// Pull all matches out of the string. // Pull all matches out of the string.
const regexExp = new RegExp('{([^{}]*?):([^{}]*?)}', 'g'); const regexExp = /{([^{}]*?):([^{}]*?)}/g;
const regexMatches = [...str.matchAll(regexExp)]; const regexMatches = [...str.matchAll(regexExp)];
const globalStateMatches = regexMatches.filter(match => { const globalStateMatches = regexMatches.filter((match) => match[1] === dynamicStrings.GLOBAL_STATE);
return match[1] === dynamicStrings.GLOBAL_STATE;
});
// Our final string value that will be built from the matches. // Our final string value that will be built from the matches.
let stringBuilder = ''; const stringBuilder = '';
for (const match of globalStateMatches) { for (const match of globalStateMatches) {
// Reset store state for each match. // Reset store state for each match.
const valueFromStore = getStoreValueFromString(match[2]); const valueFromStore = getStoreValueFromString(match[2]);
if (!valueFromStore) { if (!valueFromStore) {
console.warning('Unable to resolve global state data.'); 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); const stringWithReplacement = str.replace(match[0], valueFromStore);
@ -231,7 +226,7 @@ function getStoreValueFromString(str) {
let storeOrStateObject = useMainStore(); let storeOrStateObject = useMainStore();
for (const s of str.split('.')) { for (const s of str.split('.')) {
if (s === 'getters') continue; //For backward compatibility if (s === 'getters') continue; // For backward compatibility
if (storeOrStateObject[s] != undefined) { if (storeOrStateObject[s] != undefined) {
storeOrStateObject = storeOrStateObject[s]; storeOrStateObject = storeOrStateObject[s];
} else { } else {
@ -241,9 +236,9 @@ function getStoreValueFromString(str) {
return storeOrStateObject ?? ''; return storeOrStateObject ?? '';
} }
/////////////////////////////////// /// ////////////////////////////////
// If Statement Processing Logic // // If Statement Processing Logic //
/////////////////////////////////// /// ////////////////////////////////
/** /**
* Recursive function - replaces all instances of if statements from the CMS that utilize the specified ifConditionKeyword * 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 * @returns The processed string
*/ */
export function processIfStatements(str, ifConditionKeyword, replacePlaceholderCallback) { 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); const hasEmbeddedCrLf = /\r?\n|\r/g.test(str);
if (!containsRelevantIfStatement) { if (!containsRelevantIfStatement) {
return str; 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) { function getAndFlagFirstNonNestedIfStatementWithKeyword(matches, ifConditionKeyword) {
@ -342,20 +336,18 @@ function executeIfStatementAndSetProcessedStrings(ifStatementArray, replacePlace
function setProcessedStringOnEntry(entry, isInsideDesiredBlock) { function setProcessedStringOnEntry(entry, isInsideDesiredBlock) {
if (!isInsideDesiredBlock) { if (!isInsideDesiredBlock) {
entry.groups.processedString = ''; 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 { } else {
if (entry.groups.isIfStatement) { entry.groups.processedString = entry.isFlaggedForProcessing
entry.groups.processedString = entry.isFlaggedForProcessing ? entry.groups.endTrailingString
? entry.groups.ifTrailingString : entry[0];
: 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];
}
} }
} }
@ -364,43 +356,43 @@ function getIfStatementRegexExpression() {
// {if:...} or {else} or {end} // {if:...} or {else} or {end}
const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})'; const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})';
// NOTE: ?<variableName> syntax stores the captured match like so: match.groups.variableName // NOTE: ?<variableName> syntax stores the captured match like so: match.groups.variableName
const matchStartOfString = const matchStartOfString
'(?<processedString>^.+?)' + // Match and Capture all characters (lazy), cannot be empty = '(?<processedString>^.+?)' // Match and Capture all characters (lazy), cannot be empty
'(?=(?:{if))'; // Looks ahead but does not capture {if + '(?=(?:{if))'; // Looks ahead but does not capture {if
const matchIfOperator = const matchIfOperator
'(?<isIfStatement>{if:)' + // Match & Capture {if: = '(?<isIfStatement>{if:)' // Match & Capture {if:
'(?<ifConditionType>.*?):' + // Match all chars up to and including next ':' - Capture all chars up to ':' + '(?<ifConditionType>.*?):' // Match all chars up to and including next ':' - Capture all chars up to ':'
'(?<ifCondition>.*?)}' + // Match all chars up to and including next '}' - Capture all chars up to '}' + '(?<ifCondition>.*?)}' // Match all chars up to and including next '}' - Capture all chars up to '}'
'(?<ifTrailingString>.*?)' + // Match and Capture all characters (lazy), can be empty + '(?<ifTrailingString>.*?)' // Match and Capture all characters (lazy), can be empty
'(?=' + + `(?=${
anyLogicOperatorNonCapture + anyLogicOperatorNonCapture
')'; // Looks ahead but does not capture the next logic operator })`; // Looks ahead but does not capture the next logic operator
const matchElseOperator = const matchElseOperator
'(?<isElseStatement>{else})' + // Match & Capture {else} = '(?<isElseStatement>{else})' // Match & Capture {else}
'(?<elseTrailingString>.*?)' + // Match & Capture all characters (lazy), can be empty + '(?<elseTrailingString>.*?)' // Match & Capture all characters (lazy), can be empty
'(?=' + + `(?=${
anyLogicOperatorNonCapture + anyLogicOperatorNonCapture
')'; // Looks ahead but does not capture the next logic operator })`; // Looks ahead but does not capture the next logic operator
const matchEndOperator = const matchEndOperator
'(?<isEndStatement>{end})' + // Match & Capture {end} = '(?<isEndStatement>{end})' // Match & Capture {end}
'(?<endTrailingString>.*?)' + // Match & Capture all chracters (lazy), can be empty + '(?<endTrailingString>.*?)' // Match & Capture all characters (lazy), can be empty
'(?=' + + `(?=${
anyLogicOperatorNonCapture + anyLogicOperatorNonCapture
'|$)'; // Looks ahead but does not capture the next logic operator }|$)`; // Looks ahead but does not capture the next logic operator
// Combine all matching patterns, separated by 'or' pipes // Combine all matching patterns, separated by 'or' pipes
return new RegExp(matchStartOfString + return new RegExp(`${matchStartOfString
'|' + }|${
matchIfOperator + matchIfOperator
'|' + }|${
matchElseOperator + matchElseOperator
'|' + }|${
matchEndOperator, matchEndOperator}`,
'g'); 'g');
} }
////////////////////////////////////////// /// ///////////////////////////////////////
// End of If Statement Processing Logic // // End of If Statement Processing Logic //
////////////////////////////////////////// /// ///////////////////////////////////////
export function doesCopyContainTextLink(copy) { export function doesCopyContainTextLink(copy) {
return copy.includes(dynamicStrings.TEXT_LINK); return copy.includes(dynamicStrings.TEXT_LINK);
@ -409,12 +401,12 @@ export function doesCopyContainTextLink(copy) {
export function setupModalLinks(context) { export function setupModalLinks(context) {
context.$nextTick(() => { context.$nextTick(() => {
const elements = document.getElementsByClassName('modal-text'); const elements = document.getElementsByClassName('modal-text');
for (let element of elements){ for (const element of elements) {
const target = element.getAttribute('modalTarget'); const target = element.getAttribute('modalTarget');
if (target) { if (target) {
element.addEventListener('click', () => context.$refs[target].openModal() ); element.addEventListener('click', () => context.$refs[target].openModal());
} }
}; }
}); });
} }

View file

@ -106,11 +106,9 @@ export function updateSessionIdCookie() {
createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 }); createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
} }
export function setCookieProperties( export function setCookieProperties(properties,
properties, { useDefaultISSCookieAttributes = true, maxAge, isSecure }) {
{ useDefaultISSCookieAttributes = true, maxAge, isSecure } if (typeof properties === 'object') {
) {
if (typeof properties == 'object') {
Object.keys(properties).forEach((key) => { Object.keys(properties).forEach((key) => {
createOrUpdateCookie(key, properties[key], { createOrUpdateCookie(key, properties[key], {
useDefaultISSCookieAttributes, useDefaultISSCookieAttributes,
@ -132,8 +130,8 @@ export function setCookieProperties(
Takes an object with properties to set. Will overwrite existing properties. Takes an object with properties to set. Will overwrite existing properties.
*/ */
function setISSCookieProperties(properties) { function setISSCookieProperties(properties) {
if (typeof properties == 'object') { if (typeof properties === 'object') {
let cookie = getISSCookie(); const cookie = getISSCookie();
if (cookie !== null) { if (cookie !== null) {
Object.keys(properties).forEach((key) => { Object.keys(properties).forEach((key) => {
@ -150,11 +148,8 @@ function setISSCookieProperties(properties) {
Used to create a cookie. Used to create a cookie.
`useDefaultISSCookieAttributes` will set the path and domain to our defaults `useDefaultISSCookieAttributes` will set the path and domain to our defaults
*/ */
function createOrUpdateCookie( function createOrUpdateCookie(key, value = '',
key, { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }) {
value = '',
{ useDefaultISSCookieAttributes = true, maxAge, isSecure = true }
) {
let cookieToAdd = `${key}=${value}; `; let cookieToAdd = `${key}=${value}; `;
if (useDefaultISSCookieAttributes) { if (useDefaultISSCookieAttributes) {
@ -163,7 +158,7 @@ function createOrUpdateCookie(
if (isSecure && !isLocalhost()) { if (isSecure && !isLocalhost()) {
cookieToAdd += 'secure; '; cookieToAdd += 'secure; ';
} }
if (!isNaN(maxAge)) { if (!Number.isNaN(maxAge)) {
cookieToAdd += `max-age=${maxAge};`; cookieToAdd += `max-age=${maxAge};`;
} }
@ -174,7 +169,7 @@ function createOrUpdateCookie(
Gets current domain without the subdomain for cookie. Gets current domain without the subdomain for cookie.
*/ */
function getDomainWithoutSubdomain() { function getDomainWithoutSubdomain() {
let url = location.hostname; const url = location.hostname;
if (isLocalhost()) { if (isLocalhost()) {
return 'localhost'; return 'localhost';
} }
@ -191,8 +186,8 @@ function getDomainWithoutSubdomain() {
Gets cookie value by name, returns empty string if not found. Gets cookie value by name, returns empty string if not found.
*/ */
function getCookieValueByName(name) { function getCookieValueByName(name) {
const value = '; ' + document.cookie; const value = `; ${document.cookie}`;
const parts = value.split('; ' + name + '='); const parts = value.split(`; ${name}=`);
if (parts.length === 2) { if (parts.length === 2) {
return parts.pop().split(';').shift(); return parts.pop().split(';').shift();

View file

@ -1,16 +1,5 @@
import { randomUUID } from 'crypto'; 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) { export function getRandomInt(min = 0, max = 1000) {
min = Math.ceil(min); min = Math.ceil(min);
max = Math.floor(max); max = Math.floor(max);
@ -26,3 +15,14 @@ export function getRandomBoolean() {
const index = getRandomInt(0, 2); const index = getRandomInt(0, 2);
return bools[index]; 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;
}

View file

@ -4,9 +4,9 @@ export default {
// Adds event to the bus given its category, subcategory, and eventValue; // Adds event to the bus given its category, subcategory, and eventValue;
addEventToBus(category, subCategory, eventValue) { addEventToBus(category, subCategory, eventValue) {
useMainStore().addEventToBus({ useMainStore().addEventToBus({
category: category, category,
subCategory: subCategory, subCategory,
eventValue: eventValue, eventValue
}); });
}, },
@ -16,8 +16,8 @@ export default {
if (event) { if (event) {
useMainStore().removeEventFromBus({ useMainStore().removeEventFromBus({
category: category, category,
subCategory: subCategory, subCategory
}); });
} }

View file

@ -11,7 +11,7 @@ useMainStore().removeEventFromBus = jest.fn();
useMainStore().eventBusItem = jest.fn(); useMainStore().eventBusItem = jest.fn();
describe('event-bus.js', () => { describe('event-bus.js', () => {
let event = { const event = {
isDismissible: true, isDismissible: true,
messageCopy: 'You can get a quote by starting on this page.', messageCopy: 'You can get a quote by starting on this page.',
messageHeadline: "We're sorry, something went wrong.", messageHeadline: "We're sorry, something went wrong.",
@ -20,15 +20,13 @@ describe('event-bus.js', () => {
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
}) });
it('removes items when readandpop is called', () => { it('removes items when readandpop is called', () => {
useMainStore().eventBusItem.mockReturnValueOnce(event); useMainStore().eventBusItem.mockReturnValueOnce(event);
const eventValue = eventBus.readAndPopEventFromBus( const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT,
globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND);
globalEvents.SubCategories.PAGE_NOT_FOUND
);
expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().eventBusItem).toBeCalledTimes(1);
expect(useMainStore().removeEventFromBus).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", () => { it("doesn't try to remove items when readandpop is called and item doesn't exist", () => {
useMainStore().eventBusItem.mockReturnValueOnce(undefined); useMainStore().eventBusItem.mockReturnValueOnce(undefined);
const eventValue = eventBus.readAndPopEventFromBus( const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT,
globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND);
globalEvents.SubCategories.PAGE_NOT_FOUND
);
expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().eventBusItem).toBeCalledTimes(1);
expect(useMainStore().removeEventFromBus).toBeCalledTimes(0); expect(useMainStore().removeEventFromBus).toBeCalledTimes(0);
@ -49,21 +45,17 @@ describe('event-bus.js', () => {
it('returns event from bus', () => { it('returns event from bus', () => {
useMainStore().eventBusItem.mockReturnValueOnce(event); useMainStore().eventBusItem.mockReturnValueOnce(event);
const eventValue = eventBus.readEventFromBus( const eventValue = eventBus.readEventFromBus(globalEvents.Categories.GLOBAL_ALERT,
globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND);
globalEvents.SubCategories.PAGE_NOT_FOUND
);
expect(eventValue).toBe(event); expect(eventValue).toBe(event);
}); });
it('Reads event from bus, should have event value.', () => { it('Reads event from bus, should have event value.', () => {
// Arrange / Act // Arrange / Act
eventBus.addEventToBus( eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT,
globalEvents.Categories.GLOBAL_ALERT,
globalEvents.SubCategories.PAGE_NOT_FOUND, globalEvents.SubCategories.PAGE_NOT_FOUND,
event event);
);
expect(useMainStore().addEventToBus).toHaveBeenCalled(); expect(useMainStore().addEventToBus).toHaveBeenCalled();
}); });

View file

@ -2,11 +2,7 @@ export function settleAllPromises(promiseResultMap) {
// Pull our keys out of the promise 'table' // Pull our keys out of the promise 'table'
const promiseNames = Object.entries(promiseResultMap); const promiseNames = Object.entries(promiseResultMap);
return Promise.allSettled( return Promise.allSettled(promiseNames.map((e) => e[1]).map((n) => n.promise)).then((results) => {
promiseNames.map((e) =>
e[1]).map((n) =>
n.promise)
).then((results) => {
const resultMap = {}; const resultMap = {};
// Build a map of the results // Build a map of the results

View file

@ -1,20 +1,16 @@
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
export async function getServiceabilityDetails(serviceZipCode, lineItems) { export async function getServiceabilityDetails(serviceZipCode, lineItems) {
const serviceabilityDetails = await useMainStore().getServiceabilityDetails( const serviceabilityDetails = await useMainStore().getServiceabilityDetails({
{ serviceZipCode,
serviceZipCode: serviceZipCode, lineItems
lineItems: lineItems, },
}, false);
false
);
return Promise.resolve(serviceabilityDetails); return Promise.resolve(serviceabilityDetails);
} }
export async function getZipCodeData(zipCode) { export async function getZipCodeData(zipCode) {
const serviceZipValidationResponse = await useMainStore().validateZip( const serviceZipValidationResponse = await useMainStore().validateZip({ zip: zipCode });
{ zip: zipCode }
);
return { return {
containsMilitaryBase: serviceZipValidationResponse.data.containsMilitaryBase, containsMilitaryBase: serviceZipValidationResponse.data.containsMilitaryBase,

View file

@ -10,8 +10,7 @@ export function isAnalyticsSessionStillActive() {
const lastTouchedValue = getISSCookie().LastTouched; const lastTouchedValue = getISSCookie().LastTouched;
const timeoutAmount = applicationConfig.ANALYTICS_SESSION_TIMEOUT_MINUTES; const timeoutAmount = applicationConfig.ANALYTICS_SESSION_TIMEOUT_MINUTES;
const isMoreThanHalfHourAgo = const isMoreThanHalfHourAgo = (new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount;
(new Date() - new Date(lastTouchedValue)) / 60000 > timeoutAmount;
if (isMoreThanHalfHourAgo) { if (isMoreThanHalfHourAgo) {
return false; return false;
@ -19,6 +18,7 @@ export function isAnalyticsSessionStillActive() {
return true; return true;
} }
return false;
} }
/* /*
@ -35,6 +35,7 @@ export function isSavedSessionStillActive() {
return !isSavedSessionTimedOut; return !isSavedSessionTimedOut;
} }
return false;
} }
/* /*

View file

@ -9,15 +9,7 @@ import {
getCookieDomainValue, getCookieDomainValue,
setCookieProperties setCookieProperties
} from '@/helpers/cookie-helper'; } from '@/helpers/cookie-helper';
import { import { GaActions } from '@/constants/analytics';
analyticsPageEvents,
GaCategories,
GaActions,
GaLabels,
GaEvents,
ValueToLogTypes
} from '@/constants/analytics';
import { routerParams } from '@/router/router-constants/router-params';
import { queryStrings } from '@/constants/query-strings'; import { queryStrings } from '@/constants/query-strings';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { mapStores } from 'pinia'; import { mapStores } from 'pinia';
@ -53,7 +45,7 @@ export function getMountOptions(mockData) {
mocks.prependActionToMethod = jest.fn(); mocks.prependActionToMethod = jest.fn();
const global = { const global = {
mocks: mocks, mocks,
mixins: [mockMixin], mixins: [mockMixin],
plugins: [pinia], plugins: [pinia],
stubs: { stubs: {
@ -78,10 +70,10 @@ export const cookies = {
export function setupCookies({ ISSCookieValue = '', includeHeritageCookie = true }) { export function setupCookies({ ISSCookieValue = '', includeHeritageCookie = true }) {
Object.keys(cookies).forEach((key) => { Object.keys(cookies).forEach((key) => {
const cookieValue = const cookieValue = key === cookieNames.ISS_SESSION_INFO ? ISSCookieValue : cookies[key];
key == cookieNames.ISS_SESSION_INFO ? ISSCookieValue : cookies[key]; if (includeHeritageCookie || key !== cookieNames.ISS_SESSION_INFO) {
if (includeHeritageCookie || key != cookieNames.ISS_SESSION_INFO)
setCookieProperties({ [key]: cookieValue }, { isSecure: false }); setCookieProperties({ [key]: cookieValue }, { isSecure: false });
}
}); });
} }

View file

@ -20,5 +20,5 @@ export function regex(expression, errorMessage) {
} }
return true; return true;
} };
} }

View file

@ -161,18 +161,19 @@ describe('address-questions.vue', () => {
autocompleteElement.addEventListener = jest autocompleteElement.addEventListener = jest
.fn() .fn()
.mockImplementation((eventName, callbackFunction) => { .mockImplementation((eventName, callbackFunction) => {
if (eventName == 'change') { if (eventName === 'change') {
changeEventCallbackFunction = callbackFunction; changeEventCallbackFunction = callbackFunction;
} }
}); });
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
querySelectorFunction(query) { querySelectorFunction(query) {
if (query == '.pac-container .pac-item') { if (query === '.pac-container .pac-item') {
const element = document.createElement('div'); const element = document.createElement('div');
element.textContent = '123 Test Street'; element.textContent = '123 Test Street';
return element; return element;
} }
return null;
}, },
geocoderResult: { geocoderResult: {
address_components: [ address_components: [
@ -276,7 +277,7 @@ describe('address-questions.vue', () => {
autocompleteElement.addEventListener = jest autocompleteElement.addEventListener = jest
.fn() .fn()
.mockImplementation((eventName, callbackFunction) => { .mockImplementation((eventName, callbackFunction) => {
if (eventName == 'change') { if (eventName === 'change') {
changeEventCallbackFunction = callbackFunction; changeEventCallbackFunction = callbackFunction;
} }
}); });
@ -306,18 +307,19 @@ describe('address-questions.vue', () => {
autocompleteElement.addEventListener = jest autocompleteElement.addEventListener = jest
.fn() .fn()
.mockImplementation((eventName, callbackFunction) => { .mockImplementation((eventName, callbackFunction) => {
if (eventName == 'change') { if (eventName === 'change') {
changeEventCallbackFunction = callbackFunction; changeEventCallbackFunction = callbackFunction;
} }
}); });
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
querySelectorFunction(query) { querySelectorFunction(query) {
if (query == '.pac-container .pac-item') { if (query === '.pac-container .pac-item') {
const element = document.createElement('div'); const element = document.createElement('div');
element.textContent = '123 Test Street'; element.textContent = '123 Test Street';
return element; return element;
} }
return null;
} }
}); });
@ -474,7 +476,6 @@ function setupMocks({
const resultingMountOptions = getMountOptions({ const resultingMountOptions = getMountOptions({
...mountOptions, ...mountOptions,
router: { router: {
navigate: jest.fn(),
navigate: jest.fn() navigate: jest.fn()
}, },
loadScript: jest.fn().mockResolvedValue() loadScript: jest.fn().mockResolvedValue()
@ -522,7 +523,7 @@ function setupMocks({
: mount(addressQuestions, resultingMountOptions); : mount(addressQuestions, resultingMountOptions);
document.querySelector = jest.fn().mockImplementation((query) => { document.querySelector = jest.fn().mockImplementation((query) => {
let result = null; let result = null;
if (query == '.pac-container') result = document.createElement('div'); if (query === '.pac-container') result = document.createElement('div');
else if (querySelectorFunction) { else if (querySelectorFunction) {
result = querySelectorFunction(query); result = querySelectorFunction(query);
} }

View file

@ -1,40 +1,6 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import ButtonQuestionModal from './button-question-modal'; 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 = { const mockCmsContent = {
QuestionText: 'What caused damage.', QuestionText: 'What caused damage.',
ButtonText: 'Select an option.', 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));
});
});

View file

@ -1,9 +1,23 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import contentGroupModal from './content-group-modal';
import crypto from 'crypto'; import crypto from 'crypto';
import contentGroupModal from './content-group-modal';
global.crypto = crypto; 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', () => { describe('content-group-modal.vue', () => {
it('Should display header text when HeaderText is defined in the CMS', async () => { it('Should display header text when HeaderText is defined in the CMS', async () => {
const wrapper = mount(contentGroupModal, { const wrapper = mount(contentGroupModal, {
@ -13,7 +27,7 @@ describe('content-group-modal.vue', () => {
}, },
attachTo: document.body 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 () => { 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 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 () => { 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 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 () => { 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 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.'
};

View file

@ -5,6 +5,14 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
jest.mock('@/assets/img/loader.gif', () => 'loader.gif'); jest.mock('@/assets/img/loader.gif', () => 'loader.gif');
jest.mock('@/assets/img/windshield.png', () => 'windshield.png'); jest.mock('@/assets/img/windshield.png', () => 'windshield.png');
function setupMocks() {
const mountOptions = getMountOptions({
});
const wrapper = shallowMount(loadingModal, mountOptions);
return { wrapper };
}
describe('loadingModal', () => { describe('loadingModal', () => {
test('showModal sets modal visible', async () => { test('showModal sets modal visible', async () => {
// Arrange // Arrange
@ -19,11 +27,3 @@ describe('loadingModal', () => {
wrapper.unmount(); wrapper.unmount();
}); });
}); });
function setupMocks() {
const mountOptions = getMountOptions({
});
const wrapper = shallowMount(loadingModal, mountOptions);
return { wrapper };
}

View file

@ -1,6 +1,5 @@
import navButton from './nav-button'
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import navButton from './nav-button';
describe('NavButton', () => { describe('NavButton', () => {
it('should display input when type is button', () => { it('should display input when type is button', () => {

View file

@ -4,8 +4,8 @@ import questionsPageLayout from '@/iss-components/questions-page-layout/question
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import baseMixin from '../../mixins/base-mixin';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import baseMixin from '@/mixins/base-mixin';
// Mock our module for promises. // Mock our module for promises.
jest.mock('@/helpers/layout-helper.js', () => ({ jest.mock('@/helpers/layout-helper.js', () => ({
@ -182,63 +182,59 @@ describe('questionsPageLayout.vue', () => {
}); });
function setupMocks() { function setupMocks() {
const baseStoreGettersPageData = () => { const baseStoreGettersPageData = () => ({
return { partsOrQuestions: [
partsOrQuestions: [ {
{ parts: null,
parts: null, partQuestions: [
partQuestions: [ {
{ questionSequence: 1,
questionSequence: 1, questionText:
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?', 'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
answers: [ answers: [
{ {
answerResult: '', answerResult: '',
answerText: 'Yes', answerText: 'Yes',
nextQuestionSequence: 2 nextQuestionSequence: 2
}, },
{ {
answerResult: '', answerResult: '',
answerText: 'No', answerText: 'No',
nextQuestionSequence: 3 nextQuestionSequence: 3
} }
] ]
} }
], ],
glassLocation: 'Windshield', glassLocation: 'Windshield',
glassName: 'Single', glassName: 'Single',
answerKey: 'Windshield-Single', answerKey: 'Windshield-Single',
answerData: null answerData: null
} }
] ]
}; });
}; const baseStoreGettersDamage = () => ({
const baseStoreGettersDamage = () => { partsQuestionAnswers: [
return { {
partsQuestionAnswers: [ glassLocation: 'Windshield',
{ glassName: 'Single',
glassLocation: 'Windshield', result: 'FW04848',
glassName: 'Single', answeredQuestions: [
result: 'FW04848', {
answeredQuestions: [ questionText:
{
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?', 'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
selectedAnswerText: 'Yes', selectedAnswerText: 'Yes',
questionNum: 1 questionNum: 1
}, },
{ {
questionText: questionText:
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?', 'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
selectedAnswerText: 'Yes', selectedAnswerText: 'Yes',
questionNum: 2 questionNum: 2
} }
] ]
} }
] ]
}; });
};
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
mixins: [baseMixin, vehicleQuestionsMixin] mixins: [baseMixin, vehicleQuestionsMixin]
}); });

View file

@ -57,7 +57,7 @@ import alert from '@/ux-components/alert/alert';
import questionChain from '@/digital-components/question-chain/question-chain'; import questionChain from '@/digital-components/question-chain/question-chain';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
import siteFooter from '@/iss-components/site-footer/site-footer'; 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 { export default {
name: 'questions-page', name: 'questions-page',

View file

@ -1,39 +1,6 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import siteFooter from './site-footer'; 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 = { const mockMixin = {
methods: { methods: {
getCmsContent: jest.fn(), getCmsContent: jest.fn(),
@ -41,3 +8,36 @@ const mockMixin = {
getFooterInfoBoxHeight: jest.fn(() => 80) 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');
});
});

View file

@ -2,15 +2,6 @@ import siteHeader from '@/iss-components/site-header/site-header';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; 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({ function setupMocks({
mountOptionsMockData = {} mountOptionsMockData = {}
}) { }) {
@ -19,3 +10,12 @@ function setupMocks({
return wrapper; return wrapper;
} }
describe('site-header', () => {
test('renders the logo image', () => {
const wrapper = setupMocks({mountOptionsMockData: {} });
expect(wrapper.find('img')).toBeTruthy();
wrapper.unmount();
});
});

View file

@ -5,9 +5,7 @@ describe('site sub header', () => {
const subHeaderText = "let's fix your glass"; const subHeaderText = "let's fix your glass";
const mockMixin = { const mockMixin = {
methods: { methods: {
getCmsContent: jest.fn().mockImplementation(() => { getCmsContent: jest.fn().mockImplementation(() => subHeaderText)
return subHeaderText;
})
} }
}; };

View file

@ -4,6 +4,17 @@ import { createPinia } from 'pinia';
import { createApp } from 'vue'; import { createApp } from 'vue';
import steeringTextModal from './steering-text'; import steeringTextModal from './steering-text';
const mockCmsContent = {
BodyText: 'MASteeringText'
};
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => mockCmsContent[cmsFieldName])
}
};
describe('steering-text.vue', () => { describe('steering-text.vue', () => {
test('Should display steering text from CMS for state MA', async () => { test('Should display steering text from CMS for state MA', async () => {
// Act // Act
@ -15,26 +26,10 @@ describe('steering-text.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent['BodyText'])); expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.BodyText));
}); });
}); });
const vueApp = createApp(App); const vueApp = createApp(App);
const pinia = createPinia(); const pinia = createPinia();
vueApp.use(pinia); vueApp.use(pinia);
///////////////
// Constants //
///////////////
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
return mockCmsContent[cmsFieldName];
})
}
};
const mockCmsContent = {
BodyText: 'MASteeringText'
};

View file

@ -24,13 +24,12 @@ export default {
if (params.has(queryStrings.ISS_PAGE)) { if (params.has(queryStrings.ISS_PAGE)) {
return params.get(queryStrings.ISS_PAGE); return params.get(queryStrings.ISS_PAGE);
} else {
return '';
} }
return '';
}, },
logPageView(pageEvent) { logPageView(pageEvent) {
const currentPageName = this.getPageNameByQueryString(); const currentPageName = this.getPageNameByQueryString();
var payload = { const payload = {
userId: getDeviceIdValue(), userId: getDeviceIdValue(),
sessionKey: getSessionKeyValue(), sessionKey: getSessionKeyValue(),
pageName: currentPageName, pageName: currentPageName,
@ -47,15 +46,15 @@ export default {
logCustomEvent(category, action, label, value) { logCustomEvent(category, action, label, value) {
const currentPageName = this.getPageNameByQueryString(); const currentPageName = this.getPageNameByQueryString();
var payload = { const payload = {
userId: getDeviceIdValue(), userId: getDeviceIdValue(),
sessionKey: getSessionKeyValue(), sessionKey: getSessionKeyValue(),
pageName: currentPageName, pageName: currentPageName,
sessionId: getSessionIdValue(), sessionId: getSessionIdValue(),
category: category, category,
action: action, action,
label: label, label,
value: value, value,
shouldUseSessionId: false, shouldUseSessionId: false,
experimentsForUser: useMainStore().applicationUser.experiments experimentsForUser: useMainStore().applicationUser.experiments
}; };
@ -69,8 +68,8 @@ export default {
const eventToBePushed = { const eventToBePushed = {
event: GaEvents.GENERIC_EVENT, event: GaEvents.GENERIC_EVENT,
category: category, category,
action: action, action,
label: labelToLog, label: labelToLog,
value: undefined, value: undefined,
path: `/iss/?${queryStrings.ISS_PAGE}=${currentPageName}` path: `/iss/?${queryStrings.ISS_PAGE}=${currentPageName}`
@ -97,14 +96,14 @@ export default {
}, },
pushExperimentsToDataLayer() { pushExperimentsToDataLayer() {
const experiments = useMainStore().applicationUser.experiments; const { experiments } = useMainStore().applicationUser;
experiments?.forEach((exp) => { experiments?.forEach((exp) => {
// Set Google Dimension Index based on experiment settings. // Set Google Dimension Index based on experiment settings.
let googleDimensionIndex = 99; let googleDimensionIndex = 99;
if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) { if (exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX] !== undefined) {
googleDimensionIndex = googleDimensionIndex
exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX]; = exp.settings[experimentSettings.GOOGLE_CUSTOM_DIMENSION_INDEX];
} }
// Create object with dimension index and value. // Create object with dimension index and value.
@ -113,7 +112,7 @@ export default {
[`variationId_${googleDimensionIndex}`]: exp.variationId, [`variationId_${googleDimensionIndex}`]: exp.variationId,
[`experimentName_${googleDimensionIndex}`]: exp.universeName, [`experimentName_${googleDimensionIndex}`]: exp.universeName,
[`variationName_${googleDimensionIndex}`]: exp.variationName, [`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. // Push to the data layer with the Google Custom Dimension Index.
@ -135,7 +134,7 @@ export default {
async initSession() { async initSession() {
const sid = getSessionIdValue(); const sid = getSessionIdValue();
const skey = getSessionKeyValue(); const skey = getSessionKeyValue();
var payload = { const payload = {
userId: getDeviceIdValue(), userId: getDeviceIdValue(),
sessionId: sid, sessionId: sid,
userAgent: navigator.userAgent, userAgent: navigator.userAgent,
@ -146,28 +145,24 @@ export default {
if (response?.data) { if (response?.data) {
if (response?.data.sessionKey && skey === 0) { if (response?.data.sessionKey && skey === 0) {
setCookieProperties( setCookieProperties({ [cookieNames.SESSION_KEY]: response?.data.sessionKey },
{ [cookieNames.SESSION_KEY]: response?.data.sessionKey },
{ {
useDefaultFunnelCookieAttributes: false useDefaultFunnelCookieAttributes: false
} });
);
} }
if (response?.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') { if (response?.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') {
setCookieProperties( setCookieProperties({ [cookieNames.SESSION_ID]: response?.data.sessionId },
{ [cookieNames.SESSION_ID]: response?.data.sessionId },
{ {
maxAge: 60 * 30 // 30 minutes maxAge: 60 * 30 // 30 minutes
} });
);
} }
} }
}, },
noSession() { noSession() {
return ( return (
getSessionKeyValue() === 0 || getSessionKeyValue() === 0
getSessionIdValue() === '00000000-0000-0000-0000-000000000000' || getSessionIdValue() === '00000000-0000-0000-0000-000000000000'
); );
} }
}, },

View file

@ -5,20 +5,14 @@ import {
GaCategories, GaCategories,
GaActions, GaActions,
GaLabels, GaLabels,
GaEvents,
ValueToLogTypes ValueToLogTypes
} from '@/constants/analytics'; } from '@/constants/analytics';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
describe('analyticsMixin.js', () => { describe('analyticsMixin.js', () => {
test('logPageView: calls dispatch with type and payload', () => { test('logPageView: calls dispatch with type and payload', () => {
const type = '';
const payload = {}; const payload = {};
const mockData = {
};
const mocks = setupMocksForJsFiles(mockData);
const testCookieValue = { const testCookieValue = {
sid: '10000000-0000-0000-0000-000000000001' sid: '10000000-0000-0000-0000-000000000001'
}; };
@ -31,9 +25,6 @@ describe('analyticsMixin.js', () => {
}); });
test('logCustomEvent: calls dispatch with type and payload', () => { test('logCustomEvent: calls dispatch with type and payload', () => {
const mockData = {};
const mocks = setupMocksForJsFiles(mockData);
useMainStore().logCustomEvent('someCat', 'someAction', 'someLabel', 'someVal'); useMainStore().logCustomEvent('someCat', 'someAction', 'someLabel', 'someVal');
expect(useMainStore().logCustomEvent).toBeCalled(); expect(useMainStore().logCustomEvent).toBeCalled();
@ -42,9 +33,7 @@ describe('analyticsMixin.js', () => {
test('pushEventToGA, should call dataLayer push and logCustomEvent too', () => { test('pushEventToGA, should call dataLayer push and logCustomEvent too', () => {
// Arrange // Arrange
window.dataLayer = []; window.dataLayer = [];
const mockData = {}; const mockDataLayer = [];
const mocks = setupMocksForJsFiles(mockData);
var mockDataLayer = [];
mockDataLayer.push({ mockDataLayer.push({
event: 'event', event: 'event',
category: 'category', 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', () => { test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 only logs last 5 of label', () => {
// Arrange // Arrange
window.dataLayer = []; window.dataLayer = [];
var expectedDataLayer = []; const expectedDataLayer = [];
expectedDataLayer.push({ expectedDataLayer.push({
event: 'event', event: 'event',
category: 'category', category: 'category',
@ -75,13 +64,11 @@ describe('analyticsMixin.js', () => {
}); });
// Act // Act
analyticsMixin.methods.pushEventToGA( analyticsMixin.methods.pushEventToGA('category',
'category',
'action', 'action',
'1111122222333333', '1111122222333333',
false, false,
ValueToLogTypes.LAST_5 ValueToLogTypes.LAST_5);
);
// Assert // Assert
expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer)); 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', () => { test('pushEventToGA, should call dataLayer push and ValueToLogTypes.LAST_5 logs only the last 3 characters for a 3 character string', () => {
// Arrange // Arrange
window.dataLayer = []; window.dataLayer = [];
var expectedDataLayer = []; const expectedDataLayer = [];
expectedDataLayer.push({ expectedDataLayer.push({
event: 'event', event: 'event',
category: 'category', category: 'category',
@ -101,13 +88,11 @@ describe('analyticsMixin.js', () => {
}); });
// Act // Act
analyticsMixin.methods.pushEventToGA( analyticsMixin.methods.pushEventToGA('category',
'category',
'action', 'action',
'111', '111',
false, false,
ValueToLogTypes.LAST_5 ValueToLogTypes.LAST_5);
);
// Assert // Assert
expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer)); expect(expectedDataLayer).toEqual(expect.arrayContaining(window.dataLayer));

View file

@ -24,11 +24,11 @@ export default {
return footerInfoBox ? footerInfoBox.offsetHeight : 0; return footerInfoBox ? footerInfoBox.offsetHeight : 0;
}, },
savePageDataToStore(page, data) { savePageDataToStore(page, data) {
useMainStore().updatePageData({ page: page, data: data}); useMainStore().updatePageData({ page, data });
} }
}, },
computed: { computed: {
// store will be accessible globally as its id + 'Store' // store will be accessible globally as its id + 'Store'
...mapStores(useMainStore), ...mapStores(useMainStore),
navigationScenarios() { navigationScenarios() {
@ -44,10 +44,10 @@ export default {
return dynamicStrings; return dynamicStrings;
}, },
cssClassNameForCmsWidget() { cssClassNameForCmsWidget() {
return 'widget-name-' + this.cmsWidgetName; return `widget-name-${this.cmsWidgetName}`;
}, },
routerParams() { routerParams() {
return routerParams; return routerParams;
} }
} }
} };

View file

@ -1,5 +1,5 @@
import baseMixin from '@/mixins/base-mixin'; import baseMixin from '@/mixins/base-mixin';
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
describe('base-mixin', () => { describe('base-mixin', () => {
it('should set and get cms content', () => { it('should set and get cms content', () => {

View file

@ -3,7 +3,7 @@ import { useMainStore } from '@/store';
export default { export default {
methods: { methods: {
hasSettingEqualTo(settingName, settingValue) { hasSettingEqualTo(settingName, settingValue) {
return useMainStore().experimentSettings[settingName] == settingValue; return useMainStore().experimentSettings[settingName] === settingValue;
}, },
hasSetting(settingName) { hasSetting(settingName) {
return Object.hasOwn(useMainStore().experimentSettings, settingName); return Object.hasOwn(useMainStore().experimentSettings, settingName);

View file

@ -11,14 +11,10 @@ export default {
return partsOrQuestions?.some((pq) => pq.parts?.length > 1); return partsOrQuestions?.some((pq) => pq.parts?.length > 1);
}, },
hasChildPartQuestions(partsOrQuestions) { hasChildPartQuestions(partsOrQuestions) {
return partsOrQuestions?.some((pq) => { return partsOrQuestions?.some((pq) => pq.parts?.some((part) => part.childPartQuestions?.length > 0));
return pq.parts?.some((part) => part.childPartQuestions?.length > 0);
});
}, },
hasCapabilityQuestions(partsOrQuestions) { hasCapabilityQuestions(partsOrQuestions) {
return partsOrQuestions?.some((pq) => { return partsOrQuestions?.some((pq) => pq.parts?.some((part) => part.requiresCapabilityQuestions === true));
return pq.parts?.some((part) => part.requiresCapabilityQuestions === true);
});
}, },
// method to only include keys listed for lineItems.glassParts in // method to only include keys listed for lineItems.glassParts in
@ -54,8 +50,8 @@ export default {
]; ];
return ( return (
orderedVehicleQuestionPages.indexOf(currentPage) - orderedVehicleQuestionPages.indexOf(currentPage)
orderedVehicleQuestionPages.indexOf(issPage) - orderedVehicleQuestionPages.indexOf(issPage)
); );
}, },
currentPageComesBeforePage(currentPage = this.$route.query.issPage, issPage) { currentPageComesBeforePage(currentPage = this.$route.query.issPage, issPage) {
@ -75,18 +71,18 @@ export default {
alreadyAnsweredQuestions?.forEach((answeredGlass) => { alreadyAnsweredQuestions?.forEach((answeredGlass) => {
// if answeredGlass lacks any of these properties then exit // if answeredGlass lacks any of these properties then exit
if ( if (
!answeredGlass.glassLocation || !answeredGlass.glassLocation
!answeredGlass.glassName || || !answeredGlass.glassName
!answeredGlass.answeredQuestions || || !answeredGlass.answeredQuestions
(!answeredGlass.result && !answeredGlass.partNum) || (!answeredGlass.result && !answeredGlass.partNum)
) { ) {
return; return;
} }
// test if glass parts match // test if glass parts match
if ( if (
glass.glassLocation === answeredGlass.glassLocation && glass.glassLocation === answeredGlass.glassLocation
glass.glassName === answeredGlass.glassName && glass.glassName === answeredGlass.glassName
) { ) {
let answerString = ''; let answerString = '';
@ -98,12 +94,10 @@ export default {
// determine which answer was previously chosen // determine which answer was previously chosen
const chosenAns = glass.questions[ const chosenAns = glass.questions[
answeredQuestion.questionNum - 1 answeredQuestion.questionNum - 1
].answers.find((a) => { ].answers.find((a) => (
return ( a.answerText.toUpperCase()
a.answerText.toUpperCase() === === answeredQuestion.selectedAnswerText.toUpperCase()
answeredQuestion.selectedAnswerText.toUpperCase() ));
);
});
// set the answerString to use for answerSelected // set the answerString to use for answerSelected
if (chosenAns.nextQuestionSequence) { if (chosenAns.nextQuestionSequence) {
answerString = `${answeredQuestion.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`; answerString = `${answeredQuestion.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`;
@ -112,8 +106,8 @@ export default {
} }
// mark this question as answered (question-chain will read this) // mark this question as answered (question-chain will read this)
glass.questions[answeredQuestion.questionNum - 1].answerSelected = glass.questions[answeredQuestion.questionNum - 1].answerSelected
answerString; = answerString;
// mark this question as suppressed if needed (question-chain uses this) // mark this question as suppressed if needed (question-chain uses this)
if (answeredQuestion.suppressThisQuestion) { if (answeredQuestion.suppressThisQuestion) {
glass.questions[ glass.questions[
@ -132,8 +126,8 @@ export default {
// add answerData to current glass // add answerData to current glass
glass.answerData = { glass.answerData = {
answerResult: answerResult, answerResult,
answeredQuestions: answeredGlass.answeredQuestions, answeredQuestions: answeredGlass.answeredQuestions
}; };
} }
}); });
@ -252,8 +246,8 @@ export default {
// if the duplicate is 1ST question in array, set indexToSuppressTo // if the duplicate is 1ST question in array, set indexToSuppressTo
if (questionIndex === 0) { if (questionIndex === 0) {
if ( if (
!indexToSuppressTo || !indexToSuppressTo
matchedAnswer.nextQuestionSequence < indexToSuppressTo || matchedAnswer.nextQuestionSequence < indexToSuppressTo
) { ) {
indexToSuppressTo = matchedAnswer.nextQuestionSequence; indexToSuppressTo = matchedAnswer.nextQuestionSequence;
} }
@ -265,8 +259,8 @@ export default {
q.answers.forEach((a) => { q.answers.forEach((a) => {
// revert any previously set nextQuestion logic modifications // revert any previously set nextQuestion logic modifications
if ( if (
a.originalNextQuestionSequence === a.originalNextQuestionSequence
question.questionSequence === question.questionSequence
) { ) {
// restore original nextQuestionSequence // restore original nextQuestionSequence
a.nextQuestionSequence = a.originalNextQuestionSequence; a.nextQuestionSequence = a.originalNextQuestionSequence;
@ -283,16 +277,16 @@ export default {
// update questions that lead to duplicated question // update questions that lead to duplicated question
if (matchedAnswer.nextQuestionSequence) { if (matchedAnswer.nextQuestionSequence) {
a.originalNextQuestionSequence = a.originalNextQuestionSequence
a.nextQuestionSequence; = a.nextQuestionSequence;
a.nextQuestionSequence = a.nextQuestionSequence
matchedAnswer.nextQuestionSequence; = matchedAnswer.nextQuestionSequence;
} else { } else {
a.originalNextQuestionSequence = a.originalNextQuestionSequence
a.nextQuestionSequence; = a.nextQuestionSequence;
a.nextQuestionSequence = null; a.nextQuestionSequence = null;
a.originalAnswerResult = a.originalAnswerResult
a.originalAnswerResult || a.answerResult; = a.originalAnswerResult || a.answerResult;
a.answerResult = matchedAnswer.answerResult; a.answerResult = matchedAnswer.answerResult;
} }
} }
@ -303,9 +297,7 @@ export default {
question.suppressThisQuestion = true; question.suppressThisQuestion = true;
// are there any questions left that are not suppressed? // are there any questions left that are not suppressed?
const remainingQuestions = glass.questions.filter((q) => { const remainingQuestions = glass.questions.filter((q) => !q.suppressThisQuestion);
return !q.suppressThisQuestion;
});
if (remainingQuestions.length < 1) { if (remainingQuestions.length < 1) {
// this is the final answer for this glass piece // this is the final answer for this glass piece
@ -315,14 +307,14 @@ export default {
questionText: question.questionText, questionText: question.questionText,
selectedAnswerText: matchedAnswer.answerText, selectedAnswerText: matchedAnswer.answerText,
questionNum: question.questionSequence, questionNum: question.questionSequence,
suppressThisQuestion: question.suppressThisQuestion, suppressThisQuestion: question.suppressThisQuestion
}; };
// set the answerData (used as indicator that it has been already answered) // set the answerData (used as indicator that it has been already answered)
glass.answerData = { glass.answerData = {
answerResult: matchedAnswer.nextQuestionSequence answerResult: matchedAnswer.nextQuestionSequence
? matchedAnswer.nextQuestionSequence ? matchedAnswer.nextQuestionSequence
: matchedAnswer.answerResult, : matchedAnswer.answerResult,
answeredQuestions: [answeredQuestionObj], answeredQuestions: [answeredQuestionObj]
}; };
// suppress this glass piece because it has an answer // 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 // 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 // set final answer data for the current answered glass part
self.questionsData[answer.index].answerData = { self.questionsData[answer.index].answerData = {
answerResult: answer.answerResult, answerResult: answer.answerResult,
answeredQuestions: answer.answeredQuestions, answeredQuestions: answer.answeredQuestions
}; };
// this part has been fully answered, so advance to next part's question chain // 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 currentPage = self.$route.query.issPage;
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions); const hasPartQuestions = this.hasPartQuestions(partsOrQuestions);
const hasGlassLocationWithMultipleParts = const hasGlassLocationWithMultipleParts
this.hasGlassLocationWithMultipleParts(partsOrQuestions); = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, issPageValues.PART_QUESTIONS)) if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, issPageValues.PART_QUESTIONS)) {
{ self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, self.$route, {}, {}, { partsOrQuestions });
self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS, self.$route, } else if (hasGlassLocationWithMultipleParts && this.currentPageComesBeforePage(currentPage, issPageValues.VEHICLE_PARTS)) {
{},
{},
{ partsOrQuestions: partsOrQuestions }
);
} else if (hasGlassLocationWithMultipleParts && this.currentPageComesBeforePage(currentPage, issPageValues.VEHICLE_PARTS))
{
// if multiple parts on any glass // if multiple parts on any glass
// go to vehicle-parts page and pass the partsData // go to vehicle-parts page and pass the partsData
self.$router.navigate( self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
self.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
self.$route, self.$route,
{}, {},
{}, {},
{ partsOrQuestions: partsOrQuestions } { partsOrQuestions });
);
} else if ( } else if (
hasChildPartQuestions && hasChildPartQuestions
this.currentPageComesBeforePage(currentPage, issPageValues.MOLDING_QUESTIONS) && this.currentPageComesBeforePage(currentPage, issPageValues.MOLDING_QUESTIONS)
) { ) {
// if any childpart questions // if any childpart questions
// go to molding-questions page and pass the partsData // go to molding-questions page and pass the partsData
self.$router.navigate( self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
self.navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
self.$route, self.$route,
{}, {},
{}, {},
{ partsOrQuestions: partsOrQuestions } { partsOrQuestions });
);
} else if ( } else if (
hasCapabilityQuestions && hasCapabilityQuestions
this.currentPageComesBeforePage(currentPage, issPageValues.CAPABILITY_QUESTIONS) && this.currentPageComesBeforePage(currentPage, issPageValues.CAPABILITY_QUESTIONS)
) { ) {
// if has capability questions // if has capability questions
// go to capability-questions page and pass the partsData // go to capability-questions page and pass the partsData
// mimic part-questions page data for consistency // mimic part-questions page data for consistency
for (let partOrQuestion of partsOrQuestions) { for (const partOrQuestion of partsOrQuestions) {
if (this.hasCapabilityQuestions([partOrQuestion])) { 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) => { capabilityQuestionsForGlassLocation.forEach((question) => {
question.answers = question.answers.map((answer) => { question.answers = question.answers.map((answer) => ({
return { ...answer,
...answer, answerResult: answer.answerResult1
answerResult: answer.answerResult1 }));
};
});
}); });
partOrQuestion.capabilityQuestions = capabilityQuestionsForGlassLocation; partOrQuestion.capabilityQuestions = capabilityQuestionsForGlassLocation;
} }
} }
self.$router.navigate( self.$router.navigate(self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
self.navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
self.$route, self.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
} else { } else {
// if single parts only // if single parts only
const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions); const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions);
@ -435,28 +412,27 @@ export default {
// save to store lineItems.glassParts // save to store lineItems.glassParts
useMainStore().updateGlassParts(collectedGlassParts); 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) { navigateBack(vm) {
const self = vm ?? this; const self = vm ?? this;
const partsOrQuestions = ( const partsOrQuestions = (
self.mainStore.pageData(issPageValues.CAPABILITY_QUESTIONS) ?? self.mainStore.pageData(issPageValues.CAPABILITY_QUESTIONS)
self.mainStore.pageData(issPageValues.MOLDING_QUESTIONS) ?? ?? self.mainStore.pageData(issPageValues.MOLDING_QUESTIONS)
self.mainStore.pageData(issPageValues.VEHICLE_PARTS) ?? ?? self.mainStore.pageData(issPageValues.VEHICLE_PARTS)
self.mainStore.pageData(issPageValues.PART_QUESTIONS) ?? self.mainStore.pageData(issPageValues.PART_QUESTIONS)
)?.partsOrQuestions; )?.partsOrQuestions;
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions); const hasPartQuestions = this.hasPartQuestions(partsOrQuestions);
const hasGlassLocationWithMultipleParts = const hasGlassLocationWithMultipleParts
this.hasGlassLocationWithMultipleParts(partsOrQuestions); = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions); const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
let backNavigationScenario = ''; let backNavigationScenario = '';
if (self.mainStore.order.damage.isRepair) { if (self.mainStore.order.damage.isRepair) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_REPAIR; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_REPAIR;
} } else {
else {
backNavigationScenario = self.mainStore.vehicle.vin backNavigationScenario = self.mainStore.vehicle.vin
? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS ? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS
: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS; : navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS;
@ -464,24 +440,24 @@ export default {
const currentPage = self.$route.query.issPage; const currentPage = self.$route.query.issPage;
if ( if (
hasCapabilityQuestions && hasCapabilityQuestions
this.currentPageComesAfterPage(currentPage, issPageValues.CAPABILITY_QUESTIONS) && this.currentPageComesAfterPage(currentPage, issPageValues.CAPABILITY_QUESTIONS)
) { ) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS;
} else if ( } else if (
hasChildPartQuestions && hasChildPartQuestions
this.currentPageComesAfterPage(currentPage, issPageValues.MOLDING_QUESTIONS) && this.currentPageComesAfterPage(currentPage, issPageValues.MOLDING_QUESTIONS)
) { ) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_MOLDING_QUESTIONS;
} else if ( } else if (
hasGlassLocationWithMultipleParts && hasGlassLocationWithMultipleParts
this.currentPageComesAfterPage(currentPage, issPageValues.VEHICLE_PARTS) && this.currentPageComesAfterPage(currentPage, issPageValues.VEHICLE_PARTS)
) { ) {
backNavigationScenario = backNavigationScenario
navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE; = navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE;
} else if ( } else if (
hasPartQuestions && hasPartQuestions
this.currentPageComesAfterPage(currentPage, issPageValues.PART_QUESTIONS) && this.currentPageComesAfterPage(currentPage, issPageValues.PART_QUESTIONS)
) { ) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS; backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS;
} }

View file

@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import { setupMocksForJsFiles, getMountOptions } from '@/helpers/unit-test-helper.js'; import { setupMocksForJsFiles, getMountOptions } from '@/helpers/unit-test-helper.js';
import { issPageValues } from '@/router/router-constants/issPage-values'; import { issPageValues } from '@/router/router-constants/issPage-values';
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios'; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
import {useMainStore} from '@/store'; import { useMainStore } from '@/store';
describe('vehicle-questions-mixin', () => { describe('vehicle-questions-mixin', () => {
afterEach(() => { afterEach(() => {
@ -290,8 +290,7 @@ describe('vehicle-questions-mixin', () => {
[issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true], [issPageValues.PART_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true],
[issPageValues.MOLDING_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true] [issPageValues.MOLDING_QUESTIONS, issPageValues.CAPABILITY_QUESTIONS, true]
]; ];
test.each(testCases)( test.each(testCases)('%s comes before %s is %s',
'%s comes before %s is %s',
(currentPage, nextPage, expectedResult) => { (currentPage, nextPage, expectedResult) => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -301,8 +300,7 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(result).toEqual(expectedResult); expect(result).toEqual(expectedResult);
} });
);
}); });
describe('currentPageComesAfterPage', () => { describe('currentPageComesAfterPage', () => {
@ -390,11 +388,9 @@ describe('vehicle-questions-mixin', () => {
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
// Act // Act
const returnedGlass = await wrapper.vm.setupInitialData( const returnedGlass = await wrapper.vm.setupInitialData(glass,
glass,
i, i,
alreadyAnsweredQuestions alreadyAnsweredQuestions);
);
// Assert // Assert
expect(returnedGlass.answerData).toMatchObject({ answerResult: 'WKT D1106 C' }); expect(returnedGlass.answerData).toMatchObject({ answerResult: 'WKT D1106 C' });
@ -963,22 +959,12 @@ describe('vehicle-questions-mixin', () => {
// Act // Act
wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm); wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm);
const duplicatedQuestion = wrapper.vm.questionsData[1].questions[2]; const duplicatedQuestion = wrapper.vm.questionsData[1].questions[2];
const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter((a) => { const duplicatedQuestionAnswer = duplicatedQuestion.answers.filter((a) => a.selected);
return a.selected; const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter((a) => a.originalNextQuestionSequence);
});
const answerToTest = wrapper.vm.questionsData[1].questions[0].answers.filter(
(a) => {
return a.originalNextQuestionSequence;
}
);
// Assert // Assert
expect(answerToTest[0].originalNextQuestionSequence).toEqual( expect(answerToTest[0].originalNextQuestionSequence).toEqual(duplicatedQuestion.questionSequence);
duplicatedQuestion.questionSequence expect(answerToTest[0].nextQuestionSequence).toEqual(duplicatedQuestionAnswer[0].nextQuestionSequence);
);
expect(answerToTest[0].nextQuestionSequence).toEqual(
duplicatedQuestionAnswer[0].nextQuestionSequence
);
}); });
describe('and the duplicate was the first question for that part', () => { 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); wrapper.vm.handleAnswerUpdates(answerNo, '', wrapper.vm);
// Assert // Assert
expect( expect(wrapper.vm.questionsData[1].questions[0].suppressThisQuestion).toBeTruthy();
wrapper.vm.questionsData[1].questions[0].suppressThisQuestion expect(wrapper.vm.questionsData[1].questions[1].suppressThisQuestion).toBeTruthy();
).toBeTruthy(); expect(wrapper.vm.questionsData[1].questions[2].suppressThisQuestion).toBeFalsy();
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 questionsToTest = wrapper.vm.questionsData[1].questions;
const answerLeadingToDuplicate = questionsToTest[0].answers[1]; const answerLeadingToDuplicate = questionsToTest[0].answers[1];
const duplicateQuestion = questionsToTest[2]; const duplicateQuestion = questionsToTest[2];
const answerInDuplicateQuestion = duplicateQuestion.answers.filter((a) => { const answerInDuplicateQuestion = duplicateQuestion.answers.filter((a) => a.selected);
return a.selected;
});
// Assert // Assert
expect(answerLeadingToDuplicate.answerResult).toEqual( expect(answerLeadingToDuplicate.answerResult).toEqual(answerInDuplicateQuestion[0].answerResult);
answerInDuplicateQuestion[0].answerResult
);
expect(answerLeadingToDuplicate.originalAnswerResult).toBeFalsy(); expect(answerLeadingToDuplicate.originalAnswerResult).toBeFalsy();
expect(answerLeadingToDuplicate.nextQuestionSequence).toEqual(null); expect(answerLeadingToDuplicate.nextQuestionSequence).toEqual(null);
expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual( expect(answerLeadingToDuplicate.originalNextQuestionSequence).toEqual(duplicateQuestion.questionSequence);
duplicateQuestion.questionSequence
);
}); });
}); });
}); });
@ -1244,7 +1218,7 @@ describe('vehicle-questions-mixin', () => {
]; ];
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1252,13 +1226,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
test('multiple glass locations have part questions => go to parts-questions', async () => { test('multiple glass locations have part questions => go to parts-questions', async () => {
@ -1359,7 +1331,7 @@ describe('vehicle-questions-mixin', () => {
]; ];
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1367,13 +1339,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
test('multiple glass locations selected, one has part question => go to parts-questions', async () => { 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({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1474,13 +1444,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
test('a selected glass location has part questions and multiple parts => go to parts-questions', async () => { 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({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1629,13 +1597,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
}); });
@ -1669,7 +1635,7 @@ describe('vehicle-questions-mixin', () => {
]; ];
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1677,13 +1643,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
test('multiple glass locations selected, one of them has multiple parts => go to vehicle parts', async () => { 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({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1789,13 +1753,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
test('multiple glass locations selected, multiple have multiple parts => go to vehicle-parts', async () => { 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({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -1967,13 +1929,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
}); });
@ -2018,7 +1978,7 @@ describe('vehicle-questions-mixin', () => {
]; ];
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -2026,13 +1986,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
}); });
@ -2060,7 +2018,7 @@ describe('vehicle-questions-mixin', () => {
]; ];
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
partsOrQuestions: partsOrQuestions partsOrQuestions
}); });
// Act // Act
@ -2068,13 +2026,11 @@ describe('vehicle-questions-mixin', () => {
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
wrapper.vm.$route, wrapper.vm.$route,
{}, {},
{}, {},
{ partsOrQuestions } { partsOrQuestions });
);
}); });
}); });
}); });
@ -2089,10 +2045,8 @@ describe('vehicle-questions-mixin', () => {
wrapper.vm.navigateBack(); wrapper.vm.navigateBack();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_REPAIR,
navigationScenarios.CLICKED_BACK_WITH_REPAIR, { query: { issPage: issPageValues.COVERAGE_STATEMENT } });
{ 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', () => { 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(); wrapper.vm.navigateBack();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE,
navigationScenarios.CLICKED_BACK_WITH_MULTIPLE_PARTS_TO_CHOOSE, { query: { issPage: issPageValues.MOLDING_QUESTIONS } });
{ query: { issPage: issPageValues.MOLDING_QUESTIONS } }
);
}); });
test('current page is molding questions and there are part questions and capability questions => go to part-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(); wrapper.vm.navigateBack();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS, { query: { issPage: issPageValues.MOLDING_QUESTIONS } });
{ query: { issPage: issPageValues.MOLDING_QUESTIONS } }
);
}); });
}); });
}); });
function setupMocks({ issPage = issPageValues.VIN_LOOKUP, hasVin, carId }) { function setupMocks({ issPage = issPageValues.VIN_LOOKUP }) {
const baseMixin = setupMocksForJsFiles({ const baseMixin = setupMocksForJsFiles({
actionList: [ actionList: [
{ {
@ -2168,8 +2118,8 @@ function setupMocks({ issPage = issPageValues.VIN_LOOKUP, hasVin, carId }) {
}; };
const store = useMainStore(); const store = useMainStore();
let actionResult = []; const actionResult = [];
store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({data: actionResult})); store.getCapabilityQuestions.mockImplementation(() => Promise.resolve({ data: actionResult }));
const wrapper = shallowMount(mockVehicleQuestionComponent, mocks); const wrapper = shallowMount(mockVehicleQuestionComponent, mocks);

View file

@ -5,7 +5,7 @@ export default {
methods: { methods: {
async navigateForwardWithSingleCarMatch() { async navigateForwardWithSingleCarMatch() {
const result = await useMainStore().getPartsOrQuestions(); const result = await useMainStore().getPartsOrQuestions();
const partsOrQuestions = result.data.partsOrQuestions; const { partsOrQuestions } = result.data;
vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this); vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this);
} }

View file

@ -4,27 +4,6 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import { useMainStore } from '@/store'; 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() { function setupMocks() {
const mocks = getMountOptions({ const mocks = getMountOptions({
router: { router: {
@ -40,3 +19,24 @@ function setupMocks() {
return { wrapper }; 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();
});
});
});