diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9f677925..8c04697c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -342,6 +342,7 @@ stages: - template: templates/digital/auto-tag.yml@AzureDevOps parameters: dependsOn: prodBuildDeployment + environment: digitalCloud-prod userName: SafeliteAzureDevops userEmail: githubazuredevops@safelite.com diff --git a/src/helpers/recal-helper.js b/src/helpers/recal-helper.js index c6cce97e..f364bf68 100644 --- a/src/helpers/recal-helper.js +++ b/src/helpers/recal-helper.js @@ -73,3 +73,22 @@ export function containsRecalParts(lineItems) { } } +export function anyPartWithRequiresRecalFlag(lineItems) { + if (!lineItems) { + return false; + } + + if (Array.isArray(lineItems)) { + return lineItems.some((li) => li.requiresRecalibration === true); + } + + const flattened = [ + ...(lineItems.glassParts ?? []), + ...(lineItems.supportingItems ?? []), + ...(lineItems.otherParts ?? []), + ...(lineItems.feeItems ?? []), + ...(lineItems.vaps ?? []), + ]; + + return flattened.some((li) => li.requiresRecalibration === true); +} diff --git a/src/iss-components/recal-modal/recal-modal.vue b/src/iss-components/recal-modal/recal-modal.vue index 2564c9cf..9563d561 100644 --- a/src/iss-components/recal-modal/recal-modal.vue +++ b/src/iss-components/recal-modal/recal-modal.vue @@ -30,6 +30,7 @@ export default { default: 'RecalModal' } }, + emits: ['recal-modal-opened'], computed: { modalBodyText() { return this.getCmsContent(this.cmsWidgetName, 'BodyText').replaceAll('{custom:vehicleMake}', this.vehicleMake); @@ -50,6 +51,7 @@ export default { methods: { openModal() { this.$refs.recalModal.openModal(); + this.$emit('recal-modal-opened'); }, footerButtonClick() { this.$refs.recalModal.closeModal(); diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index dcccbed6..5c056587 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -14,6 +14,7 @@ import { useMainStore } from '@/store'; import { getPriceOfLineItems } from '@/helpers/price-calculator.js'; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; +import { containsRecalParts } from '@/helpers/recal-helper'; jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/price-calculator.js', () => ({ @@ -36,8 +37,6 @@ jest.mock('@/helpers/recal-helper.js', () => ({ containsRecalParts: jest.fn() })); -import { containsRecalParts } from '@/helpers/recal-helper.js'; - const SAFELITE_PROVIDER = 'Safelite'; const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal'; @@ -115,7 +114,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.PENDING, @@ -343,7 +343,7 @@ describe('coverageStatement.vue', () => { // Assert expect(result).toBeFalsy(); }); - test('returns true when a part in glassParts require recalibration and recalibration has been added to order', () => { + test('returns true when a part in glassParts requires recalibration and recalibration has been added to order', () => { // Arrange containsRecalParts.mockReturnValue(true); const mainInitialState = { @@ -614,7 +614,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.PENDING, @@ -644,7 +645,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.VERIFIED, @@ -673,7 +675,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.VERIFIED, @@ -705,7 +708,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.VERIFIED, @@ -732,7 +736,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.VERIFIED, @@ -763,7 +768,8 @@ describe('coverageStatement.vue', () => { const mainInitialState = { order: { damage: { - isRepair: true + isRepair: true, + numberOfChips: 2 }, insuranceCoverage: { coverageStatus: coverageStatuses.VERIFIED, diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 0e2dadc4..88a0ecb7 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -103,14 +103,16 @@ + cmsWidgetName="RecalModal" + @recalModalOpened="handleRecalModalOpened" /> + cmsWidgetName="OEMEndorsementModal" + @oemEndorsementModalOpened="handleOemEndorsementModalOpened" /> @@ -377,6 +379,71 @@ export default { setupModalLinks(this); }, methods: { + logEventsToGA() { + const clientName = this.mainStore.accountNameForEvents; + + if (this.isDeductibleVisible || this.isITACQuoteVisible) { + this.pushEventToGA('coverage', 'Yes', clientName, true, null, '1'); + if (this.isITACQuoteVisible) { + this.pushEventToGA('Coverage', 'ITAC', `${this.deductibleValue}_${this.totalServicePrice}`, true); + } + else { + this.pushEventToGA('coverage', 'full_comprehensive', clientName, true); + this.pushEventToGA('coverage', 'deductible', this.deductibleValue.toString(), true); + } + } + else { + this.pushEventToGA('coverage', 'No', clientName, true, null, '0'); + if (this.isNoCompQuoteVisible) { + this.pushEventToGA('coverage', 'no_comprehensive', `${this.totalServicePrice}`, true); + this.pushEventToGA('coverage', 'deductible', '9999', true); + } + else { + this.pushEventToGA('coverage', 'deductible', '7777', true); + } + } + + if (this.mainStore.hasOemEndorsement) { + this.pushEventToGA('oem_endorsement', 'displayed', 'Yes', true, null, '1'); + } + else { + this.pushEventToGA('oem_endorsement', 'displayed', 'No', true, null, '0'); + } + + if (this.isADAS) { + if (this.mainStore.vehicle.canSafeliteService) { + this.pushEventToGA('ADAS_self_service', 'ADAS_servicable_status', 'yes', true); + if (this.mainStore.hasRecalibrationPart) { + if (this.isDeductibleVisible) { + const recalibrationType = this.mainStore.lineItems.glassParts.find((part) => part.requiresRecalibration).recalibrationType; + if (this.deductibleValue <= 0) { + this.pushEventToGA('recalibration_opportunity_verified_0_deductible', this.mainStore.vehicle.carId, `recal_type_${recalibrationType}`, true); + } + else { + this.pushEventToGA('recalibration_opportunity_verified_over_0_deductible', this.mainStore.vehicle.carId, `recal_type_${recalibrationType}`, true); + } + } + else { + let appointmentType = ''; + if (this.isITACQuoteVisible) { + appointmentType = 'ITAC'; + } + else if (this.isNoCompQuoteVisible) { + appointmentType = 'no_comp'; + } + else { + appointmentType = 'unverified'; + } + this.pushEventToGA(`recalibration_opportunity_${appointmentType}`, this.mainStore.vehicle.carId, `recal_type_${this.mainStore.lineItems.glassParts.find((part) => part.requiresRecalibration).recalibrationType}`, true); + } + } + } + else { + this.pushEventToGA('ADAS_self_service', 'ADAS_servicable_status', 'no', true); + } + } + }, + arePagePrerequisitesValid() { return !!useMainStore().vehicle.carId; }, @@ -396,6 +463,8 @@ export default { } } + this.logEventsToGA(); + showIssLoadingModal(false); this.isPageLoading = false; }, @@ -414,7 +483,13 @@ export default { }, async navigateForward() { showIssLoadingModal(true); - if (this.isUnverifiedVisible || this.isDeductibleVisible) { + if (this.isUnverifiedVisible || this.isDeductibleVisible) { + if (this.isRepair) { + this.pushEventToGA('RepairDamage', 'Repair', this.mainStore.damage.numberOfChips.toString(), true, null, '1'); + } + else { + this.pushEventToGA('RepairDamage', 'Replacement', 'Replacement', true, null, '1'); + } this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD); } else if (this.isITACQuoteVisible || this.isNoCompQuoteVisible) { this.mainStore.updateIsSafeliteProvider(true); @@ -478,7 +553,13 @@ export default { cancelClaim() { this.mainStore.updateIsSafeliteProvider(false); this.$router.navigateBailout(bailoutMessage.CoverageCancelledByUser()); - } + }, + handleRecalModalOpened() { + this.pushEventToGA('recalibration_modal', 'learn_more_clicked', this.mainStore.vehicle.carId, true); + }, + handleOemEndorsementModalOpened() { + this.pushEventToGA('oem_endorsement_modal', 'clicked', 'Yes', true, null, '1'); + }, } }; diff --git a/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue b/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue index 85ee726b..6daff222 100644 --- a/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue +++ b/src/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue @@ -26,6 +26,7 @@ export default { default: 'OEMEndorsementModal' } }, + emits: ['oem-endorsement-modal-opened'], computed: { modalBodyText() { return this.getCmsContent(this.cmsWidgetName, 'BodyText'); @@ -40,6 +41,7 @@ export default { methods: { openModal() { this.$refs.oemEndorsementModal.openModal(); + this.$emit('oem-endorsement-modal-opened'); }, footerButtonClick() { this.$refs.oemEndorsementModal.closeModal(); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index d533f276..21ce4fc7 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -193,7 +193,7 @@ export default { appointmentType: serviceLocation.appointmentType, providerAddress: serviceLocation?.provider?.address, customerPortalLoginToken, - carrierName: issConfig.clientName, + carrierName: issConfig.clientDisplayName, carrierUrl: issConfig.successReturnURL, isRepair: damage.isRepair, hasRecalibrationPart, diff --git a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue index 53b2d204..2c64ba69 100644 --- a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue +++ b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue @@ -6,11 +6,12 @@ linkType="text" href="#!" :text="textForToggle" - @click="handleClickToggle" /> -
+
+ @click="handleClickToggle">
+
+ +
+ +
+ + + +
+

{{ errorMessage }}

+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue b/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue new file mode 100644 index 00000000..c4525695 --- /dev/null +++ b/src/layouts/schedule-page/recal-ack-modal/recal-ack-toggle/recal-ack-toggle.vue @@ -0,0 +1,115 @@ + + + diff --git a/src/layouts/schedule-page/schedule-page.spec.js b/src/layouts/schedule-page/schedule-page.spec.js index a418f35e..fefde032 100644 --- a/src/layouts/schedule-page/schedule-page.spec.js +++ b/src/layouts/schedule-page/schedule-page.spec.js @@ -12,6 +12,8 @@ jest.mock('@/helpers/cms-content-helper', () => ({ fetchCmsContentForPage: jest.fn() })); +const RECAL_ACK_MODAL_REF_NAME = 'recalAckModal'; + const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => ''), @@ -55,6 +57,22 @@ const loadingModalStub = { } }; +const serviceLocationStub = { + render: () => {}, + methods: { + forwardButtonAction: jest.fn(), + initializeComponent: jest.fn() + } +}; + +const recalAckModalStub = { + template: '
', + methods: { + openModal: jest.fn(), + footerButtonClick: jest.fn() + } +}; + function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { const mountOptions = getMountOptions({ router: { @@ -64,7 +82,9 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { mountOptions.global.stubs = { siteFooter: footerStub, - loadingModal: loadingModalStub + loadingModal: loadingModalStub, + serviceLocation: serviceLocationStub, + recalAckModal: recalAckModalStub }; methodToRun(); @@ -75,6 +95,27 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { ); const wrapper = shallowMount(schedule, mountOptions); + + // Manually create the ref for recalAckModal since shallowMount doesn't populate it + Object.defineProperty(wrapper.vm.$refs, RECAL_ACK_MODAL_REF_NAME, { + value: { + openModal: jest.fn(), + footerButtonClick: jest.fn() + }, + writable: false, + configurable: true + }); + + // Manually create the ref for serviceLocation since shallowMount doesn't populate it + Object.defineProperty(wrapper.vm.$refs, 'serviceLocation', { + value: { + forwardButtonAction: jest.fn(), + initializeComponent: jest.fn() + }, + writable: false, + configurable: true + }); + return { wrapper }; } @@ -126,152 +167,163 @@ afterEach(() => { jest.clearAllMocks(); }); -describe('schedule-page.vue', () => { - beforeAll(() => { - Object.defineProperty(window, 'matchMedia', { value: jest.fn().mockImplementation((query) => ({ - matches: false, - media: query, - onchange: null, - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn() - })), - writable: true }); +beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn() + })), + writable: true }); +}); +describe('Initial Load', () => { + test('Should pass arePagePrerequisitesValid with a serviceLocation zipcode [in beforeEach]', () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + + // Act + const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(arePagePrerequisitesValid).toBe(true); }); - describe('Initial Load', () => { - test('Should pass arePagePrerequisitesValid with a serviceLocation zipcode [in beforeEach]', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); + test('Should fail arePagePrerequisitesValid with no serviceLocation zipcode', () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.mainStore.order.serviceLocation.zipCode = null; - // Act - const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); + // Act + const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - // Assert - expect(arePagePrerequisitesValid).toBe(true); - }); - test('Should fail arePagePrerequisitesValid with no serviceLocation zipcode', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.zipCode = null; - - // Act - const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(arePagePrerequisitesValid).toBeFalsy(); - }); - test('should return newShopTimeSlots when getAvailableDatesMethod is called', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.selectableDatesData = { - days: [] - }; - const store = useMainStore(); - store.getShopTimeSlots.mockImplementation(() => Promise.resolve({ - data: { - estimatedServiceMinutesMinimum: 90, - estimatedServiceMinutesMaximum: 120, - days: [ - { - date: '2023-12-01', - timeSlots: [ - { - id: '06747-01820-S-B*20424*7 AM', - startTime: '07:00', - endTime: '08:00', - offerPremium: false - } - ] - } - ] - } - })); - - // Act - const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod( - '2023-01-01', - '2023-01-15' - ); - - // Assert - expect(newShopTimeSlots).toStrictEqual({ + // Assert + expect(arePagePrerequisitesValid).toBeFalsy(); + }); + test('should return newShopTimeSlots when getAvailableDatesMethod is called', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.selectableDatesData = { + days: [] + }; + const store = useMainStore(); + store.getShopTimeSlots.mockImplementation(() => Promise.resolve({ + data: { + estimatedServiceMinutesMinimum: 90, + estimatedServiceMinutesMaximum: 120, days: [ { date: '2023-12-01', timeSlots: [ { - endTime: '08:00', id: '06747-01820-S-B*20424*7 AM', - offerPremium: false, - startTime: '07:00' + startTime: '07:00', + endTime: '08:00', + offerPremium: false } ] } - ], - estimatedServiceMinutesMinimum: 90, - estimatedServiceMinutesMaximum: 120 - }); - }); - test('Should call API service in days of 15 or less when getAvailableDatesMethod is called with large date ranges', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.selectableDatesData = { - days: [] - }; - const store = useMainStore(); - store.getShopTimeSlots.mockImplementation(() => Promise.resolve({ - data: { - estimatedServiceMinutesMinimum: 90, - estimatedServiceMinutesMaximum: 120, - days: [] + ] + } + })); + + // Act + const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod( + '2023-01-01', + '2023-01-15' + ); + + // Assert + expect(newShopTimeSlots).toStrictEqual({ + days: [ + { + date: '2023-12-01', + timeSlots: [ + { + endTime: '08:00', + id: '06747-01820-S-B*20424*7 AM', + offerPremium: false, + startTime: '07:00' + } + ] } - })); - - // Act - await wrapper.vm.getAvailableDates.call( - wrapper.vm, - '2023-01-01', - '2023-03-31', - 'Inshop', - '123', - '43228' - ); - - // Assert - // 2023-01-01 --> 2023-02-05 - // 2023-02-06 --> 2023-03-12 - // 2023-03-13 --> 2023-03-31 - expect(store.getShopTimeSlots).toHaveBeenCalledTimes(6); + ], + estimatedServiceMinutesMinimum: 90, + estimatedServiceMinutesMaximum: 120 }); }); - describe('Rendering', () => { - test('Schedule page loads', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - - // Assert - expect(wrapper).toBeTruthy(); - }); - }); - describe('schedule page methods...', () => { - test('getServiceZipCtuCodeFromStore should return zipCodeCtu', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.selectableDatesData = { + test('Should call API service in days of 15 or less when getAvailableDatesMethod is called with large date ranges', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.selectableDatesData = { + days: [] + }; + const store = useMainStore(); + store.getShopTimeSlots.mockImplementation(() => Promise.resolve({ + data: { + estimatedServiceMinutesMinimum: 90, + estimatedServiceMinutesMaximum: 120, days: [] - }; + } + })); - // Act - const testValue = wrapper.vm.getServiceZipCtuCodeFromStore(); + // Act + await wrapper.vm.getAvailableDates.call( + wrapper.vm, + '2023-01-01', + '2023-03-31', + 'Inshop', + '123', + '43228' + ); - // Assert - expect(testValue).toStrictEqual('01234'); - }); + // Assert + // 2023-01-01 --> 2023-02-05 + // 2023-02-06 --> 2023-03-12 + // 2023-03-13 --> 2023-03-31 + expect(store.getShopTimeSlots).toHaveBeenCalledTimes(6); }); - test.skip('forwardButtonAction should call route method navigateWithoutSaving', async () => { +}); +describe('Rendering', () => { + test('Schedule page loads', () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + + // Assert + expect(wrapper).toBeTruthy(); + }); +}); +describe('schedule page methods...', () => { + test('getServiceZipCtuCodeFromStore should return zipCodeCtu', () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.selectableDatesData = { + days: [] + }; + + // Act + const testValue = wrapper.vm.getServiceZipCtuCodeFromStore(); + + // Assert + expect(testValue).toStrictEqual('01234'); + }); + test('forwardButtonAction should call route method navigate', async () => { // Arrange const { wrapper } = getShallowMountedComponent(); wrapper.vm.$router.navigate = jest.fn(() => ({})); + wrapper.vm.mainStore.saveSchedule = jest.fn(); + wrapper.vm.navigationScenarios = { + CLICKED_FORWARD: 'CLICKED_FORWARD' + }; + + // Mock the serviceLocation ref using Object.defineProperty to bypass readonly + Object.defineProperty(wrapper.vm.$refs, 'serviceLocation', { + value: { + forwardButtonAction: jest.fn() + }, + configurable: true + }); + wrapper.vm.selectedTimeSlotInfo = { timeSlot: { routeCode: 'test-id' @@ -281,6 +333,59 @@ describe('schedule-page.vue', () => { // Act await wrapper.vm.forwardButtonAction(); + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + }); + test('recalAckModal should open when part requires recal, but recal not added to order', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.mainStore.lineItems.glassParts = [ + { + partNumber: 'TEST123', + requiresRecalibration: true + } + ]; + + // Act + await wrapper.vm.forwardButtonAction(); + + // Assert + expect(wrapper.vm.$refs[RECAL_ACK_MODAL_REF_NAME].openModal).toHaveBeenCalled(); + }); + test('navigation forward is blocked when recalAckModal is displayed, but checkbox has not been acknowledged', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.mainStore.lineItems.glassParts = [ + { + partNumber: 'TEST123', + requiresRecalibration: true + } + ]; + + // Act + await wrapper.vm.forwardButtonAction(); + await wrapper.vm.$refs[RECAL_ACK_MODAL_REF_NAME].openModal(); + await wrapper.vm.$refs[RECAL_ACK_MODAL_REF_NAME].footerButtonClick(); + + // Assert + expect(wrapper.vm.$router.navigate).not.toHaveBeenCalled(); + }); + test('navigation forward is allowed when checkbox has been acknowledged on recalAckModal', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent(); + wrapper.vm.mainStore.lineItems.glassParts = [ + { + partNumber: 'TEST123', + requiresRecalibration: true + } + ]; + + // Act + await wrapper.vm.$refs[RECAL_ACK_MODAL_REF_NAME].openModal(); + wrapper.vm.updateIsRecalAcknowledged(true); + await wrapper.vm.$refs[RECAL_ACK_MODAL_REF_NAME].footerButtonClick(); + await wrapper.vm.forwardButtonAction(); + // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 2e65643b..904329f3 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -64,6 +64,11 @@ :ref="SUGGEST_TIMESLOT_MODAL_REF_NAME" cmsWidgetName="SuggestTimeslotModal" @confirmAppointmentClicked="autoSelectTimeslotConfirmed" /> + diff --git a/src/store/index.js b/src/store/index.js index 12dc746f..2aa8248a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -225,7 +225,8 @@ export const getDefaultState = () => ({ loadedFromDupeCheck: null, loadedSessionClearedPreviousData: null, availableVaps: null, - visitedDuplicateCheckPage: false + visitedDuplicateCheckPage: false, + isRecalAcknowledgedForScheduling: false }, applicationUser: { experiments: [], @@ -3163,7 +3164,7 @@ export const useMainStore = defineStore({ resetSubmittedOrder() { // clear from sessionStorage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); - } + }, }, persist: { // Default is localStorage, but sessionStorage is used here to ensure state is cleared when the browser tab is closed, preventing potential issues with stale data on return visits.