diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 3356787a1..58f22ebe2 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -43,6 +43,7 @@ const errorMessages = { INSURANCE_COMPANY_NAME_REQUIRED: "Please enter your insurance company name", POLICY_NUMBER_REQUIRED: "Please enter your policy number", POLICY_NUMBER_FORMAT: "Please enter a valid policy number", + CLAIM_NUMBER_REQUIRED: "Please enter your claim number", CLAIM_NUMBER_VALID: "Please enter a valid claim number", CLAIM_NUMBER_FORMAT: "Claim number must be 6 to 8 digits", DATE_OF_LOSS_REQUIRED: "Please enter your date of damage", diff --git a/src/constants/more-policy-questions.js b/src/constants/more-policy-questions.js new file mode 100644 index 000000000..7f7e51c3d --- /dev/null +++ b/src/constants/more-policy-questions.js @@ -0,0 +1,54 @@ +// CMS answer `Name` values that can appear in MorePolicyQuestionsWidget / +// MorePolicyQuestionsOverrideWidget's Answers array (CMS content is a superset +// across both widget variants). +export const morePolicyQuestionAnswers = { + ADDITIONAL_DAMAGE: "AdditionalDamage", + RENTAL: "Rental", + OTHER_RESPONSIBLE_PARTY: "OtherResponsibleParty", + THIRD_PARTY_VEHICLE: "ThirdPartyVehicle", + INJURIES: "Injuries", +}; + +// Maps each possible CMS answer Name to the boolean flag persisted in the store +// and sent to the save-session API, regardless of which widget variant (and +// therefore which subset of answers) is shown to the user. +export const morePolicyQuestionAnswerToFlag = { + [morePolicyQuestionAnswers.ADDITIONAL_DAMAGE]: "additionalDamage", + [morePolicyQuestionAnswers.RENTAL]: "rental", + [morePolicyQuestionAnswers.OTHER_RESPONSIBLE_PARTY]: "otherResponsibleParty", + [morePolicyQuestionAnswers.THIRD_PARTY_VEHICLE]: "thirdPartyVehicle", + [morePolicyQuestionAnswers.INJURIES]: "injuries", +}; + +export function getDefaultMorePolicyQuestions() { + return Object.values(morePolicyQuestionAnswerToFlag).reduce((flags, flagName) => { + flags[flagName] = false; + return flags; + }, {}); +} + +// Converts the array of selected CMS answer Names (as emitted by the +// checkbox-based buttonQuestion component) into the boolean-flag object shape +// that is persisted to the store and sent to the backend. +export function morePolicyQuestionAnswerNamesToFlags(selectedAnswerNames) { + const flags = getDefaultMorePolicyQuestions(); + for (const answerName of Array.isArray(selectedAnswerNames) ? selectedAnswerNames : []) { + const flagName = morePolicyQuestionAnswerToFlag[answerName]; + if (flagName) { + flags[flagName] = true; + } + } + return flags; +} + +// Reverses morePolicyQuestionAnswerNamesToFlags, so the checkbox-based +// buttonQuestion component (which expects an array of selected values) can be +// pre-populated from previously persisted flags. +export function morePolicyQuestionFlagsToAnswerNames(flags) { + if (!flags) { + return []; + } + return Object.entries(morePolicyQuestionAnswerToFlag) + .filter(([, flagName]) => flags[flagName]) + .map(([answerName]) => answerName); +} diff --git a/src/layouts/policy-info/more-policy-questions/more-policy-questions.spec.js b/src/layouts/policy-info/more-policy-questions/more-policy-questions.spec.js new file mode 100644 index 000000000..a6e1175b5 --- /dev/null +++ b/src/layouts/policy-info/more-policy-questions/more-policy-questions.spec.js @@ -0,0 +1,88 @@ +import { shallowMount } from "@vue/test-utils"; +import morePolicyQuestions from "./more-policy-questions"; + +const answersFromCms = [ + { Name: "AdditionalDamage", Text: "Additional damage occurred" }, + { Name: "Rental", Text: "The vehicle was a rental" }, + { Name: "OtherResponsibleParty", Text: "Another party is responsible" }, +]; + +const mockMixin = { + methods: { + getCmsContent: jest.fn().mockImplementation((widgetName, property) => { + if (property === "Answers") { + return answersFromCms; + } + return "Please select all that apply"; + }), + }, +}; + +function mountComponent(modelValue) { + return shallowMount(morePolicyQuestions, { + props: { + modelValue, + groupName: "MorePolicyQuestionsQuestion", + cmsWidgetName: "MorePolicyQuestionsWidget", + }, + mixins: [mockMixin], + }); +} + +describe("more-policy-questions.vue", () => { + it("converts previously selected boolean flags into the array of CMS answer Names for the checkbox group", () => { + // Act + const wrapper = mountComponent({ + additionalDamage: true, + rental: false, + otherResponsibleParty: true, + thirdPartyVehicle: false, + injuries: false, + }); + + // Assert + expect(wrapper.vm.selectedValues).toEqual(["AdditionalDamage", "OtherResponsibleParty"]); + }); + + it("treats a null/undefined modelValue as no answers selected", () => { + // Act + const wrapper = mountComponent(undefined); + + // Assert + expect(wrapper.vm.selectedValues).toEqual([]); + }); + + it("emits a full set of boolean flags reflecting which CMS answer Names were checked", () => { + // Arrange + const wrapper = mountComponent({}); + + // Act + wrapper.vm.selectedValues = ["Rental", "Injuries"]; + + // Assert + expect(wrapper.emitted("update:modelValue")[0][0]).toEqual({ + additionalDamage: false, + rental: true, + otherResponsibleParty: false, + thirdPartyVehicle: false, + injuries: true, + }); + }); + + it("emits every flag as false when no answers are checked", () => { + // Arrange + const wrapper = mountComponent({ rental: true }); + + // Act + wrapper.vm.selectedValues = []; + + // Assert + expect(wrapper.emitted("update:modelValue")[0][0]).toEqual({ + additionalDamage: false, + rental: false, + otherResponsibleParty: false, + thirdPartyVehicle: false, + injuries: false, + }); + }); +}); diff --git a/src/layouts/policy-info/more-policy-questions/more-policy-questions.vue b/src/layouts/policy-info/more-policy-questions/more-policy-questions.vue index 44c9d5fb9..1523062ac 100644 --- a/src/layouts/policy-info/more-policy-questions/more-policy-questions.vue +++ b/src/layouts/policy-info/more-policy-questions/more-policy-questions.vue @@ -13,11 +13,18 @@