diff --git a/src/constants/payment-method-constants.js b/src/constants/payment-method-constants.js new file mode 100644 index 00000000..0799f2b2 --- /dev/null +++ b/src/constants/payment-method-constants.js @@ -0,0 +1,7 @@ +export const paymentMethods = { + NONE: null, + LATER: "Later", + CREDIT_CARD: "CreditCard", + PAYPAL: "Paypal", + AFTERPAY: "Afterpay", +}; diff --git a/src/iss-components/nav-bar/nav-bar.spec.js b/src/iss-components/nav-bar/nav-bar.spec.js new file mode 100644 index 00000000..68b9f6c8 --- /dev/null +++ b/src/iss-components/nav-bar/nav-bar.spec.js @@ -0,0 +1,59 @@ +import { mount } from "@vue/test-utils"; +import navbar from "./nav-bar"; + +describe("nav-bar.vue", () => { + test("Should emit ForwardClicked on button click", async () => { + // Act + const wrapper = mount(navbar, { + mixins: [mockMixin], + }); + wrapper.vm.buttonClick(); + // Assert + expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled; + }); + + test("Should emit BackClicked on link click", async () => { + // Act + const wrapper = mount(navbar, { + mixins: [mockMixin], + }); + wrapper.vm.linkClick(); + // Assert + expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled; + }); + + test("Should change button text when update button text is called", async () => { + // Act + const wrapper = mount(navbar, { + mixins: [mockMixin], + }); + wrapper.vm.updateButtonText("newText"); + + // Assert + expect(wrapper.componentVM.customButtontext).toBe("newText"); + }); + + test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => { + // Arrange + const wrapper = mount(navbar, { + mixins: [mockMixin], + }); + + // Act + wrapper.vm.$refs.buttonMain.removeLoader = jest.fn(); + wrapper.vm.removeLoader(); + const spy = jest.spyOn(document, "onkeydown"); + document.onkeydown(); + + // Assert + expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled(); + expect(spy).toReturnWith(true); + }); +}); + +const mockMixin = { + methods: { + getCmsContent: jest.fn(), + getFooterInfoBoxHeight: jest.fn(() => 80), + }, +}; diff --git a/src/iss-components/nav-bar/nav-bar.vue b/src/iss-components/nav-bar/nav-bar.vue new file mode 100644 index 00000000..631e5c0e --- /dev/null +++ b/src/iss-components/nav-bar/nav-bar.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js new file mode 100644 index 00000000..8cf6c55b --- /dev/null +++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js @@ -0,0 +1,104 @@ +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +import paymentMethodListButton from "@/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button"; + +const testConstants = { + images: { + A: "imageA", + B: "imageB", + NONE: null, + }, + names: { + A: "nameA", + B: "nameB", + }, + content: { + withInline: "Button text with {custom:inlineImage} inline.", + noInline: "Button text with no inline", + }, +}; + +let cmsContent; + +describe("Payment Method Question", () => { + beforeEach(() => { + cmsContent = {}; + }); + + describe("Side image", () => { + it("Renders side image if image is present and not inline", () => { + // Arrange + const props = generateDefaultProps(); + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(true); + }); + + it("Does not render side image if no image is present", () => { + // Arrange + let props = generateDefaultProps(); + + props.buttonImage = testConstants.images.NONE; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(false); + }); + + it("Does not render side image if inline", () => { + // Arrange + let props = generateDefaultProps(); + + props.buttonLabel = testConstants.content.withInline; + props.altText = testConstants.content.withInline; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(false); + }); + }); +}); + +function generateDefaultProps() { + return { + buttonLabel: testConstants.noInline, + altText: testConstants.noInline, + groupName: "payment-method", + value: testConstants.names.A, + buttonImage: testConstants.images.A, + }; +} + +function setupMocks(customMountOptions) { + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(paymentMethodListButton, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue new file mode 100644 index 00000000..2763f1af --- /dev/null +++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/layouts/payment-method/payment-method-question/payment-method-question.spec.js b/src/layouts/payment-method/payment-method-question/payment-method-question.spec.js new file mode 100644 index 00000000..d3a486d5 --- /dev/null +++ b/src/layouts/payment-method/payment-method-question/payment-method-question.spec.js @@ -0,0 +1,130 @@ +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + +import paymentMethodQuestion from "@/layouts/payment-method/payment-method-question/payment-method-question"; + +const testConstants = { + cms: { + question: { + text: "Choose a payment option", + }, + answers: { + optionA: { + name: "NameA", + text: "TextA", + subText: "SubTextA", + imageId: "idA", + image: "imageA", + subWidget: "subWidgetA", + }, + optionB: { + name: "NameB", + text: "TextB", + subText: "SubTextB", + imageId: "idB", + image: "imageB", + subWidget: "subWidgetB", + }, + }, + }, +}; + +let cmsContent; + +describe("Payment Method Question", () => { + beforeEach(() => { + cmsContent = { + PaymentMethodWidget: { + QuestionText: testConstants.cms.question, + Answers: [ + { + Name: testConstants.cms.answers.optionA.name, + Text: testConstants.cms.answers.optionA.text, + SubText: testConstants.cms.answers.optionA.subText, + ImageId: testConstants.cms.answers.optionA.imageId, + AnswerImageUrl: testConstants.cms.answers.optionA.image, + SubWidgetName: testConstants.cms.answers.optionA.subWidget, + }, + { + Name: testConstants.cms.answers.optionB.name, + Text: testConstants.cms.answers.optionB.text, + SubText: testConstants.cms.answers.optionB.subText, + ImageId: testConstants.cms.answers.optionB.imageId, + AnswerImageUrl: testConstants.cms.answers.optionB.image, + SubWidgetName: testConstants.cms.answers.optionB.subWidget, + }, + ], + }, + }; + }); + + it("Should map cms content correctly", () => { + // Arrange + const props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + const mappedContent = wrapper.vm.paymentMethodAnswerData; + + // Assert + expect(mappedContent).toEqual([ + { + buttonLabel: testConstants.cms.answers.optionA.text, + altText: testConstants.cms.answers.optionA.text, + groupName: "payment-method", + value: testConstants.cms.answers.optionA.name, + buttonImage: testConstants.cms.answers.optionA.image, + }, + { + buttonLabel: testConstants.cms.answers.optionB.text, + altText: testConstants.cms.answers.optionB.text, + groupName: "payment-method", + value: testConstants.cms.answers.optionB.name, + buttonImage: testConstants.cms.answers.optionB.image, + }, + ]); + }); + + it("Handles null cms content gracefully", () => { + // Arrange + cmsContent = {}; + const props = generateDefaultProps(); + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + const mappedContent = wrapper.vm.paymentMethodAnswerData; + + // Assert + expect(mappedContent).toEqual([]); + }); +}); + +function generateDefaultProps() { + return { + modelValue: "modelValue", + }; +} + +function setupMocks(customMountOptions) { + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(paymentMethodQuestion, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} diff --git a/src/layouts/payment-method/payment-method-question/payment-method-question.vue b/src/layouts/payment-method/payment-method-question/payment-method-question.vue new file mode 100644 index 00000000..bbd0617b --- /dev/null +++ b/src/layouts/payment-method/payment-method-question/payment-method-question.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index a7ca3dba..190e82c5 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -4,6 +4,7 @@ v-slot="{ meta }" @submit="onSubmit" @invalidSubmit="onInvalidSubmit"> +
Cart Placeholder

Pia Alert Placeholder
-
Payment Method Question
+
Pia Disabled Placeholder
- @@ -39,14 +43,17 @@ diff --git a/src/store/index.js b/src/store/index.js index a4e9f04d..fe6538cd 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -13,6 +13,7 @@ import damageLocationsSelected from '@/constants/damage-locations-selected'; import coverageStatuses from '@/constants/coverage-statuses'; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants'; import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper'; +import { paymentMethods } from "@/constants/payment-method-constants"; const storeId = 'main'; @@ -147,7 +148,9 @@ const getDefaultState = () => ({ coverageStatus: coverageStatuses.PENDING, claimNumber: null }, - parentAccountNumber: 0 + parentAccountNumber: 0, + isPia: null, + piaType: null, }, contactInfo: { firstName: null, @@ -2127,7 +2130,13 @@ export const useMainStore = defineStore({ this.resetVehicleState(); this.resetDamageState(); this.resetBailout(); - } + }, + + savePaymentMethodChoice(paymentMethod) { + const isPia = paymentMethod !== paymentMethods.LATER; + this.order.payment.isPia = isPia; + this.order.payment.piaType = isPia ? paymentMethod : null; + }, }, persist: true