diff --git a/README.md b/README.md index 65e8bfb95..535976602 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,8 @@ This Repository is for Fix My Glass front end Vue and documentation associated w #### Routing We are using [Vue Router](https://next.router.vuejs.org/) 4.x for our front end routing. We are using a runtime dynamic routing solution. Some more information about dynamic routing can be found on the [official Vue Router documentation](https://next.router.vuejs.org/guide/advanced/dynamic-routing.html). -Here is a high level overview of how our routing works: -![FixMyGlass - Routing](https://user-images.githubusercontent.com/44780237/139876801-7d5c495a-f361-4234-a8ec-69126a357f80.png) - -`RetainStructureAndGoTo404(to, next)` - Since our 404 path on our router is `path: '/:pathMatch(.*)*'` (meaning that we don't have a dedicated 404 route) we retain the information entered by the user in the url bar and just serve back our `NotFound` component on Vue. For example if a user was to type in `.../fmg/fmgPage=junkPage` Vue will retain this url in the browser and return our `NotFound` component. This could be especially useful for analytics and reporting. - `Next()` - Is a function that is native to Vue Router in which we call in order to send the user where want them to go based on some logic we have[. You can read more about Navigation Guards and the `Next()` function on the Vue Router documentation. ](https://next.router.vuejs.org/guide/advanced/navigation-guards.html) -`GetRouteInfoFromPageName(PageName)` - This method typically takes the query string value of `fmgPage` and passes it into a call to our Content Service. The service will pull information on the page; matching page name passed to page name in our Cms. If we have a match, we will compile the route information and send it to our router to process. If we do not have a that page in our Cms, the user will be served back a 404 page while retaining the structure. \ No newline at end of file +`GetRouteInfoFromPageName(PageName)` - This method typically takes the query string value of `fmgPage` and passes it into a call to our Content Service. The service will pull information on the page; matching page name passed to page name in our Cms. If we have a match, we will compile the route information and send it to our router to process. If we do not have a that page in our Cms, the user will be served back a 404 page while retaining the structure. + +`GoToFunnelStartOn404(next)` - When a user tries to go to a page that doesn't exist in the CMS, they will be put back to the 'Start' of the funnel which is whatever page is marked as the homepage on Sitefinity. \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 7a6fcbc01..bce302e5a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,12 +13,12 @@ module.exports = { "!src/helpers/unit-test-helper.js", "!src/layouts/component-test/component-test.vue", "!src/layouts/form-test/form-test.vue", - "!src/layouts/address-poc/address-poc.vue" + "!src/layouts/address-poc/address-poc.vue", ], //! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], coverageThreshold: { global: { - statements: 85, + statements: 87, }, }, }; diff --git a/src/App.vue b/src/App.vue index 3d665312e..76a01d29c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,7 +5,6 @@ \ No newline at end of file + @import "@/styles/common-error-styles.scss"; + diff --git a/src/common-components/button-back/button-back.spec.js b/src/common-components/button-back/button-back.spec.js index b8bc3256d..c7bff87f0 100644 --- a/src/common-components/button-back/button-back.spec.js +++ b/src/common-components/button-back/button-back.spec.js @@ -2,7 +2,6 @@ import { shallowMount } from "@vue/test-utils"; import buttonBack from "./button-back"; describe("back button", () => { - test("renders a button", () => { // Arrange const myFunction = () => {}; @@ -14,10 +13,9 @@ describe("back button", () => { backButtonAccessibleText: "something", }, }); - + // Assert expect(wrapper.find("button").exists()).toBe(true); wrapper.unmount(); }); - }); diff --git a/src/common-components/button-back/button-back.vue b/src/common-components/button-back/button-back.vue index 657795dee..cf3a630bf 100644 --- a/src/common-components/button-back/button-back.vue +++ b/src/common-components/button-back/button-back.vue @@ -1,13 +1,38 @@ @@ -19,71 +44,39 @@ export default { type: String, required: true, default: "", - } + }, }, methods: { handleClick() { - this.$emit('click-event'); - } - } + this.$emit("click-event"); + }, + }, }; diff --git a/src/common-components/button-question/button-question.spec.js b/src/common-components/button-question/button-question.spec.js index 7296c66d2..808e5c4ba 100644 --- a/src/common-components/button-question/button-question.spec.js +++ b/src/common-components/button-question/button-question.spec.js @@ -13,9 +13,7 @@ describe("buttonQuestion.vue", () => { wrapper.vm.chooseAnswer("2021"); // Assert - expect(wrapper.find(".text-center").text()).toEqual( - "Question Text" - ); + expect(wrapper.find(".text-center").text()).toEqual("Question Text"); const buttonButtons = wrapper.findAllComponents('[data-test="button"]'); expect(buttonButtons.length).toBe(3); expect(wrapper.props().modelValue).toBe("2020"); diff --git a/src/common-components/button-question/button-question.vue b/src/common-components/button-question/button-question.vue index 0e4212f50..28fd2258f 100644 --- a/src/common-components/button-question/button-question.vue +++ b/src/common-components/button-question/button-question.vue @@ -1,9 +1,7 @@ diff --git a/src/constants/events.js b/src/constants/events.js index 91461d535..066ef6dcd 100644 --- a/src/constants/events.js +++ b/src/constants/events.js @@ -1,17 +1,17 @@ const globalEvents = { - Categories: { - GLOBAL_ALERT: "GLOBAL_ALERT", - }, - SubCategories: { - PAGE_NOT_FOUND: "PAGE_NOT_FOUND", - } -} + Categories: { + GLOBAL_ALERT: "GLOBAL_ALERT", + }, + SubCategories: { + PAGE_NOT_FOUND: "PAGE_NOT_FOUND", + }, +}; const globalEventTypes = { - Success: "alert-success", - Warning: "alert-warning", - Info: "alert-info", - Danger: "alert-danger", -} + Success: "alert-success", + Warning: "alert-warning", + Info: "alert-info", + Danger: "alert-danger", +}; -export {globalEvents, globalEventTypes} \ No newline at end of file +export { globalEvents, globalEventTypes }; diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 1c795aab2..a20446ef8 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -9,20 +9,26 @@ export function fetchCmsContentForPage(fmgPage) { const pageDataFromCms = {}; response.data.Result.forEach((widget) => { - - let widgetWithReplacements = findAndReplaceGlobalStateValues(widget.Model, widget.Name); + let widgetWithReplacements = findAndReplaceGlobalStateValues( + widget.Model, + widget.Name + ); // If we already have this widget, push it on the collection if (widgetWithReplacements.Name in pageDataFromCms) { - pageDataFromCms[widgetWithReplacements.Name].push(widgetWithReplacements.Model); + pageDataFromCms[widgetWithReplacements.Name].push( + widgetWithReplacements.Model + ); return; } - pageDataFromCms[widgetWithReplacements.Name] = [widgetWithReplacements.Model]; + pageDataFromCms[widgetWithReplacements.Name] = [ + widgetWithReplacements.Model, + ]; }); Object.keys(pageDataFromCms).forEach((key) => { - if (pageDataFromCms[key].length === 1){ + if (pageDataFromCms[key].length === 1) { pageDataFromCms[key] = pageDataFromCms[key][0]; } }); @@ -33,31 +39,29 @@ export function fetchCmsContentForPage(fmgPage) { // Function to convert a string, into a matching global state item. function mapStringToState(str) { - // Pull all matches out of the string. - const regexExp = new RegExp('{(.*?):(.*?)}', 'g'); + const regexExp = new RegExp("{(.*?):(.*?)}", "g"); const matches = [...str.matchAll(regexExp)]; // Our final string value that will be built from the matches. - let stringBuilder = ''; + let stringBuilder = ""; for (const match of matches) { - // Reset store state for each match. let storeState = store.state; - for (const s of match[2].split('.')) { + for (const s of match[2].split(".")) { if (storeState[s] != undefined) { storeState = storeState[s]; } else { - 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], storeState); // If we still have values we need to substitute, call this function again. - if(stringWithReplacement.includes('{globalState:')) { + if (stringWithReplacement.includes("{globalState:")) { return mapStringToState(stringWithReplacement); } @@ -71,15 +75,16 @@ function mapStringToState(str) { // 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: {} + Model: {}, }; - Object.keys(widgetModel).forEach(key => { - - let modelWithReplacements = processWidgetItemForReplacement(widgetModel, key); + Object.keys(widgetModel).forEach((key) => { + let modelWithReplacements = processWidgetItemForReplacement( + widgetModel, + key + ); objWithReplacements.Model[key] = modelWithReplacements; }); @@ -91,16 +96,19 @@ function findAndReplaceGlobalStateValues(widgetModel, widgetName) { // 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('{globalState:')) { + if (typeof widgetModel[key] === "string") { + if (widgetModel[key].includes("{globalState:")) { 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 => { + if ( + typeof widgetModel[key] === "object" && + Object.keys(widgetModel[key]).length + ) { + Object.keys(widgetModel[key]).forEach((item) => { processWidgetItemForReplacement(widgetModel[key], item); }); @@ -109,5 +117,4 @@ function processWidgetItemForReplacement(widgetModel, key) { // If we have something else like a number, boolean, etc. just return it return widgetModel[key]; - -} \ No newline at end of file +} diff --git a/src/helpers/cms-helper.spec.js b/src/helpers/cms-helper.spec.js index efc0ee56c..d7aeb8bf4 100644 --- a/src/helpers/cms-helper.spec.js +++ b/src/helpers/cms-helper.spec.js @@ -4,12 +4,11 @@ import { dispatch } from "@/store"; jest.mock("@/store", () => ({ dispatch: jest.fn(), state: { - order: { vehicle: { year: "2019", make: "Acura" } } - } + order: { vehicle: { year: "2019", make: "Acura" } }, + }, })); - -describe("cms-content-helper.js", () => { +describe("cms-content-helper.js", () => { it("Should return data from CMS", () => { // Arrange const cmsMockData = { @@ -34,9 +33,9 @@ describe("cms-content-helper.js", () => { }, ], }; - + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - + // Act fetchCmsContentForPage("testPage").then((response) => { // Assert @@ -45,10 +44,9 @@ describe("cms-content-helper.js", () => { ); }); }); - }); -describe("cms-content-helper.js", () => { +describe("cms-content-helper.js", () => { it("Should replace strings for global state", () => { const cmsMockData = { Result: [ @@ -60,21 +58,18 @@ describe("cms-content-helper.js", () => { }, ], }; - + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - + fetchCmsContentForPage("testPage").then((response) => { // Assert - expect(response.FunnelSubHeaderWidget.HeaderText).toEqual( - "2019" - ); + expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); }); }); }); -describe("cms-content-helper.js", () => { +describe("cms-content-helper.js", () => { it("Should replace strings for global state, and leave others the same", () => { - const cmsMockData = { Result: [ { @@ -91,21 +86,21 @@ describe("cms-content-helper.js", () => { }, ], }; - + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - + fetchCmsContentForPage("testPage").then((response) => { // Assert expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); - expect(response.VehicleYearQuestion.ExampleText).toEqual("My widget value!"); - + expect(response.VehicleYearQuestion.ExampleText).toEqual( + "My widget value!" + ); }); }); }); -describe("cms-content-helper.js", () => { +describe("cms-content-helper.js", () => { it("Should replace strings for global state in nested objects", () => { - const cmsMockData = { Result: [ { @@ -119,22 +114,23 @@ describe("cms-content-helper.js", () => { Model: { OtherObjectInside: { ExampleText: "{globalState:order.vehicle.make}", - } + }, }, }, ], }; - + dispatch.mockImplementation(() => Promise.resolve({ data: cmsMockData })); - + fetchCmsContentForPage("testPage").then((response) => { // Assert - + expect(response.FunnelSubHeaderWidget.HeaderText).toEqual("2019"); - expect(response.VehicleMakeQuestion.OtherObjectInside.ExampleText).toEqual("Acura"); - + expect( + response.VehicleMakeQuestion.OtherObjectInside.ExampleText + ).toEqual("Acura"); }); }); }); -test.todo("String cannot be mapped to global state"); \ No newline at end of file +test.todo("String cannot be mapped to global state"); diff --git a/src/helpers/event-bus/event-bus.js b/src/helpers/event-bus/event-bus.js index 8ac156776..47f229210 100644 --- a/src/helpers/event-bus/event-bus.js +++ b/src/helpers/event-bus/event-bus.js @@ -2,24 +2,31 @@ import store from "@/store"; import { storeActions } from "@/constants/store-actions.js"; export default { - // Adds event to the bus given its category, subcategory, and eventValue; - addEventToBus(category, subCategory, eventValue) { - store.commit(storeActions.ADD_EVENT_TO_BUS, { category: category, subCategory: subCategory, eventValue: eventValue }); - }, + // Adds event to the bus given its category, subcategory, and eventValue; + addEventToBus(category, subCategory, eventValue) { + store.commit(storeActions.ADD_EVENT_TO_BUS, { + category: category, + subCategory: subCategory, + eventValue: eventValue, + }); + }, - // Finds event on the bus, removes the item, and returns its value to the caller. - readAndPopEventFromBus(category, subCategory) { - const event = store.getters.eventBusItem(category, subCategory); + // Finds event on the bus, removes the item, and returns its value to the caller. + readAndPopEventFromBus(category, subCategory) { + const event = store.getters.eventBusItem(category, subCategory); - store.commit(storeActions.REMOVE_EVENT_FROM_BUS, { category: category, subCategory: subCategory }); + store.commit(storeActions.REMOVE_EVENT_FROM_BUS, { + category: category, + subCategory: subCategory, + }); - return event; - }, + return event; + }, - // Finds the event on the bus and returns its value to the caller, does not remove it. - readEventFromBus(category, subCategory) { - const event = store.getters.eventBusItem(category, subCategory); + // Finds the event on the bus and returns its value to the caller, does not remove it. + readEventFromBus(category, subCategory) { + const event = store.getters.eventBusItem(category, subCategory); - return event; - }, -} \ No newline at end of file + return event; + }, +}; diff --git a/src/helpers/event-bus/event-bus.spec.js b/src/helpers/event-bus/event-bus.spec.js index d20c11044..fece3fee2 100644 --- a/src/helpers/event-bus/event-bus.spec.js +++ b/src/helpers/event-bus/event-bus.spec.js @@ -3,48 +3,57 @@ import eventBus from "@/helpers/event-bus/event-bus"; import store from "@/store"; describe("event-bus.js", () => { + let event = { + isDismissible: true, + messageCopy: "You can get a quote by starting on this page.", + messageHeadline: "We're sorry, something went wrong.", + type: globalEventTypes.Danger, + }; - let event = { - isDismissible: true, - messageCopy: 'You can get a quote by starting on this page.', - messageHeadline: 'We\'re sorry, something went wrong.', - type: globalEventTypes.Danger - }; + it("Puts item on bus and then take it off", () => { + // Arrange / Act + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND, + event + ); - it("Puts item on bus and then take it off", () => { + // Assert + expect( + store.getters.eventBusItem( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ) + ).toEqual(event); - // Arrange / Act - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND, - event - ); + expect(store.state.applicationUser.eventBus.length).toEqual(1); + // Arrange / Act + const eventValue = eventBus.readAndPopEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); - // Assert - expect(store.getters.eventBusItem(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND)).toEqual(event); + // Assert + expect(eventValue).toEqual(event); - expect(store.state.applicationUser.eventBus.length).toEqual(1); + expect(store.state.applicationUser.eventBus.length).toEqual(0); + }); - // Arrange / Act - const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND); + it("Reads event from bus, should have event value.", () => { + // Arrange / Act + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND, + event + ); - // Assert - expect(eventValue).toEqual(event); - - expect(store.state.applicationUser.eventBus.length).toEqual(0); - }); - - it("Reads event from bus, should have event value.", () => { - // Arrange / Act - eventBus.addEventToBus( - globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND, - event - ); - - // Assert - expect(eventBus.readEventFromBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND)).toEqual(event); - - }); -}); \ No newline at end of file + // Assert + expect( + eventBus.readEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ) + ).toEqual(event); + }); +}); diff --git a/src/layouts/address-poc/address-poc.vue b/src/layouts/address-poc/address-poc.vue index 31a5e66ee..65ca768b4 100644 --- a/src/layouts/address-poc/address-poc.vue +++ b/src/layouts/address-poc/address-poc.vue @@ -8,45 +8,51 @@
- +
-
- + + diff --git a/src/layouts/component-test/component-test.vue b/src/layouts/component-test/component-test.vue index 2b5074ea7..2f5dc0308 100644 --- a/src/layouts/component-test/component-test.vue +++ b/src/layouts/component-test/component-test.vue @@ -8,10 +8,10 @@
@@ -22,26 +22,22 @@
- -
-
-
-
-
- + +
+
+
+
+
@@ -54,31 +50,31 @@ Functioning as Checkbox
@@ -93,13 +89,13 @@
Functioning as Checkbox
@@ -110,13 +106,13 @@
Checkbox no Description
@@ -127,13 +123,13 @@
Functioning as Radio Button
@@ -144,13 +140,13 @@
Radio Button no Description
@@ -161,14 +157,14 @@
Horizontal Checkbox
@@ -179,14 +175,14 @@
Checkbox no Description
@@ -197,13 +193,13 @@
Horizontal Radio Button
@@ -214,13 +210,13 @@
Radio Button no Description
@@ -233,93 +229,99 @@
-
+
-

