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..189bd2a78 --- /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); + }); + }); + }); +}); 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 860aaf087..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)); @@ -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 045527a45..a0be7d09e 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 = [ { @@ -175,7 +176,8 @@ 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); } @@ -423,7 +425,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