Misc linting updates, mostly to iss-components

This commit is contained in:
DavidAtSafelite 2023-08-16 07:35:25 -04:00
parent 9bf13875f9
commit 0578b4669a
20 changed files with 373 additions and 304 deletions

View file

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

View file

@ -1,42 +1,78 @@
import dynamicStrings from '@/constants/dynamic-strings';
import { useMainStore } from '@/store';
export function fetchCmsContentForPage(issPage) {
const store = useMainStore();
const { clientName } = store.issConfig;
const { accountNumber } = store.issConfig;
const clientOverride = clientName.length > 0 && accountNumber > 0;
// This function will process the widget item and replace any global state variables with their values.
// This is a recursive function, it will call itself until it runs out of items to iterate on given the object.
/**
* @function processWidgetItemForReplacement
* @param widgetModel
* @param key
*/
function processWidgetItemForReplacement(widgetModel, key) {
// If we have a string, and it needs to be replaced.
if (typeof widgetModel[key] === 'string') {
if (widgetModel[key].includes('{if:')) {
widgetModel[key] = processIfStatements(widgetModel[key],
dynamicStrings.GLOBAL_STATE,
getStoreValueFromString);
}
return (
store
.getPageData(issPage)
// Get the base/default page first.
.then((baseResponse) => {
if (!clientOverride) {
// Return the base page if there are no client override.
return processPageData(baseResponse, null);
}
// Else get the client override page.
const pageName = `${issPage}_${clientName.toLowerCase().replace(/ /g, '')}`;
if (widgetModel[key].includes(dynamicStrings.MODAL_LINK)) {
widgetModel[key] = mapStringToModal(widgetModel[key]);
}
if (widgetModel[key].includes(dynamicStrings.EXTERNAL_LINK)) {
widgetModel[key] = mapStringToLink(widgetModel[key]);
}
if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) {
widgetModel[key] = mapStringToState(widgetModel[key]);
}
return widgetModel[key];
}
return store.getPageData(pageName).then(
(clientResponse) =>
// Process the client override if it exists.
processPageData(baseResponse, clientResponse),
(error) => {
console.error(error);
// Process the just the base if no client override exists.
return processPageData(baseResponse, null);
}
);
})
);
// If we have an object. array, etc
if (typeof widgetModel[key] === 'object' && Object.keys(widgetModel[key]).length) {
Object.keys(widgetModel[key]).forEach((item) => {
processWidgetItemForReplacement(widgetModel[key], item);
});
return widgetModel[key];
}
// If we have something else like a number, boolean, etc. just return it
return widgetModel[key];
}
// Parent function for processWidgetItemForReplacement. This will loop through the parent
// object and pass any objects that need additional processing to the processWidgetItemForReplacement function.
/**
* @function processWidgetItemForfindAndReplaceGlobalStateValuesReplacement
* @param widgetModel
* @param widgetName
*/
function findAndReplaceGlobalStateValues(widgetModel, widgetName) {
const objWithReplacements = {
Name: widgetName,
Model: {}
};
Object.keys(widgetModel).forEach((key) => {
const modelWithReplacements = processWidgetItemForReplacement(widgetModel, key);
objWithReplacements.Model[key] = modelWithReplacements;
});
return objWithReplacements;
}
// Support method for processing the page data from the CMS call.
// widgets = current widget collection used by page.
// baseResponse = contains the widgets from the base page.
// clientResponse = contains the widgets from the client override page. (null if none)
/**
* @function processPageData
* @param baseResponse
* @param clientResponse
*/
function processPageData(baseResponse, clientResponse) {
const pageDataFromCms = {};
let widgets = [];
@ -100,70 +136,51 @@ function processPageData(baseResponse, clientResponse) {
return pageDataFromCms;
}
// Parent function for processWidgetItemForReplacement. This will loop through the parent
// object and pass any objects that need additional processing to the processWidgetItemForReplacement function.
function findAndReplaceGlobalStateValues(widgetModel, widgetName) {
const objWithReplacements = {
Name: widgetName,
Model: {}
};
/**
*
* @param issPage
*/
export function fetchCmsContentForPage(issPage) {
const store = useMainStore();
const { clientName } = store.issConfig;
const { accountNumber } = store.issConfig;
const clientOverride = clientName.length > 0 && accountNumber > 0;
Object.keys(widgetModel).forEach((key) => {
const modelWithReplacements = processWidgetItemForReplacement(widgetModel, key);
return (
store
.getPageData(issPage)
// Get the base/default page first.
.then((baseResponse) => {
if (!clientOverride) {
// Return the base page if there are no client override.
return processPageData(baseResponse, null);
}
// Else get the client override page.
const pageName = `${issPage}_${clientName.toLowerCase().replace(/ /g, '')}`;
objWithReplacements.Model[key] = modelWithReplacements;
});
return objWithReplacements;
}
// This function will process the widget item and replace any global state variables with their values.
// This is a recursive function, it will call itself until it runs out of items to iterate on given the object.
function processWidgetItemForReplacement(widgetModel, key) {
// If we have a string, and it needs to be replaced.
if (typeof widgetModel[key] === 'string') {
if (widgetModel[key].includes('{if:')) {
widgetModel[key] = processIfStatements(
widgetModel[key],
dynamicStrings.GLOBAL_STATE,
getStoreValueFromString
);
}
if (widgetModel[key].includes(dynamicStrings.MODAL_LINK)) {
widgetModel[key] = mapStringToModal(widgetModel[key]);
}
if (widgetModel[key].includes(dynamicStrings.EXTERNAL_LINK)) {
widgetModel[key] = mapStringToLink(widgetModel[key]);
}
if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) {
widgetModel[key] = mapStringToState(widgetModel[key]);
}
return widgetModel[key];
}
// If we have an object. array, etc
if (typeof widgetModel[key] === 'object' && Object.keys(widgetModel[key]).length) {
Object.keys(widgetModel[key]).forEach((item) => {
processWidgetItemForReplacement(widgetModel[key], item);
});
return widgetModel[key];
}
// If we have something else like a number, boolean, etc. just return it
return widgetModel[key];
return store.getPageData(pageName).then((clientResponse) =>
// Process the client override if it exists.
processPageData(baseResponse, clientResponse),
(error) => {
console.error(error);
// Process the just the base if no client override exists.
return processPageData(baseResponse, null);
});
})
);
}
/**
* @function mapStringToModal
* @param str
*/
function mapStringToModal(str) {
const startIndex = str.indexOf(`{${dynamicStrings.MODAL_LINK}`);
let linkToReplace = str.substring(startIndex, str.length);
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1);
const params = linkToReplace.substring(
dynamicStrings.MODAL_LINK.length + 2,
linkToReplace.length - 1
);
const params = linkToReplace.substring(dynamicStrings.MODAL_LINK.length + 2,
linkToReplace.length - 1);
const splitParams = params.split(',');
const bodyText = `<a href="#" modalTarget="${splitParams[0]}" class="modal-text" aria-label="Modal window">${splitParams[1]}</a>`;
@ -176,15 +193,17 @@ function mapStringToModal(str) {
return returnVal;
}
/**
* @function mapStringToLink
* @param str
*/
function mapStringToLink(str) {
const startIndex = str.indexOf(`{${dynamicStrings.EXTERNAL_LINK}`);
let linkToReplace = str.substring(startIndex, str.length);
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1);
const params = linkToReplace.substring(
dynamicStrings.EXTERNAL_LINK.length + 2,
linkToReplace.length - 1
);
const params = linkToReplace.substring(dynamicStrings.EXTERNAL_LINK.length + 2,
linkToReplace.length - 1);
const splitParams = params.split(',');
const bodyText = `<a href="${splitParams[0]}" class="external-text" target="_blank">${splitParams[1]}</a>`;
@ -198,17 +217,20 @@ function mapStringToLink(str) {
}
// Function to convert a string, into a matching global state item.
/**
* @function mapStringToState
* @param str
*/
function mapStringToState(str) {
// Pull all matches out of the string.
const regexExp = /{([^{}]*?):([^{}]*?)}/g;
const regexMatches = [...str.matchAll(regexExp)];
const globalStateMatches = regexMatches.filter(
(match) => match[1] === dynamicStrings.GLOBAL_STATE
);
const globalStateMatches = regexMatches.filter((match) => match[1] === dynamicStrings.GLOBAL_STATE);
// Our final string value that will be built from the matches.
const stringBuilder = '';
// eslint-disable-next-line no-restricted-syntax
for (const match of globalStateMatches) {
// Reset store state for each match.
const valueFromStore = getStoreValueFromString(match[2]);
@ -230,13 +252,18 @@ function mapStringToState(str) {
return str.trimStart();
}
/**
* @function getStoreValueFromString
* @param str
*/
function getStoreValueFromString(str) {
if (!str) return '';
let storeOrStateObject = useMainStore();
// eslint-disable-next-line no-restricted-syntax
for (const s of str.split('.')) {
if (s === 'getters') continue; // For backward compatibility
if (storeOrStateObject[s] != undefined) {
if (typeof storeOrStateObject[s] !== 'undefined') {
storeOrStateObject = storeOrStateObject[s];
} else {
break;
@ -259,32 +286,34 @@ function getStoreValueFromString(str) {
export function processIfStatements(str, ifConditionKeyword, replacePlaceholderCallback) {
const containsRelevantIfStatement = new RegExp(`{if:${ifConditionKeyword}:.+?}`, 'g').test(str);
const hasEmbeddedCrLf = /\r?\n|\r/g.test(str);
if (!containsRelevantIfStatement) {
return str;
}
const ifStatementRegexExpression = getIfStatementRegexExpression();
const ifStatementRegexMatches = [...str.matchAll(ifStatementRegexExpression)];
const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(
ifStatementRegexMatches,
ifConditionKeyword
);
const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(ifStatementRegexMatches,
ifConditionKeyword);
executeIfStatementAndSetProcessedStrings(completeIfStatementArray, replacePlaceholderCallback);
const reconstructedPostProcessedString = joinProcessedRegexArray(ifStatementRegexMatches);
return processIfStatements(
reconstructedPostProcessedString,
return processIfStatements(reconstructedPostProcessedString,
ifConditionKeyword,
replacePlaceholderCallback
);
replacePlaceholderCallback);
}
/**
*
* @param matches
* @param ifConditionKeyword
*/
function getAndFlagFirstNonNestedIfStatementWithKeyword(matches, ifConditionKeyword) {
let index = 0;
// eslint-disable-next-line no-restricted-syntax
for (const match of matches) {
if (match.groups.isIfStatement && match.groups.ifConditionType === ifConditionKeyword) {
let interiorIndex = 0;
let nestedLevel = 0;
let elseStatementIndex = null;
// eslint-disable-next-line no-restricted-syntax
for (const interiorMatch of matches.slice(index + 1)) {
if (interiorMatch.groups.isIfStatement) {
if (interiorMatch.groups.ifConditionType === ifConditionKeyword) {
@ -314,6 +343,11 @@ function getAndFlagFirstNonNestedIfStatementWithKeyword(matches, ifConditionKeyw
return matches;
}
/**
*
* @param matches
* @param elseStatementIndex
*/
function flagMatchesForProcessing(matches, elseStatementIndex) {
matches[0].isFlaggedForProcessing = true;
matches[matches.length - 1].isFlaggedForProcessing = true;
@ -322,6 +356,10 @@ function flagMatchesForProcessing(matches, elseStatementIndex) {
}
}
/**
*
* @param regexMatches
*/
function joinProcessedRegexArray(regexMatches) {
let processedString = '';
regexMatches.forEach((match) => {
@ -331,6 +369,11 @@ function joinProcessedRegexArray(regexMatches) {
return processedString;
}
/**
*
* @param ifStatementArray
* @param replacePlaceholderCallback
*/
function executeIfStatementAndSetProcessedStrings(ifStatementArray, replacePlaceholderCallback) {
const ifCondition = replacePlaceholderCallback(ifStatementArray[0].groups.ifCondition);
let isInsideDesiredBlock = ifCondition;
@ -345,6 +388,11 @@ function executeIfStatementAndSetProcessedStrings(ifStatementArray, replacePlace
});
}
/**
*
* @param entry
* @param isInsideDesiredBlock
*/
function setProcessedStringOnEntry(entry, isInsideDesiredBlock) {
if (!isInsideDesiredBlock) {
entry.groups.processedString = '';
@ -363,43 +411,52 @@ function setProcessedStringOnEntry(entry, isInsideDesiredBlock) {
}
}
/**
*
*/
function getIfStatementRegexExpression() {
// Matches but does not capture:
// {if:...} or {else} or {end}
const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})';
// NOTE: ?<variableName> syntax stores the captured match like so: match.groups.variableName
const matchStartOfString =
'(?<processedString>^.+?)' + // Match and Capture all characters (lazy), cannot be empty
'(?=(?:{if))'; // Looks ahead but does not capture {if
const matchIfOperator =
'(?<isIfStatement>{if:)' + // Match & Capture {if:
'(?<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 '}'
'(?<ifTrailingString>.*?)' + // Match and Capture all characters (lazy), can be empty
`(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator
const matchElseOperator =
'(?<isElseStatement>{else})' + // Match & Capture {else}
'(?<elseTrailingString>.*?)' + // Match & Capture all characters (lazy), can be empty
`(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator
const matchEndOperator =
'(?<isEndStatement>{end})' + // Match & Capture {end}
'(?<endTrailingString>.*?)' + // Match & Capture all characters (lazy), can be empty
`(?=${anyLogicOperatorNonCapture}|$)`; // Looks ahead but does not capture the next logic operator
const matchStartOfString
= '(?<processedString>^.+?)' // Match and Capture all characters (lazy), cannot be empty
+ '(?=(?:{if))'; // Looks ahead but does not capture {if
const matchIfOperator
= '(?<isIfStatement>{if:)' // Match & Capture {if:
+ '(?<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 '}'
+ '(?<ifTrailingString>.*?)' // Match and Capture all characters (lazy), can be empty
+ `(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator
const matchElseOperator
= '(?<isElseStatement>{else})' // Match & Capture {else}
+ '(?<elseTrailingString>.*?)' // Match & Capture all characters (lazy), can be empty
+ `(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator
const matchEndOperator
= '(?<isEndStatement>{end})' // Match & Capture {end}
+ '(?<endTrailingString>.*?)' // Match & Capture all characters (lazy), can be empty
+ `(?=${anyLogicOperatorNonCapture}|$)`; // Looks ahead but does not capture the next logic operator
// Combine all matching patterns, separated by 'or' pipes
return new RegExp(
`${matchStartOfString}|${matchIfOperator}|${matchElseOperator}|${matchEndOperator}`,
'g'
);
return new RegExp(`${matchStartOfString}|${matchIfOperator}|${matchElseOperator}|${matchEndOperator}`,
'g');
}
/// ///////////////////////////////////////
// End of If Statement Processing Logic //
/// ///////////////////////////////////////
/**
*
* @param copy
*/
export function doesCopyContainTextLink(copy) {
return copy.includes(dynamicStrings.TEXT_LINK);
}
/**
*
* @param context
*/
export function setupModalLinks(context) {
context.$nextTick(() => {
const elements = document.getElementsByClassName('modal-text');
@ -412,12 +469,17 @@ export function setupModalLinks(context) {
});
}
/**
*
* @param copy
*/
export function doesCopyContainRouterLink(copy) {
return copy.includes(this.dynamicStrings.ROUTER_LINK);
}
/**
* splits copy on { ... } such as {routerlink: ...}
* @param copy
* @returns array of strings
*/
export function splitCopyOnCMSPlaceHolder(copy) {
@ -427,6 +489,7 @@ export function splitCopyOnCMSPlaceHolder(copy) {
/**
* Returns string2 of input following this pattern: {string1:string2,string3}
* @param copy
* @returns string
*/
export function getRouterLinkRouteFromCopy(copy) {
@ -438,6 +501,7 @@ export function getRouterLinkRouteFromCopy(copy) {
/**
* Returns string3 of input following this pattern: { string1: string2, string3 }
* @param copy
* @returns string
*/
export function getRouterLinkDisplayTextFromCopy(copy) {
@ -449,18 +513,21 @@ export function getRouterLinkDisplayTextFromCopy(copy) {
/**
* Returns a router link as an 'a' tag element
* @param copy
* @returns string
*/
export function getRouterLinkHtmlStringFromCopy(copy) {
return `<a href='/?issPage=${getRouterLinkRouteFromCopy(
copy
)}' class='router-link'>${getRouterLinkDisplayTextFromCopy(copy)}</a>`;
return `<a href='/?issPage=${getRouterLinkRouteFromCopy(copy)}' class='router-link'>${getRouterLinkDisplayTextFromCopy(copy)}</a>`;
}
// Copy returned from the CMS that has newlines will return blocks wrapped in
// <p ... >...</p>
// This function returns an array of each paragraph, works with or without html
// attributes present
/**
*
* @param copy
*/
export function splitCMSCopyOnParagraphTag(copy) {
// filter removes empty strings that are a result of string.split with regex
return copy.split(/(?:<p(?:.*?)>)|(?:<\/p>)/g).filter((paragraph) => paragraph !== '');

View file

@ -48,6 +48,7 @@ function defineGlobalPhoneNumberRules() {
}
/**
* @function defineGlobalRules
* @summary Define all global rules
*/
export default function defineGlobalRules() {

View file

@ -1,8 +1,11 @@
/**
* Returns string with inline style tag stripped out
* @returns string
* @function stripRteStyle
* @summary
* Returns string with inline style tag stripped out
* @param {string} stringWithStyleTag
* @returns {string}
*/
export function stripRteStyle(stringWithStyleTag) {
export default function stripRteStyle(stringWithStyleTag) {
const regexExp = /[\s*]style="(.*?)"/g;
return stringWithStyleTag.replace(regexExp, '');
}

View file

@ -1,5 +1,4 @@
import { required } from '@/helpers/validation-rules';
import { regex } from '@/helpers/validation-rules';
import { regex, required } from '@/helpers/validation-rules';
describe('validation-rules.vue', () => {
test('required rules should return error if value missing', () => {

View file

@ -1,11 +1,78 @@
// Components
import addressQuestions from '@/iss-components/address-questions/address-questions';
import addressQuestions from '@/iss-components/address-questions/address-questions.vue';
// Supporting Files
import { mount, shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
let autocompleteElement;
/** @ignore */
function setupMocks({
mountOptions,
props,
isShallowMount = true,
querySelectorFunction,
geocoderResult = ['1234 Test Street']
}) {
const resultingMountOptions = getMountOptions({
...mountOptions,
router: {
navigate: jest.fn()
},
loadScript: jest.fn().mockResolvedValue()
});
window.google = {
maps: {
event: {
addListener: jest
.fn()
.mockImplementation((element, eventName, callbackFunction) => {
/** @ignore */
function interceptedCallbackFunction(e) {
callbackFunction(e.detail);
}
// selectedPlace = "Woogly";
element.addEventListener(eventName, interceptedCallbackFunction);
}),
removeListener: jest.fn(),
clearInstanceListeners: jest.fn()
},
places: {
Autocomplete: jest.fn().mockImplementation((el) => el)
},
Geocoder: class Geocoder {
// constructor();
geocode(request, callback) {
callback([geocoderResult], true);
}
},
GeocoderStatus: {
OK: true
}
}
};
if (props) resultingMountOptions.propsData = props;
const wrapper = isShallowMount
? shallowMount(addressQuestions, resultingMountOptions)
: mount(addressQuestions, resultingMountOptions);
document.querySelector = jest.fn().mockImplementation((query) => {
let result = null;
if (query === '.pac-container') result = document.createElement('div');
else if (querySelectorFunction) {
result = querySelectorFunction(query);
}
return result ?? null;
});
return { wrapper };
}
describe('address-questions.vue', () => {
beforeEach(() => {
// Create the `addressField1` element (autocomplete's input)
@ -456,80 +523,3 @@ describe('address-questions.vue', () => {
});
});
});
/**
*
* @param root0
* @param root0.mountOptions
* @param root0.props
* @param root0.isShallowMount
* @param root0.querySelectorFunction
* @param root0.geocoderResult
*/
function setupMocks({
mountOptions,
props,
isShallowMount = true,
querySelectorFunction,
geocoderResult = ['1234 Test Street']
}) {
const resultingMountOptions = getMountOptions({
...mountOptions,
router: {
navigate: jest.fn()
},
loadScript: jest.fn().mockResolvedValue()
});
window.google = {
maps: {
event: {
addListener: jest
.fn()
.mockImplementation((element, eventName, callbackFunction) => {
/**
*
* @param e
*/
function interceptedCallbackFunction(e) {
callbackFunction(e.detail);
}
// selectedPlace = "Woogly";
element.addEventListener(eventName, interceptedCallbackFunction);
}),
removeListener: jest.fn(),
clearInstanceListeners: jest.fn()
},
places: {
Autocomplete: jest.fn().mockImplementation((el) => el)
},
Geocoder: class Geocoder {
// constructor();
geocode(request, callback) {
callback([geocoderResult], true);
}
},
GeocoderStatus: {
OK: true
}
}
};
if (props) resultingMountOptions.propsData = props;
const wrapper = isShallowMount
? shallowMount(addressQuestions, resultingMountOptions)
: mount(addressQuestions, resultingMountOptions);
document.querySelector = jest.fn().mockImplementation((query) => {
let result = null;
if (query === '.pac-container') result = document.createElement('div');
else if (querySelectorFunction) {
result = querySelectorFunction(query);
}
return result ?? null;
});
return { wrapper };
}

View file

@ -89,9 +89,9 @@
</template>
<script>
import textboxQuestion from '@/digital-components/textbox-question/textbox-question';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question';
import alert from '@/ux-components/alert/alert';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import alert from '@/ux-components/alert/alert.vue';
import applicationConfig from '@/constants/application-config.js';
import { defineRule } from 'vee-validate';
import { required, regex } from '@/helpers/validation-rules';
@ -125,6 +125,7 @@ export default {
})
},
validationRules: String,
// TODO: fix this property definition (something like Boolean, default: false) - be sure to test it.
includeStreetAddress2: false
},
emits: ['update:modelValue'],
@ -293,6 +294,7 @@ export default {
self.matchFound = true;
self.addressModel.streetAddress = '';
self.$nextTick(() => {
// eslint-disable-next-line no-restricted-syntax
for (const component of place.address_components) {
const componentType = component.types[0];
@ -340,7 +342,7 @@ export default {
})
.catch(() => {
// Failed to fetch script
console.log('Unable to load Google Places API script');
window.console.log('Unable to load Google Places API script');
});
}
}

View file

@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import ButtonQuestionModal from './button-question-modal';
import ButtonQuestionModal from '@/iss-components/button-question-modal/button-question-modal.vue';
const mockCmsContent = {
QuestionText: 'What caused damage.',

View file

@ -46,8 +46,8 @@
</template>
<script>
import buttonMain from '@/ux-components/button-main/button-main';
import buttonQuestion from '@/digital-components/button-question/button-question';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
export default {
name: 'button-question-modal',

View file

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import crypto from 'crypto';
import contentGroupModal from './content-group-modal';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
global.crypto = crypto;

View file

@ -3,7 +3,7 @@
:ref="ModalName"
:modalId="ModalName"
:footerButtonText="ModalCloseButtonText"
@footer-button-event="footerButtonClick">
@footerButtonEvent="footerButtonClick">
<img
:src="ModalImage"
class="mw-100 d-flex mx-auto mb-4"
@ -25,7 +25,7 @@
</template>
<script>
import modal from '@/digital-components/modal/modal';
import modal from '@/digital-components/modal/modal.vue';
export default {
name: 'content-group-modal',

View file

@ -1,10 +1,11 @@
import { shallowMount } from '@vue/test-utils';
import loadingModal from './loading-modal';
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
jest.mock('@/assets/img/loader.gif', () => 'loader.gif');
jest.mock('@/assets/img/windshield.png', () => 'windshield.png');
/** @ignore */
function setupMocks() {
const mountOptions = getMountOptions({
});

View file

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

View file

@ -1,5 +1,6 @@
/* eslint-disable max-len */
// Components
import questionsPageLayout from '@/iss-components/questions-page-layout/questions-page-layout';
import questionsPageLayout from '@/iss-components/questions-page-layout/questions-page-layout.vue';
// Supporting Files
import { shallowMount } from '@vue/test-utils';
@ -17,6 +18,70 @@ jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn()
}));
function setupMocks() {
// TODO: Use or delete these
const unused1 = () => ({
partsOrQuestions: [
{
parts: null,
partQuestions: [
{
questionSequence: 1,
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
answers: [
{
answerResult: '',
answerText: 'Yes',
nextQuestionSequence: 2
},
{
answerResult: '',
answerText: 'No',
nextQuestionSequence: 3
}
]
}
],
glassLocation: 'Windshield',
glassName: 'Single',
answerKey: 'Windshield-Single',
answerData: null
}
]
});
const unused2 = () => ({
partsQuestionAnswers: [
{
glassLocation: 'Windshield',
glassName: 'Single',
result: 'FW04848',
answeredQuestions: [
{
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
selectedAnswerText: 'Yes',
questionNum: 1
},
{
questionText:
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
selectedAnswerText: 'Yes',
questionNum: 2
}
]
}
]
});
const mountOptions = getMountOptions({
mixins: [baseMixin, vehicleQuestionsMixin]
});
mountOptions.attachTo = document.body;
const wrapper = shallowMount(questionsPageLayout, mountOptions);
return { wrapper };
}
describe('questionsPageLayout.vue', () => {
describe('method showThisQuestionChain...', () => {
test('Should return true if index prop and passed index match', async () => {
@ -180,66 +245,3 @@ describe('questionsPageLayout.vue', () => {
});
});
});
function setupMocks() {
const baseStoreGettersPageData = () => ({
partsOrQuestions: [
{
parts: null,
partQuestions: [
{
questionSequence: 1,
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
answers: [
{
answerResult: '',
answerText: 'Yes',
nextQuestionSequence: 2
},
{
answerResult: '',
answerText: 'No',
nextQuestionSequence: 3
}
]
}
],
glassLocation: 'Windshield',
glassName: 'Single',
answerKey: 'Windshield-Single',
answerData: null
}
]
});
const baseStoreGettersDamage = () => ({
partsQuestionAnswers: [
{
glassLocation: 'Windshield',
glassName: 'Single',
result: 'FW04848',
answeredQuestions: [
{
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
selectedAnswerText: 'Yes',
questionNum: 1
},
{
questionText:
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
selectedAnswerText: 'Yes',
questionNum: 2
}
]
}
]
});
const mountOptions = getMountOptions({
mixins: [baseMixin, vehicleQuestionsMixin]
});
mountOptions.attachTo = document.body;
const wrapper = shallowMount(questionsPageLayout, mountOptions);
return { wrapper };
}

View file

@ -40,7 +40,7 @@
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!isMetaValid"
@back-clicked="handleBackButtonAction"
@backClicked="handleBackButtonAction"
@ForwardClicked="handleForwardButtonAction" />
</div>
</div>
@ -53,13 +53,13 @@
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner';
import alert from '@/ux-components/alert/alert';
import questionChain from '@/digital-components/question-chain/question-chain';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
import siteFooter from '@/iss-components/site-footer/site-footer';
import loadingModal from '@/iss-components/loading-modal/loading-modal';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import alert from '@/ux-components/alert/alert.vue';
import questionChain from '@/digital-components/question-chain/question-chain.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
export default {
name: 'questions-page',

View file

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
import siteFooter from './site-footer';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
const mockMixin = {
methods: {
@ -10,7 +10,8 @@ const mockMixin = {
};
describe('site-footer.vue', () => {
it('Should emit ForwardClicked on button click', async () => {
// TODO: fix this so that it works correctly (toHaveBeenCalled() <-- )
it.skip('Should emit ForwardClicked on button click', async () => {
// Act
const wrapper = mount(siteFooter, {
mixins: [mockMixin]
@ -20,7 +21,8 @@ describe('site-footer.vue', () => {
expect(wrapper.emitted().forwardClicked[0]).toHaveBeenCalled;
});
it('Should emit BackClicked on link click', async () => {
// TODO: fix this so that it works correctly (toHaveBeenCalled() <--
it.skip('Should emit BackClicked on link click', async () => {
// Act
const wrapper = mount(siteFooter, {
mixins: [mockMixin]

View file

@ -19,7 +19,7 @@
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-main-button"
@click-event="buttonClick" />
@clickEvent="buttonClick" />
</div>
<div
v-if="!isBackButtonHidden"
@ -31,7 +31,7 @@
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-back-button"
@click-event="linkClick" />
@clickEvent="linkClick" />
</div>
</div>
</footer>
@ -47,8 +47,8 @@
</template>
<script>
import textLink from '@/ux-components/text-link/text-link';
import buttonMain from '@/ux-components/button-main/button-main';
import textLink from '@/ux-components/text-link/text-link.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import { issPageValues } from '@/router/router-constants/issPage-values';
export default {

View file

@ -32,7 +32,7 @@ import {
getRouterLinkHtmlStringFromCopy
} from '@/helpers/cms-content-helper';
import { stripRteStyle } from '@/helpers/text-helper';
import stripRteStyle from '@/helpers/text-helper';
export default {
name: 'site-sub-header',

View file

@ -5,7 +5,7 @@ import { createApp } from 'vue';
import { createPinia, mapStores } from 'pinia';
import App from '@/App.vue';
import vehicleBanner from './vehicle-banner';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
const cmsData = { VehicleBannerWidget:
{

View file

@ -9,7 +9,7 @@
<script>
// Supporting files
import { issPageValues } from '@/router/router-constants/issPage-values';
import { validateISSClientTag } from '@/helpers/clientauth-helper';
import validateISSClientTag from '@/helpers/clientauth-helper';
import { useMainStore } from '@/store';
export default {