- Select Vehicle Year -

+

Select Vehicle Year

- @@ -331,187 +333,205 @@
-
+

Select Vehicle Year

Functioning as Radio Buttons
-
+

Select Vehicle Year

-

List Button - Multi-Line Centered

+

+ List Button - Multi-Line Centered +

Functioning as Checkboxes
-
+

Multi-Line Centered

Functioning as Radio Buttons
-
+

Multi-Line Centered

@@ -523,104 +543,108 @@
-
+
-

- Select Vehicle Year -

+

Select Vehicle Year

Functioning as Radio Buttons
-
+
-

- Select Vehicle Year -

+

Select Vehicle Year

@@ -631,18 +655,15 @@
- Text Link (default text link behavior) -

- Text Link Small (.small) -

- Footer Link (.footer-link) -

- Navigation Link (.navigation-link) +

+

+

+
-

Typogrophy

+

Typography

@@ -699,60 +720,60 @@
@@ -764,7 +785,7 @@
@@ -776,7 +797,7 @@
@@ -786,99 +807,99 @@
- + :answers="checkboxAnswers" + :isMultiSelect="true" + ariaLabelBy="checkbox" + groupName="checkbox-list" + questionText="List Button as checkbox" + /> - - - - - - - - + :answers="radioAnswers" + ariaLabelBy="radio" + groupName="radio-list" + questionText="List Button as radio" + /> + + + + + + + + +
\ No newline at end of file +.form-test-error { + color: red; + font-weight: bold; +} +.form-test-invalid { + opacity: 0.5; +} + diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js index a6688a9af..81c7c8b7a 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.spec.js +++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js @@ -1,125 +1,201 @@ -import { shallowMount, flushPromises } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; +// Components import vehicleDamage from "@/layouts/vehicle-damage/vehicle-damage.vue"; import funnelHeader from "@/common-components/funnel-header/funnel-header"; import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; + +// Supporting Files import { settleAllPromises } from "@/helpers/layout-helper.js"; import baseMixin from "@/mixins/base-mixin"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; import { nextTick } from "vue"; // Mock our module for promises. jest.mock("@/helpers/layout-helper.js", () => ({ - settleAllPromises: jest.fn(), + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +// Mock Store +jest.mock("@/store", () => ({ + getters: { + vehicle: { + carId: "C00000000", + }, + }, })); describe("vehicle-damage.vue", () => { test("Page header is initailized with api data", async (done) => { - //Arrange const pageHeaderWidgetHeaderText = "Select Damage"; - const { wrapper, apiPromise } = setupMocks( { pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText }); + const { wrapper, apiPromise } = setupMocks({ + pageHeaderWidgetHeaderText: pageHeaderWidgetHeaderText, + }); //Act - vehicleDamage.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm)); + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); //Assert apiPromise.finally(() => { - expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith(pageHeaderWidgetHeaderText); + expect(funnelSubHeader.methods.initializeComponent).toHaveBeenCalledWith( + pageHeaderWidgetHeaderText + ); done(); }); }); }); describe("vehicle-damage.vue", () => { - test("Page logo image is initailized with api data", async (done) => { - - //Arrange - const SiteHeaderWidget = { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - } - const { wrapper, apiPromise } = setupMocks( { SiteHeaderWidget: SiteHeaderWidget}); - - //Act - vehicleDamage.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm)); - - //Assert - apiPromise.finally(() => { - expect(funnelHeader.methods.initializeComponent).toHaveBeenCalledWith(SiteHeaderWidget); - done(); - }); + test("Page logo image is initailized with api data", async (done) => { + //Arrange + const SiteHeaderWidget = { + LogoImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }; + const { wrapper, apiPromise } = setupMocks({ + SiteHeaderWidget: SiteHeaderWidget, }); - }); - describe("vehicle-damage.vue", () => { - test("Vehicle image is initailized with api data", async (done) => { - - //Arrange - const VehicleBannerWidget = { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - } - const { wrapper, apiPromise } = setupMocks( { VehicleBannerWidget: VehicleBannerWidget}); - - //Act - vehicleDamage.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-damage" } }, undefined, (c) => c(wrapper.vm)); - - //Assert - apiPromise.finally(() => { - expect(vehicleBanner.methods.initializeComponent).toHaveBeenCalledWith(VehicleBannerWidget); - done(); - }); + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(funnelHeader.methods.initializeComponent).toHaveBeenCalledWith( + SiteHeaderWidget + ); + done(); }); }); +}); + +describe("vehicle-damage.vue", () => { + test("Vehicle image is initailized with api data", async (done) => { + //Arrange + const VehicleBannerWidget = { + GenericVehicleImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", + }; + const { wrapper, apiPromise } = setupMocks({ + VehicleBannerWidget: VehicleBannerWidget, + }); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(vehicleBanner.methods.initializeComponent).toHaveBeenCalledWith( + VehicleBannerWidget + ); + done(); + }); + }); +}); + +describe("vehicle-damage.vue", () => { + test("CarId set, arePagePrerequisitesValid should be true ", async () => { + //Arrange + const { wrapper } = setupMocks({}); + + //Act + vehicleDamage.beforeRouteEnter.call( + wrapper.vm, + { query: { fmgPage: "vehicle-damage" } }, + undefined, + (c) => c(wrapper.vm) + ); + + let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + await nextTick(); + + //Assert + expect(arePagePrerequisitesValid).toBe(true); + }); +}); function setupMocks({ - pageHeaderWidgetHeaderText = {}, - mountOptionsMockData = {}, - }) { - - //Mock api responses - baseMixin.methods.dispatchNonBlockingStoreAction = jest.fn(); - baseMixin.methods.dispatchNonBlockingStoreAction.mockImplementation(() => { - return Promise.resolve({ data: ['Front Window', 'Back Window', 'Side Window'] }); + pageHeaderWidgetHeaderText = {}, + mountOptionsMockData = {}, +}) { + //Mock api responses + baseMixin.methods.dispatchNonBlockingStoreAction = jest.fn(); + baseMixin.methods.dispatchNonBlockingStoreAction.mockImplementation(() => { + return Promise.resolve({ + data: ["Front Window", "Back Window", "Side Window"], }); - const apiResponses = { - cmsContent: { - FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, - VehicleBannerWidget: - { - GenericVehicleImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", - }, - FunnelHeaderWidget: - { - LogoImage: - "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", - }, + }); + const apiResponses = { + cmsContent: { + FunnelSubHeaderWidget: pageHeaderWidgetHeaderText, + VehicleBannerWidget: { + GenericVehicleImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", }, - damageOptions: ['Front Window', 'Back Window', 'Side Window'], - }; - const apiPromise = Promise.resolve(apiResponses); - settleAllPromises.mockImplementation(() => apiPromise); - - //Mock damage initialize methods - funnelHeader.methods = { - initializeComponent: jest.fn(), - }; - vehicleBanner.methods = { - initializeComponent: jest.fn(), - }; - funnelSubHeader.methods = { - initializeComponent: jest.fn(), - }; - const mountOptions = getMountOptions(mountOptionsMockData); - const wrapper = shallowMount(vehicleDamage, mountOptions); - const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); - funnelHeaderWrapper.vm.initializeComponent = funnelHeader.methods.initializeComponent; - const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); - vehicleBannerWrapper.vm.initializeComponent = vehicleBanner.methods.initializeComponent; - const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" }); - funnelSubHeaderWrapper.vm.initializeComponent = funnelSubHeader.methods.initializeComponent; - - return { wrapper, apiPromise }; - } \ No newline at end of file + FunnelHeaderWidget: { + LogoImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }, + }, + damageOptions: ["Front Window", "Back Window", "Side Window"], + }; + + const apiPromise = Promise.resolve(apiResponses); + + settleAllPromises.mockImplementation(() => apiPromise); + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + + //Mock damage initialize methods + funnelHeader.methods = { + initializeComponent: jest.fn(), + }; + + vehicleBanner.methods = { + initializeComponent: jest.fn(), + }; + + funnelSubHeader.methods = { + initializeComponent: jest.fn(), + }; + + const mountOptions = getMountOptions(mountOptionsMockData); + const wrapper = shallowMount(vehicleDamage, mountOptions); + + const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" }); + funnelHeaderWrapper.vm.initializeComponent = + funnelHeader.methods.initializeComponent; + + const vehicleBannerWrapper = wrapper.findComponent({ name: "vehicleBanner" }); + vehicleBannerWrapper.vm.initializeComponent = + vehicleBanner.methods.initializeComponent; + + const funnelSubHeaderWrapper = wrapper.findComponent({ + name: "funnelSubHeader", + }); + funnelSubHeaderWrapper.vm.initializeComponent = + funnelSubHeader.methods.initializeComponent; + + return { wrapper, apiPromise }; +} diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 92d00964c..766a0697f 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -1,5 +1,5 @@