diff --git a/src/common-components/dropdown-question/dropdown-question.spec.js b/src/common-components/dropdown-question/dropdown-question.spec.js new file mode 100644 index 00000000..381f3489 --- /dev/null +++ b/src/common-components/dropdown-question/dropdown-question.spec.js @@ -0,0 +1,170 @@ +import { shallowMount } from "@vue/test-utils"; +import dropdownQuestion from "./dropdown-question"; + +// Mock CMS content +const questionText = "Question Text"; +const mockMixin = { + methods: { + getCmsContent: jest.fn().mockImplementation(()=> { + return questionText; + }) + } +} + +// TODO: Remove the following from dropdown-question.vue -> :class="(errors && errors.length) || hasError ? 'has-error' : ''" +// It is not being used. +describe("dropdownQuestion.vue", () => { + + it("Should render a select input", async () => { + + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + wrapper.getCmsContent = jest.fn(); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.exists()).toBe(true); + + }); + + it("Should render the 'questionText' data value as the label text.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.text()).toContain(questionText); + + }); + + it("Should render the 'questionText' data value with '⁠' after the first character of each word in the label text when disableAutoFill is true.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + disableAutoFill: true, + }, + mixins: [mockMixin] + }); + + // Mock CMS content ... + // Trust me, the below instance of the string "Q⁠uestion Text" actually has the ⁠ in it. You just can't see it + // Don't believe me? Copy and paste it into Google. Then inspect the search field element in Dev Tools, + // you will see "Q⁠uestion T⁠ext" + const expectedQuestionText = "Q⁠uestion T⁠ext"; + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.text()).toContain(expectedQuestionText); + + }); + + it("Should return input id as the id of the select field", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + inputId: "input ID", + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.attributes().id).toEqual("input ID"); + + }); + + it("Should render the 'questionText' data value as the aria-label attribute.", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + }, + mixins: [mockMixin] + }); + + // Act + const label = wrapper.find("label"); + + // Assert + expect(label.attributes("aria-label")).toContain(questionText); + + }); + + it("Should return aria-disabled state as disabled", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + isDisabled: true, + }, + mixins: [mockMixin] + }); + + // Act + const select = wrapper.find("select"); + + // Assert + expect(select.attributes("aria-disabled")).toEqual("true"); + + }); + + it("Should emit new value when modelValue is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: "val", + }, + mixins: [mockMixin] + }); + + // Act + await wrapper.find("select").setValue("val2"); + + // Assert + expect(wrapper.emitted()).toHaveProperty('change') + + }); + + it("Should call this.handleChange with new value when selectedOption is changed", async () => { + // Arrange + const wrapper = shallowMount(dropdownQuestion, { + propsData: { + options: {}, + modelValue: 0, + }, + mixins: [mockMixin] + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + + // Act + wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1); + + // Assert + expect(wrapper.vm.handleChange).toHaveBeenCalled; + + }); + +}); diff --git a/src/common-components/dropdown-question/dropdown-question.vue b/src/common-components/dropdown-question/dropdown-question.vue new file mode 100644 index 00000000..8e6ae0fa --- /dev/null +++ b/src/common-components/dropdown-question/dropdown-question.vue @@ -0,0 +1,152 @@ + + + + + + + diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 62fa856a..500bde97 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -29,7 +29,8 @@ const errorMessages = { POLICY_ZIP_REQUIRED: "Please enter policy zip", POLICY_ZIP_FORMAT: "Please enter a valid policy ZIP", LOSS_CAUSE_REQUIRED: "Please enter loss cause", - LOSS_CITY_REQUIRED: "Please enter loss city" + LOSS_CITY_REQUIRED: "Please enter loss city", + LOSS_STATE_REQUIRED: "Please enter loss state" }; export { errorMessages }; \ No newline at end of file diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 98794a76..92c1fc21 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -4,6 +4,17 @@

Welcome Page Placeholder


+
+ +
@@ -15,32 +26,114 @@ import siteHeader from '@/common-components/site-header/site-header'; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; + import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question"; + import { defineRule } from "vee-validate"; + import { required } from "@/helpers/validation-rules"; + import { errorMessages } from "@/constants/error-messages"; + //define validation rules + defineRule("loss-state-required", required(errorMessages.STATE_REQUIRED)); - export default { + export default ({ name: "welcome-page", - components: { navButton, siteHeader }, + emits: ['update:modelValue'], // The component emits an event + props: { + modelValue: { + type: Object, + default: () => ({ + lossState: "", + }), + }, + validationRules: String, + }, + components: { navButton, siteHeader, dropdownQuestion }, async beforeRouteEnter(to, from, next) + { + // Call APIs + const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); + + // Settle promises and get results + const promiseResultMap = [ { - // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); - - // Settle promises and get results - const promiseResultMap = [ - { - resultKey: "cmsContent", - promise: cmsContentPromise, - }, - ]; + resultKey: "cmsContent", + promise: cmsContentPromise, + }, + ]; - //use resultMap to populate layout content. - let resultMap = await settleAllPromises(promiseResultMap); + //use resultMap to populate layout content. + let resultMap = await settleAllPromises(promiseResultMap); - next((vm) => { - vm.setCmsContent(resultMap.cmsContent); - }); - }, - } + next((vm) => { + vm.setCmsContent(resultMap.cmsContent); + }); + }, + computed: + { + stateOptions: { + get: function () { + return { + 'AL': 'Alabama', + 'AK': 'Alaska', + 'AZ': 'Arizona', + 'AR': 'Arkansas', + 'CA': 'California', + 'CO': 'Colorado', + 'CT': 'Connecticut', + 'DE': 'Delaware', + 'DC': 'District Of Columbia', + 'FL': 'Florida', + 'GA': 'Georgia', + 'HI': 'Hawaii', + 'ID': 'Idaho', + 'IL': 'Illinois', + 'IN': 'Indiana', + 'IA': 'Iowa', + 'KS': 'Kansas', + 'KY': 'Kentucky', + 'LA': 'Louisiana', + 'ME': 'Maine', + 'MD': 'Maryland', + 'MA': 'Massachusetts', + 'MI': 'Michigan', + 'MN': 'Minnesota', + 'MS': 'Mississippi', + 'MO': 'Missouri', + 'MT': 'Montana', + 'NE': 'Nebraska', + 'NV': 'Nevada', + 'NH': 'New Hampshire', + 'NJ': 'New Jersey', + 'NM': 'New Mexico', + 'NY': 'New York', + 'NC': 'North Carolina', + 'ND': 'North Dakota', + 'OH': 'Ohio', + 'OK': 'Oklahoma', + 'OR': 'Oregon', + 'PA': 'Pennsylvania', + 'RI': 'Rhode Island', + 'SC': 'South Carolina', + 'SD': 'South Dakota', + 'TN': 'Tennessee', + 'TX': 'Texas', + 'UT': 'Utah', + 'VT': 'Vermont', + 'VA': 'Virginia', + 'WA': 'Washington', + 'WV': 'West Virginia', + 'WI': 'Wisconsin', + 'WY': 'Wyoming', + } + } + }, + addressModel: + { + get: function() { + return this.modelValue; + }, + }, + } + })