diff --git a/src/common-components/button-question/button-question.vue b/src/common-components/button-question/button-question.vue index 97ebf1310..e1fee1e40 100644 --- a/src/common-components/button-question/button-question.vue +++ b/src/common-components/button-question/button-question.vue @@ -17,7 +17,7 @@ data-test="button" :groupName="groupName" textPosition="text-start" - isRequired=true + :isRequired="true" :value="modelValue" screenReaderOnlyText="(opens new window)" /> @@ -46,3 +46,15 @@ export default { }, }; + + \ No newline at end of file diff --git a/src/common-components/vehicle-banner/vehicle-banner.vue b/src/common-components/vehicle-banner/vehicle-banner.vue index e369cddb9..984657a47 100644 --- a/src/common-components/vehicle-banner/vehicle-banner.vue +++ b/src/common-components/vehicle-banner/vehicle-banner.vue @@ -1,5 +1,5 @@ - + { return {}; }, {virtual: true}); + +describe("make-question.vue", () => { + test("Selected make is emitted upon selection.", async () => { + + //Arrange + const { wrapper } = setupMocks({ modelValueProp: "honda" }); + const makeToSelect = "ford"; + + //Act + wrapper.setData({ selectedMake: makeToSelect }); + await wrapper.vm.$nextTick(); + + //Assert + expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["ford"]); + }); +}); + +describe("make-question.vue", () => { + test("CMS question text is used as radio question text.", async () => { + + //Arrange + const { wrapper, cmsContent } = setupMocks({ cmsQuestionText: "What make is your vehicle?" }); + + //Act + makeQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, null); + + //Assert + const buttonQuestionComponent = await wrapper.findComponent({ name: "buttonQuestion" }); + expect(buttonQuestionComponent.attributes("questiontext")).toBe("What make is your vehicle?"); + }); +}); + +describe("make-question.vue", () => { + test("Data from store api are used as radio question answers.", async () => { + + //Arrange + const { wrapper, cmsContent } = setupMocks({ dataFromStoreApi: ["honda", "ford", "dodge"] }); + + //Act + const initialData = makeQuestion.methods.loadInitialData.call(wrapper.vm); + makeQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, initialData); + + //Assert + const buttonQuestionComponent = await wrapper.findComponent({ name: "buttonQuestion" }); + expect(buttonQuestionComponent.attributes("answers")).toBe("honda,ford,dodge"); + }); +}); + + +function setupMocks({ + modelValueProp = "1900", + cmsQuestionText = "CMS text goes here", + dataFromStoreApi = [], +}) { + + //Mock store + store.dispatch = jest.fn(() => dataFromStoreApi); + store.getters = { vehicle: {year: 2019} }; + const mountOptions = getMountOptions({ + store: { + dispatch: store.dispatch, + getters: store.getters, + }, + }); + + //Mock props + mountOptions.propsData = { + modelValue: modelValueProp, + }; + const wrapper = shallowMount(makeQuestion, mountOptions); + + //Mock CMS content + const cmsContent = { + QuestionText: cmsQuestionText + }; + return { wrapper, cmsContent }; +} \ No newline at end of file diff --git a/src/layouts/vehicle-make/make-question/make-question.vue b/src/layouts/vehicle-make/make-question/make-question.vue new file mode 100644 index 000000000..765c7a542 --- /dev/null +++ b/src/layouts/vehicle-make/make-question/make-question.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/layouts/vehicle-make/vehicle-make.spec.js b/src/layouts/vehicle-make/vehicle-make.spec.js new file mode 100644 index 000000000..87df24e38 --- /dev/null +++ b/src/layouts/vehicle-make/vehicle-make.spec.js @@ -0,0 +1,93 @@ +import { shallowMount, flushPromises } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import vehicleMake from "@/layouts/vehicle-make/vehicle-make.vue"; +import makeQuestion from "@/layouts/vehicle-make/make-question/make-question"; +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { nextTick } from "vue"; + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +describe("vehicle-make.vue", () => { + test("Make question component is initized with api data", async (done) => { + + //Arange + const radioQuestionCmsContent = { QuestionText: "What make is your vehicle?" }; + const makeQuestionInitialData = ["honda", "ford", "dodge"]; + const { wrapper, apiPromise } = setupMocks( { + radioQuestionCmsContent: radioQuestionCmsContent, + makeQuestionInitialData: makeQuestionInitialData, + } ); + + //Act + vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm)); + + //Assert + apiPromise.finally(() => { + expect(makeQuestion.methods.initializeComponent).toHaveBeenCalledWith(radioQuestionCmsContent, makeQuestionInitialData); + done(); + }); + }); +}); + +describe("vehicle-make.vue", () => { + test("Page header is passed data from CMS", async (done) => { + + //Arange + const { wrapper, apiPromise } = setupMocks( { pageHeaderWidgetHeaderText: "Select a make to get started" }); + + //Act + vehicleMake.beforeRouteEnter.call(wrapper.vm, { query: { fmgPage: "vehicle-make" } }, undefined, (c) => c(wrapper.vm)); + + //Assert + const header = await wrapper.find(".Header"); + apiPromise.finally(() => { + expect(header.attributes("text")).toEqual("Select a make to get started"); + done(); + }); + }); +}); + +function setupMocks({ + radioQuestionCmsContent = {}, + makeQuestionInitialData = {}, + pageHeaderWidgetHeaderText = {}, +}) { + + //Mock api responses + const apiResponses = { + cmsContent: { + PageHeaderWidget: [{ HeaderText: pageHeaderWidgetHeaderText }], + RadioQuestionWidget: [radioQuestionCmsContent], + VehicleBannerWidget: [ + { + GenericVehicleImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3", + }, + ], + SiteHeaderWidget: [ + { + LogoImage: + "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", + }, + ], + }, + makeQuestionInitialData: makeQuestionInitialData, + }; + const apiPromise = Promise.resolve(apiResponses); + settleAllPromises.mockImplementation(() => apiPromise); + + //Mock make question methods + makeQuestion.methods = { + loadInitialData: jest.fn(), + initializeComponent: jest.fn(), + }; + const mountOptions = getMountOptions({ }); + const wrapper = shallowMount(vehicleMake, mountOptions); + const makeQuestionWrapper = wrapper.findComponent({ name: "makeQuestion" }); + makeQuestionWrapper.vm.initializeComponent = makeQuestion.methods.initializeComponent; + + return { wrapper, apiPromise }; +} \ No newline at end of file diff --git a/src/layouts/vehicle-make/vehicle-make.vue b/src/layouts/vehicle-make/vehicle-make.vue index f04bea0ec..a5abd776b 100644 --- a/src/layouts/vehicle-make/vehicle-make.vue +++ b/src/layouts/vehicle-make/vehicle-make.vue @@ -1,3 +1,77 @@ - Vehicle Make Layout - Do Something Cool Here - \ No newline at end of file + + + + + + + + + + + + + diff --git a/src/layouts/vehicle-year/vehicle-year.vue b/src/layouts/vehicle-year/vehicle-year.vue index 829601c6a..55591052f 100644 --- a/src/layouts/vehicle-year/vehicle-year.vue +++ b/src/layouts/vehicle-year/vehicle-year.vue @@ -69,7 +69,7 @@ export default { watch: { selectedYear(year) { this.$store.commit(this.storeMutations.UPDATE_YEAR, year); - this.$router.navigate(navigationScenarios.SELECTED_YEAR, this.$route); + this.$router.navigate(this.navigationScenarios.SELECTED_YEAR, this.$route); } }, @@ -81,15 +81,3 @@ export default { }, }; - - diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index afe618125..14da7a16b 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -1,5 +1,6 @@ import { storeActions } from "@/constants/store-actions.js"; import { storeMutations } from "@/constants/store-mutations.js"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { widgetNames } from "@/constants/widget-names.js"; export default { @@ -31,6 +32,9 @@ export default { storeMutations() { return storeMutations; }, + navigationScenarios() { + return navigationScenarios; + }, widgetNames() { return widgetNames; }, diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 826357f63..34f4c5579 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -39,4 +39,4 @@ const routingTable = [ }, ]; -export { routingTable }; +export { routingTable }; \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index 036694868..1bf7243b7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -65,6 +65,9 @@ export default createStore({ state.order.vehicle.year = year; }, }, + getters: { + vehicle: state => state.order.vehicle + }, actions: { // Vehicle API Actions getVehicleYears(context) { diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index a8ad64d8c..0e5424151 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -28,7 +28,7 @@ export default { props: { isCheckbox: Boolean, groupName: String, /* Required, unique for each button GROUP */ - buttonID: String, /* Required, unique for each button. Used for button id, label and */ + buttonID: [Number,String], /* Required, unique for each button. Used for button id, label and */ isRequired: Boolean, /* Optional, default is false */ screenReaderOnlyText: String, /* Optional, copy to be read by screenreader */ buttonLabelSubCopy: String, /* Optional, used for multi-line buttons */
Vehicle Make Layout - Do Something Cool Here