From a8a959e49145db218e958e3ced060211a835f287 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Mon, 27 Jan 2025 18:02:34 -0500 Subject: [PATCH 1/2] Change eval to getBoolFromString helper --- src/helpers/boolean-helper.js | 19 +++ src/helpers/boolean-helper.spec.js | 146 ++++++++++++++++++ src/layouts/payment-method/payment-method.vue | 5 +- src/layouts/payment/payment.vue | 3 +- src/layouts/quote/quote.vue | 5 +- src/layouts/vehicle-damage/vehicle-damage.vue | 3 +- src/router/index.js | 16 +- 7 files changed, 184 insertions(+), 13 deletions(-) create mode 100644 src/helpers/boolean-helper.js create mode 100644 src/helpers/boolean-helper.spec.js diff --git a/src/helpers/boolean-helper.js b/src/helpers/boolean-helper.js new file mode 100644 index 000000000..71016ef06 --- /dev/null +++ b/src/helpers/boolean-helper.js @@ -0,0 +1,19 @@ +export function getBoolFromString(str) { + // Catch edge cases + if (str === null || str === undefined) { + return false; + } + + if (typeof str === "boolean") { + return str; + } + + if (typeof str !== "string") { + return false; + } + + // string logic + const toLower = str?.toLowerCase(); + + return toLower === "true"; +} diff --git a/src/helpers/boolean-helper.spec.js b/src/helpers/boolean-helper.spec.js new file mode 100644 index 000000000..37045d132 --- /dev/null +++ b/src/helpers/boolean-helper.spec.js @@ -0,0 +1,146 @@ +import { getBoolFromString } from "./boolean-helper"; + +describe("getBoolFromString", () => { + describe("Happy paths", () => { + test("\"true\" -> true", () => { + const input = "true"; + + const output = getBoolFromString(input); + + expect(output).toBe(true); + }); + + test("\"false\" -> false", () => { + const input = "false"; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("\"other string\" -> false", () => { + const input = "some random value"; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + }); + + describe("Capitalization", () => { + test("\"TRUE\" -> true", () => { + const input = "TRUE"; + + const output = getBoolFromString(input); + + expect(output).toBe(true); + }); + + test("\"True\" -> true", () => { + const input = "True"; + + const output = getBoolFromString(input); + + expect(output).toBe(true); + }); + + test("\"FALSE\" -> false", () => { + const input = "FALSE"; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("\"False\" -> false", () => { + const input = "False"; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + }); + + describe("Graceful type errors", () => { + describe("Boolean", () => { + test("true -> true", () => { + const input = true; + + const output = getBoolFromString(input); + + expect(output).toBe(true); + }); + + test("false -> false", () => { + const input = false; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + }); + + describe("Empty", () => { + test("undefined -> false", () => { + const input = undefined; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("null -> false", () => { + const input = null; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("{} -> false", () => { + const input = {}; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + }); + + describe("Other types", () => { + test("1 -> false", () => { + const input = 1; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("Object -> false", () => { + const input = { + test: true, + true: true, + }; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("function -> false", () => { + const input = () => true; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }); + + test("array -> false", () => { + const input = [true]; + + const output = getBoolFromString(input); + + expect(output).toBe(false); + }) + }); + }); +}); \ No newline at end of file diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 38fa19611..add9339c1 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -156,6 +156,7 @@ import { mapTaxedLineItemsToStoreFormat } from "../../store"; import { coverageStatus } from "@/constants/insurance"; import { containsLineItemWithPartType } from "@/helpers/service-package-helper"; import { containsRecalParts } from "@/helpers/recal-helper"; +import { getBoolFromString } from "@/helpers/boolean-helper"; defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED)); defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED)); @@ -429,7 +430,7 @@ export default { // prettier-ignore { const log = getQuerystringParameter(queryStrings.LOG); - const logAsBool = (log?.toLowerCase() === "true"); + const logAsBool = getBoolFromString(log); if (logAsBool || !preReqResult) { console.log("------------- payment-method.vue pagePrereqs start -----------------"); console.log(new Date() + " serviceLocationReqs::isMobile: " + isMobile); @@ -786,7 +787,7 @@ export default { shouldDisplayPiaAlert() { return ( this.$route.query[queryStrings.DISPLAY_PIA_ALERT] || - eval(window.history.state.displayPiaAlert) + getBoolFromString(window.history.state.displayPiaAlert) ); }, // Necessary to make the watcher of lineItems work diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue index ce5e6bcbe..5ffb04faa 100644 --- a/src/layouts/payment/payment.vue +++ b/src/layouts/payment/payment.vue @@ -234,6 +234,7 @@ import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js" import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js"; import { routerParams } from "@/router/router-constants/router-params"; import { coverageStatus } from "@/constants/insurance"; +import { getBoolFromString } from "@/helpers/boolean-helper.js"; export default { name: "payment", @@ -800,7 +801,7 @@ export default { shouldDisplayPiaAlert(payMethod) { return ( this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod || - eval(window.history.state.displayPiaAlert) + getBoolFromString(window.history.state.displayPiaAlert) ); }, }, diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index f3590cbc3..61034fe5e 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -159,6 +159,7 @@ import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigat import { containsRecalParts } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; import { saveQuote } from "@/helpers/heritage-integration/order-helper.js"; +import { getBoolFromString } from "@/helpers/boolean-helper"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); @@ -298,7 +299,7 @@ export default { // to restore, uncomment the 2 lines below // vm.showSaveProgressPopup = showSaveProgressPopup; // vm.showSaveProgressModal = showSaveProgressModal; - + vm.addableVaps = addableVaps; vm.lineItems = lineItems; vm.availableLineItems = pricingResults; @@ -407,7 +408,7 @@ export default { baseMixin.methods.ResetExternalParamsAndHideModal(); } else { // user came from an external source, however, the externalParms may have been reset on service-zip, property-questions, etc... - if (eval(store.getters.externalParameterQuote?.isInsurance)) { + if (getBoolFromString(store.getters.externalParameterQuote?.isInsurance)) { // did user intentionally select insurance? vm.isInsuranceSelected = true; vm.servicePackage = store.getters.externalParameterQuote.servicePackage; diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 7cce1c120..6e9c4b198 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -102,6 +102,7 @@ import { routerParams } from "@/router/router-constants/router-params"; import store from "@/store"; import baseMixin from "@/mixins/base-mixin"; import { nextTick } from "vue"; +import { getBoolFromString } from "@/helpers/boolean-helper"; // DEFINE VALIDATION RULES defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED)); @@ -622,7 +623,7 @@ export default { ); }, shouldDisplayVehicleChangeAlert() { - return eval(window.history.state.displayVehicleChangeAlert); + return getBoolFromString(window.history.state.displayVehicleChangeAlert); }, shouldHideBackButton() { return this.$store.getters.requiresVerifiedRedirecting; diff --git a/src/router/index.js b/src/router/index.js index 49d3b0e4f..52b9023b9 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -38,6 +38,7 @@ import { applicationConfig } from "../constants/application-config"; import { shouldStripPromoQueryString } from "@/helpers/promotions-helper"; import bailout from "@/layouts/bailout/bailout"; import { nextTick } from "vue"; +import { getBoolFromString } from "@/helpers/boolean-helper"; const routes = [ { @@ -57,7 +58,7 @@ const routes = [ log(` --from.redirectedFrom:>${JSON.stringify(from.redirectedFrom)}<`, ""); await analyticsMixin.methods.validateSession(); - + // after session is validated, remove the fromHeritage querystring if it exists so session expiration works if (to.query) { delete to.query[queryStrings.FROM_HERITAGE]; @@ -178,8 +179,9 @@ const routes = [ // clear part related state because heritage selected a new vehicle if ( to.query.fmgPage === fmgPageValues.VEHICLE && - eval(getFunnelCookie()?.HasDelayedClaimRegistration && - !fromReturnUser) + getBoolFromString( + getFunnelCookie()?.HasDelayedClaimRegistration && !fromReturnUser + ) ) { store.commit(storeMutations.RESET_GLASS_PARTS_STATE); } @@ -187,7 +189,7 @@ const routes = [ // if coming from the return user page, clear the destination page so implicit navigation runs log(" --to.query ", JSON.stringify(to.query)); if (fromReturnUser && to.query) { - log( " --clear to.query"); + log(" --clear to.query"); delete to.query[queryStrings.FMG_PAGE]; //to.query[queryStrings.FMG_PAGE] = ""; @@ -427,7 +429,7 @@ router.afterEach(async (to, from) => { store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name); // If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate - if (eval(window.history.state.isSavingNavigation)) { + if (getBoolFromString(window.history.state.isSavingNavigation)) { if ( store.getters.applicationUser.savedSessionId || store.getters.order.customer?.emailAddress @@ -571,7 +573,7 @@ async function navigate( const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR); const logQs = getQuerystringParameter(queryStrings.LOG); baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false); - + log("------------- router index.js navigate start -----------------"); log(" --scenario: ", scenario); log(" --isSavingNavigation: ", isSavingNavigation); @@ -636,7 +638,7 @@ function getNavigationMap(scenario, currentRoute) { function log(message, data) { const log = getQuerystringParameter(queryStrings.LOG); baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false); - + data = data ?? ""; const outData = typeof data === "object" ? JSON.stringify(data) : data; From 009f07df057dd9ee272c5c269d995165672eaf91 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Mon, 27 Jan 2025 18:06:01 -0500 Subject: [PATCH 2/2] Prettier + parenthesis change --- src/helpers/boolean-helper.spec.js | 20 ++++++++++---------- src/helpers/querystring-helper.js | 6 +++--- src/router/index.js | 5 ++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/helpers/boolean-helper.spec.js b/src/helpers/boolean-helper.spec.js index 37045d132..189bd2a78 100644 --- a/src/helpers/boolean-helper.spec.js +++ b/src/helpers/boolean-helper.spec.js @@ -2,7 +2,7 @@ import { getBoolFromString } from "./boolean-helper"; describe("getBoolFromString", () => { describe("Happy paths", () => { - test("\"true\" -> true", () => { + test('"true" -> true', () => { const input = "true"; const output = getBoolFromString(input); @@ -10,7 +10,7 @@ describe("getBoolFromString", () => { expect(output).toBe(true); }); - test("\"false\" -> false", () => { + test('"false" -> false', () => { const input = "false"; const output = getBoolFromString(input); @@ -18,7 +18,7 @@ describe("getBoolFromString", () => { expect(output).toBe(false); }); - test("\"other string\" -> false", () => { + test('"other string" -> false', () => { const input = "some random value"; const output = getBoolFromString(input); @@ -28,7 +28,7 @@ describe("getBoolFromString", () => { }); describe("Capitalization", () => { - test("\"TRUE\" -> true", () => { + test('"TRUE" -> true', () => { const input = "TRUE"; const output = getBoolFromString(input); @@ -36,7 +36,7 @@ describe("getBoolFromString", () => { expect(output).toBe(true); }); - test("\"True\" -> true", () => { + test('"True" -> true', () => { const input = "True"; const output = getBoolFromString(input); @@ -44,7 +44,7 @@ describe("getBoolFromString", () => { expect(output).toBe(true); }); - test("\"FALSE\" -> false", () => { + test('"FALSE" -> false', () => { const input = "FALSE"; const output = getBoolFromString(input); @@ -52,7 +52,7 @@ describe("getBoolFromString", () => { expect(output).toBe(false); }); - test("\"False\" -> false", () => { + test('"False" -> false', () => { const input = "False"; const output = getBoolFromString(input); @@ -70,7 +70,7 @@ describe("getBoolFromString", () => { expect(output).toBe(true); }); - + test("false -> false", () => { const input = false; @@ -140,7 +140,7 @@ describe("getBoolFromString", () => { const output = getBoolFromString(input); expect(output).toBe(false); - }) + }); }); }); -}); \ No newline at end of file +}); diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js index 8c40c91b7..e6c488b1d 100644 --- a/src/helpers/querystring-helper.js +++ b/src/helpers/querystring-helper.js @@ -10,10 +10,10 @@ export function getQuerystringParameter(key) { } // if you add the fmgPage to the querystringobject before calling, then pass true for skipFmgPageName -export function buildQuerystringObject(qso, skipFmgPageName=false) { +export function buildQuerystringObject(qso, skipFmgPageName = false) { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); - + for (const [name, value] of urlParams) { if (name.toLowerCase() === "fmgpage" && skipFmgPageName) { continue; @@ -21,4 +21,4 @@ export function buildQuerystringObject(qso, skipFmgPageName=false) { qso[name] = value; } return qso; -} \ No newline at end of file +} diff --git a/src/router/index.js b/src/router/index.js index f1bca935d..a0be7d09e 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -176,9 +176,8 @@ const routes = [ // clear part related state because heritage selected a new vehicle if ( to.query.fmgPage === fmgPageValues.VEHICLE && - getBoolFromString( - getFunnelCookie()?.HasDelayedClaimRegistration && !fromReturnUser - ) + getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration) && + !fromReturnUser ) { store.commit(storeMutations.RESET_GLASS_PARTS_STATE); }