-
-
-
Placeholder for review page
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js b/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js
new file mode 100644
index 00000000..1e0f612d
--- /dev/null
+++ b/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js
@@ -0,0 +1,129 @@
+// Components
+import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue';
+
+// Supporting Files
+import { shallowMount } from '@vue/test-utils';
+import { getMountOptions } from '@/helpers/unit-test-helper.js';
+
+const testConstants = {
+ cms: {
+ header: {
+ text: 'Header'
+ },
+ sms: {
+ text: 'Sms'
+ }
+ },
+ customer: {
+ firstName: 'First',
+ lastName: 'Last',
+ phoneNumber: '111-111-1111',
+ emailAddress: 'builddigitaltest@safelite.com',
+ isSmsOptIn: false
+ },
+ displayContent: {
+ fullName: 'First Last',
+ phoneNumber: '111-111-1111',
+ emailAddress: 'builddigitaltest@safelite.com',
+ smsOptIn: 'Sms'
+ }
+};
+
+function generateDefaultProps() {
+ return {
+ cmsWidgetName: 'CustomerWidget',
+ customer: {
+ firstName: testConstants.customer.firstName,
+ lastName: testConstants.customer.lastName,
+ phoneNumber: testConstants.customer.phoneNumber,
+ emailAddress: testConstants.customer.emailAddress,
+ isSmsOptIn: testConstants.customer.isSmsOptIn
+ }
+ };
+}
+
+let cmsContent;
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
+ }
+};
+
+function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
+ const mountOptions = getMountOptions({
+ router: {
+ navigate: jest.fn()
+ }
+ });
+
+ methodToRun();
+
+ mountOptions.data = () => (
+ initialData
+ );
+
+ mountOptions.mixins = [mockMixin];
+
+ const wrapper = shallowMount(customerReview, mountOptions);
+ return { wrapper };
+}
+
+beforeEach(() => {
+ cmsContent = {
+ CustomerWidget: {
+ HeaderText: testConstants.cms.header.text,
+ SubheaderText: testConstants.cms.sms.text
+ }
+ };
+});
+
+describe('Customer Review Block', () => {
+ test('Should display header text from cms', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.header).toEqual(testConstants.cms.header.text);
+ });
+
+ test('Should display sms text from cms', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.text);
+ });
+
+ test('Should render correct display content', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toEqual([
+ testConstants.displayContent.fullName,
+ testConstants.displayContent.emailAddress,
+ testConstants.displayContent.phoneNumber,
+ testConstants.displayContent.smsOptIn
+ ]);
+ });
+});
diff --git a/src/layouts/review-page/review-sections/customer-review/customer-review.vue b/src/layouts/review-page/review-sections/customer-review/customer-review.vue
new file mode 100644
index 00000000..5f442531
--- /dev/null
+++ b/src/layouts/review-page/review-sections/customer-review/customer-review.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js b/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js
new file mode 100644
index 00000000..b7a36442
--- /dev/null
+++ b/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js
@@ -0,0 +1,436 @@
+// Components
+import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue';
+
+// Supporting Files
+import { shallowMount } from '@vue/test-utils';
+import { getMountOptions } from '@/helpers/unit-test-helper.js';
+import damageLocationsSelected from '@/constants/damage-locations-selected';
+
+const testConstants = {
+ cmsConstants: {
+ widgetNames: {
+ header: 'DamageReviewWidget',
+ locations: 'DamageLocationsWidget',
+ driverDamages: 'DriverDamagesWidget',
+ passengerDamages: 'PassengerDamagesWidget'
+ },
+ header: {
+ text: 'Damage'
+ },
+ damageLocations: {
+ windshield: damageLocationsSelected.WINDSHIELD,
+ driver: damageLocationsSelected.DRIVER,
+ passenger: damageLocationsSelected.PASSENGER,
+ rear: damageLocationsSelected.REAR
+ },
+ damageNames: {
+ vent: damageLocationsSelected.VENT,
+ front: damageLocationsSelected.FRONT,
+ back: damageLocationsSelected.BACK,
+ quarter: damageLocationsSelected.QUARTER,
+ side: damageLocationsSelected.SIDEDOOR
+ },
+ locationCopy: {
+ windshield: 'Windshield copy',
+ driver: 'Driver copy',
+ passenger: 'Passenger copy',
+ rear: 'Rear copy'
+ },
+ damageCopy: {
+ vent: 'Vent copy',
+ front: 'Front copy',
+ back: 'Back copy',
+ quarter: 'Quarter copy',
+ side: 'Side copy'
+ },
+ imageId: '00000000-0000-0000-0000-000000000000'
+ },
+ makeBulletedList: (items) => {
+ let list = '
';
+ items.forEach((item) => {
+ list += `- ${item}
`;
+ });
+ list += '
';
+
+ return list;
+ },
+ glassItems: {
+ windshield: {
+ glassLocation: damageLocationsSelected.WINDSHIELD,
+ glassName: damageLocationsSelected.SINGLE
+ },
+ rear: {
+ glassLocation: damageLocationsSelected.REAR,
+ glassName: damageLocationsSelected.STATIONARY
+ },
+ passengerItems: {
+ vent: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.VENT
+ },
+ front: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.FRONT
+ },
+ back: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.BACK
+ },
+ quarter: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.QUARTER
+ },
+ side: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.SIDEDOOR
+ }
+ },
+ driverItems: {
+ vent: {
+ glassLocation: damageLocationsSelected.DRIVER,
+ glassName: damageLocationsSelected.VENT
+ },
+ front: {
+ glassLocation: damageLocationsSelected.DRIVER,
+ glassName: damageLocationsSelected.FRONT
+ },
+ back: {
+ glassLocation: damageLocationsSelected.DRIVER,
+ glassName: damageLocationsSelected.BACK
+ },
+ quarter: {
+ glassLocation: damageLocationsSelected.DRIVER,
+ glassName: damageLocationsSelected.QUARTER
+ },
+ side: {
+ glassLocation: damageLocationsSelected.DRIVER,
+ glassName: damageLocationsSelected.SIDEDOOR
+ }
+ }
+ }
+};
+
+let cmsContent;
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
+ }
+};
+
+function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
+ const mountOptions = getMountOptions({
+ router: {
+ navigate: jest.fn()
+ }
+ });
+
+ methodToRun();
+
+ mountOptions.data = () => (
+ initialData
+ );
+
+ mountOptions.mixins = [mockMixin];
+
+ const wrapper = shallowMount(damageReview, mountOptions);
+ return { wrapper };
+}
+
+beforeEach(() => {
+ cmsContent = {
+ DamageReviewWidget: {
+ Text: testConstants.cmsConstants.header.text
+ },
+ DamageLocationsWidget: {
+ Answers: [
+ {
+ Name: testConstants.cmsConstants.damageLocations.windshield,
+ Text: testConstants.cmsConstants.locationCopy.windshield,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageLocations.driver,
+ Text: testConstants.cmsConstants.locationCopy.driver,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages
+ },
+ {
+ Name: testConstants.cmsConstants.damageLocations.passenger,
+ Text: testConstants.cmsConstants.locationCopy.passenger,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages
+ },
+ {
+ Name: testConstants.cmsConstants.damageLocations.rear,
+ Text: testConstants.cmsConstants.locationCopy.rear,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ }
+ ]
+ },
+ DriverDamagesWidget: {
+ Answers: [
+ {
+ Name: testConstants.cmsConstants.damageNames.vent,
+ Text: testConstants.cmsConstants.damageCopy.vent,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.front,
+ Text: testConstants.cmsConstants.damageCopy.front,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.back,
+ Text: testConstants.cmsConstants.damageCopy.back,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.quarter,
+ Text: testConstants.cmsConstants.damageCopy.quarter,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.side,
+ Text: testConstants.cmsConstants.damageCopy.side,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ }
+ ]
+ },
+ PassengerDamagesWidget: {
+ Answers: [
+ {
+ Name: testConstants.cmsConstants.damageNames.vent,
+ Text: testConstants.cmsConstants.damageCopy.vent,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.front,
+ Text: testConstants.cmsConstants.damageCopy.front,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.back,
+ Text: testConstants.cmsConstants.damageCopy.back,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.quarter,
+ Text: testConstants.cmsConstants.damageCopy.quarter,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: testConstants.cmsConstants.damageNames.side,
+ Text: testConstants.cmsConstants.damageCopy.side,
+ SubText: '',
+ ImageId: testConstants.cmsConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ }
+ ]
+ }
+ };
+});
+
+describe('Damage Review Block', () => {
+ describe('Correctly assembles damage info into a display string', () => {
+ test('Shows windshield copy when windshield damage is included', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.glassItems.windshield]
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.windshield
+ ]);
+ });
+
+ test('Windshield copy is shown when order is a repair', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: true,
+ numberOfChips: 2,
+ glassToReplace: []
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.windshield
+ ]);
+ });
+
+ test('Rear windshield copy shows when rear damage is present', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: false,
+ numberOfChips: null,
+ glassToReplace: [testConstants.glassItems.rear]
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.rear
+ ]);
+ });
+
+ test('Driver side copy and items are shown when driver side damage is present', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: false,
+ numberOfChips: null,
+ glassToReplace: [
+ testConstants.glassItems.driverItems.back,
+ testConstants.glassItems.driverItems.front
+ ]
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.driver,
+ testConstants.makeBulletedList([
+ testConstants.cmsConstants.damageCopy.front,
+ testConstants.cmsConstants.damageCopy.back
+ ])
+ ]);
+ });
+
+ test('Passenger side copy and items are shown when passenger side damage is present', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: false,
+ numberOfChips: null,
+ glassToReplace: [
+ testConstants.glassItems.passengerItems.quarter,
+ testConstants.glassItems.passengerItems.vent,
+ testConstants.glassItems.passengerItems.side
+ ]
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.passenger,
+ testConstants.makeBulletedList([
+ testConstants.cmsConstants.damageCopy.vent,
+ testConstants.cmsConstants.damageCopy.quarter,
+ testConstants.cmsConstants.damageCopy.side
+ ])
+ ]);
+ });
+
+ test('All relevant sections are shown in order in multiglass scenario', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
+ damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
+ damage: {
+ isRepair: false,
+ numberOfChips: null,
+ glassToReplace: [
+ testConstants.glassItems.windshield,
+ testConstants.glassItems.rear,
+ testConstants.glassItems.driverItems.vent,
+ testConstants.glassItems.driverItems.front,
+ testConstants.glassItems.driverItems.back,
+ testConstants.glassItems.passengerItems.quarter,
+ testConstants.glassItems.passengerItems.back,
+ testConstants.glassItems.passengerItems.side
+ ]
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual([
+ testConstants.cmsConstants.locationCopy.windshield,
+ testConstants.cmsConstants.locationCopy.driver,
+ testConstants.makeBulletedList([
+ testConstants.cmsConstants.damageCopy.vent,
+ testConstants.cmsConstants.damageCopy.front,
+ testConstants.cmsConstants.damageCopy.back
+ ]),
+ testConstants.cmsConstants.locationCopy.passenger,
+ testConstants.makeBulletedList([
+ testConstants.cmsConstants.damageCopy.back,
+ testConstants.cmsConstants.damageCopy.quarter,
+ testConstants.cmsConstants.damageCopy.side
+ ]),
+ testConstants.cmsConstants.locationCopy.rear
+ ]);
+ });
+ });
+});
diff --git a/src/layouts/review-page/review-sections/damage-review/damage-review.vue b/src/layouts/review-page/review-sections/damage-review/damage-review.vue
new file mode 100644
index 00000000..4e0b0878
--- /dev/null
+++ b/src/layouts/review-page/review-sections/damage-review/damage-review.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue b/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue
new file mode 100644
index 00000000..d34e33a5
--- /dev/null
+++ b/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js b/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js
new file mode 100644
index 00000000..834714aa
--- /dev/null
+++ b/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js
@@ -0,0 +1,134 @@
+// Components
+import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue';
+
+// Supporting Files
+import { shallowMount } from '@vue/test-utils';
+import { getMountOptions } from '@/helpers/unit-test-helper.js';
+import { AppointmentTypeStrings } from '@/constants/schedule-constants';
+
+const cmsContent = {
+ ServiceLocationTitleWidget: {
+ Text: 'Title Text'
+ }
+};
+
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
+ }
+};
+
+function generateDefaultProps() {
+ return {
+ cmsWidgetName: 'ServiceLocationTitleWidget',
+ serviceLocation: {
+ address: 'Mobile Address 1',
+ address2: 'Mobile Address 2',
+ city: 'Mobile City',
+ state: 'MO',
+ zipCode: '11111',
+ zipCodeCtu: '',
+ appointmentType: AppointmentTypeStrings.MOBILE,
+ isVehicleProtected: false,
+ provider: {
+ providerNumber: '',
+ address: {
+ streetAddress: 'Service Location Address',
+ city: 'Service Location City',
+ state: 'SL',
+ zipCode: '22222',
+ zipCodeCtu: ''
+ }
+ }
+ }
+ };
+}
+
+function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
+ const mountOptions = getMountOptions({
+ router: {
+ navigate: jest.fn()
+ }
+ });
+
+ methodToRun();
+
+ mountOptions.data = () => (
+ initialData
+ );
+
+ mountOptions.mixins = [mockMixin];
+
+ const wrapper = shallowMount(serviceLocationReview, mountOptions);
+ return { wrapper };
+}
+
+describe('Service Location Review Block', () => {
+ test('Should render mobile address if mobile appointment', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toEqual([
+ 'Mobile Address 1, Mobile Address 2, Mobile City, MO 11111'
+ ]);
+ });
+
+ test('Should render service location address if inshop appointment.', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ props.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP;
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toEqual([
+ 'Service Location Address, Service Location City, SL 22222'
+ ]);
+ });
+
+ test('Should render service location address if drop-off appointment', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ props.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF;
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toEqual([
+ 'Service Location Address, Service Location City, SL 22222'
+ ]);
+ });
+
+ test('Should not add comma or any text if address2 is null', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ props.serviceLocation.address2 = null;
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toEqual(['Mobile Address 1, Mobile City, MO 11111']);
+ });
+});
diff --git a/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue b/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue
new file mode 100644
index 00000000..59241b15
--- /dev/null
+++ b/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js b/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js
new file mode 100644
index 00000000..6dfd6f4e
--- /dev/null
+++ b/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js
@@ -0,0 +1,969 @@
+// Components
+import servicePackageReview from '@/layouts/review-page/review-sections/service-package-review/service-package-review.vue';
+
+// Supporting Files
+import { shallowMount } from '@vue/test-utils';
+import { getMountOptions } from '@/helpers/unit-test-helper.js';
+import packageNames from '@/constants/package-names';
+import partTypeStrings from '@/constants/part-type-strings';
+import damageLocationsSelected from '@/constants/damage-locations-selected';
+
+const testConstants = {
+ cmsPropValues: {
+ servicePackageOptionsCmsName: 'ServicePackageTitle',
+ defaultPackageItemsCmsName: 'DefaultPackageItemDescriptions',
+ vapsItemsCmsName: 'VapsItemDescriptions'
+ },
+ widgetNames: {
+ tierOneTitle: 'EconomyServiceTitle',
+ tierTwoTitle: 'StandardServiceTitle',
+ tierThreeTitle: 'PremiumServiceTitle'
+ },
+ defaultItemCopy: {
+ itemOne: 'Item Description 1',
+ itemTwo: 'Item Description 2',
+ itemThree: 'Item Description 3',
+ itemFour: 'Item Description 4',
+ defaultItemCopyArray: ['Item Description 1', 'Item Description 2', 'Item Description 3']
+ },
+ vapsCopy: {
+ frontWiperCopy: 'Front Wiper copy',
+ rearWiperCopy: 'Rear Wiper copy',
+ rainDefenseCopy: 'Rain defense copy'
+ },
+ parts: {
+ frontWiperPart: {
+ partNumber: 'SBB16',
+ description: 'SAFELITE BEAM BLADE 16',
+ partType: 'FRONT WIPER',
+ price: 32.64
+ },
+ rearWiperPart: {
+ partNumber: 'SBBR12A',
+ description: 'SAFELITE REAR BLADE 12A',
+ partType: 'REAR WIPER',
+ price: 24.48
+ },
+ rainDefensePart: {
+ partNumber: 'RAIN DEFENSE',
+ description: null,
+ partType: 'RAIN DEFENSE',
+ price: 35.5
+ },
+ recalPart: {
+ partNumber: 'RECAL STATIC',
+ Description: 'Recalibration',
+ partType: 'recalibration',
+ Quantity: '1',
+ price: 150.0
+ }
+ },
+ damages: {
+ frontWindshield: {
+ glassLocation: damageLocationsSelected.WINDSHIELD,
+ glassName: damageLocationsSelected.SINGLE
+ },
+ rearWindshield: {
+ glassLocation: damageLocationsSelected.REAR,
+ glassName: damageLocationsSelected.STATIONARY
+ },
+ sideGlass: {
+ glassLocation: damageLocationsSelected.PASSENGER,
+ glassName: damageLocationsSelected.QUARTER
+ }
+ },
+ imageId: '00000000-0000-0000-0000-000000000000'
+};
+
+const figmaScenarios = [
+ {
+ name: '05_01_CSR_Quote_Cash',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.frontWindshield]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard+RearWiper',
+ vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ }
+ ]
+ },
+ {
+ name: '05_01_CSR_Quote_Standard_Repair',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: true,
+ glassToReplace: []
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard+RearWiper',
+ vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ }
+ ]
+ },
+ {
+ name: '05_01_CSR_Quote_Recal',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.frontWindshield]
+ },
+ glassParts: [],
+ supportingItems: [testConstants.parts.recalPart]
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard+RearWiper',
+ vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ }
+ ]
+ },
+ // 05_01_CSR_Quote_RearGlass omitted as a duplicate of below.
+ {
+ name: '05_01_CSR_Quote_RearGlass+NonWindshield',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.rearWindshield]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Economy+Frontwiper',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard+RainDefense',
+ vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ }
+ ]
+ },
+ {
+ name: '05_01_CSR_Quote_RearGlass+Windshield',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [
+ testConstants.damages.frontWindshield,
+ testConstants.damages.rearWindshield
+ ]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Economy+Frontwiper',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+Rearwiper',
+ vapsCombo: [testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+RainDefense',
+ vapsCombo: [testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+Frontwiper+RainDefense',
+ vapsCombo: [
+ testConstants.parts.frontWiperPart,
+ testConstants.parts.rainDefensePart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+Rearwiper+RainDefense',
+ vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rearWiperPart,
+ testConstants.parts.frontWiperPart,
+ testConstants.parts.rainDefensePart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ }
+ ]
+ },
+ {
+ name: '05_01_CSR_Quote_RearGlassNoFrontFit',
+ params: {
+ wiperResponse: [testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.rearWindshield]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Economy+Raindefense',
+ vapsCombo: [testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ }
+ ]
+ },
+ // 05_01_CSR_Quote_Windshield+SideGlass has identical outcomes to 05_01_CSR_Quote_Cash, but included in case that changes in the future.
+ {
+ name: '05_01_CSR_Quote_Windshield+SideGlass',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [
+ testConstants.damages.frontWindshield,
+ testConstants.damages.sideGlass
+ ]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Standard',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Standard+RearWiper',
+ vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierTwoTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ }
+ ]
+ },
+ // Has no standard package
+ {
+ name: '05_01_CSR_Quote_SideGlass',
+ params: {
+ wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.sideGlass]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Economy+Frontwiper',
+ vapsCombo: [testConstants.parts.frontWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+RainDefense',
+ vapsCombo: [testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Economy+Rearwiper',
+ vapsCombo: [testConstants.parts.rearWiperPart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rearWiperCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ },
+ {
+ name: 'Premium+Rearwiper',
+ vapsCombo: [
+ testConstants.parts.rainDefensePart,
+ testConstants.parts.frontWiperPart,
+ testConstants.parts.rearWiperPart
+ ],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.frontWiperCopy,
+ testConstants.vapsCopy.rearWiperCopy,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ }
+ ]
+ },
+ // Has no standard package
+ {
+ name: '05_01_CSR_Quote_NoWiperFit',
+ params: {
+ wiperResponse: [],
+ rainDefenseResponse: testConstants.parts.rainDefensePart,
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.frontWindshield]
+ },
+ glassParts: [],
+ supportingItems: []
+ },
+ iterations: [
+ {
+ name: 'Economy',
+ vapsCombo: [],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierOneTitle,
+ displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
+ }
+ },
+ {
+ name: 'Premium',
+ vapsCombo: [testConstants.parts.rainDefensePart],
+ expected: {
+ packageNameWidget: testConstants.widgetNames.tierThreeTitle,
+ displayContent: [
+ ...testConstants.defaultItemCopy.defaultItemCopyArray,
+ testConstants.vapsCopy.rainDefenseCopy
+ ]
+ }
+ }
+ ]
+ }
+];
+
+function generateDefaultProps() {
+ return {
+ servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName,
+ defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName,
+ vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName,
+ lineItems: {
+ glassParts: [],
+ supportingItems: [],
+ vaps: [testConstants.parts.frontWiperPart]
+ },
+ damage: {
+ isRepair: false,
+ glassToReplace: [testConstants.damages.frontWindshield]
+ }
+ };
+}
+
+let cmsContent;
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
+ }
+};
+
+function initializeWithDefault(wrapper) {
+ wrapper.vm.initializeComponent({
+ wipers: [testConstants.parts.frontWiperPart],
+ rainDefense: testConstants.parts.rainDefensePart
+ });
+}
+
+function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
+ const mountOptions = getMountOptions({
+ router: {
+ navigate: jest.fn()
+ }
+ });
+
+ methodToRun();
+
+ mountOptions.data = () => (
+ initialData
+ );
+
+ mountOptions.mixins = [mockMixin];
+
+ const wrapper = shallowMount(servicePackageReview, mountOptions);
+ wrapper.vm.setCmsContent = jest.fn();
+ return { wrapper };
+}
+
+beforeEach(() => {
+ cmsContent = {
+ ServicePackageTitle: {
+ Answers: [
+ {
+ Name: packageNames.TIER_ONE,
+ Text: '',
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: testConstants.widgetNames.tierOneTitle
+ },
+ {
+ Name: packageNames.TIER_TWO,
+ Text: '',
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: testConstants.widgetNames.tierTwoTitle
+ },
+ {
+ Name: packageNames.TIER_THREE,
+ Text: '',
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: testConstants.widgetNames.tierThreeTitle
+ }
+ ]
+ },
+ DefaultPackageItemDescriptions: {
+ Answers: [
+ {
+ Name: 'Item1',
+ Text: testConstants.defaultItemCopy.itemOne,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: 'Item2',
+ Text: testConstants.defaultItemCopy.itemTwo,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: 'Item3',
+ Text: testConstants.defaultItemCopy.itemThree,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ }
+ ]
+ },
+ VapsItemDescriptions: {
+ Answers: [
+ {
+ Name: partTypeStrings.FRONT_WIPER,
+ Text: testConstants.vapsCopy.frontWiperCopy,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: partTypeStrings.REAR_WIPER,
+ Text: testConstants.vapsCopy.rearWiperCopy,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ },
+ {
+ Name: partTypeStrings.RAIN_DEFENSE,
+ Text: testConstants.vapsCopy.rainDefenseCopy,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ }
+ ]
+ }
+ };
+});
+
+describe('Service Package Review Block', () => {
+ describe('General functionality', () => {
+ test('Should properly "Round Down" package tier', async () => {
+ // Slightly longer explanation:
+ // Should only return the highest tier where *every* offered VAP is part of the order.
+ // However, there may be vaps not offered in the qualifying tier. Hence rounding *down*.
+ //
+ // I.e. Economy=[], Standard=[front wipers], Premium=[front wipers, rain defense].
+ // Current vaps=[rain defense]. Though rain defense is in Premium, we don't satisfy it or standard.
+ // So our tier should still be Economy.
+ // Should still display extra vaps.
+
+ // Arrange
+ const props = generateDefaultProps();
+ props.lineItems.vaps = [testConstants.parts.rainDefensePart];
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ initializeWithDefault(wrapper);
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.packageNameWidget).toEqual(testConstants.widgetNames.tierOneTitle);
+
+ const containsRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy);
+ expect(containsRainDefenseCopy).toBe(true);
+ });
+
+ test('Should display all default items from cms', async () => {
+ // Arrange
+ cmsContent.DefaultPackageItemDescriptions.Answers.push({
+ Name: 'Item4',
+ Text: testConstants.defaultItemCopy.itemFour,
+ SubText: '',
+ ImageId: testConstants.imageId,
+ Image: '',
+ SubWidgetName: ''
+ });
+
+ const props = generateDefaultProps();
+ props.lineItems.vaps = [];
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ initializeWithDefault(wrapper);
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ const expectedResult = [
+ testConstants.defaultItemCopy.itemOne,
+ testConstants.defaultItemCopy.itemTwo,
+ testConstants.defaultItemCopy.itemThree,
+ testConstants.defaultItemCopy.itemFour
+ ];
+
+ expect(wrapper.vm.displayContent).toEqual(expectedResult);
+ });
+
+ test('Should display vaps if and only if they are added', async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ initializeWithDefault(wrapper);
+
+ // Assert
+ const includesFrontWiperCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.frontWiperCopy);
+ const includesRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy);
+ expect(includesFrontWiperCopy).toBe(true);
+ expect(includesRainDefenseCopy).toBe(false);
+ });
+
+ test('Should not error if cms content is missing (though may display poorly).', async () => {
+ // Arrange
+ cmsContent = {};
+ const props = generateDefaultProps();
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ initializeWithDefault(wrapper);
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.packageNameWidget).toEqual('');
+ expect(wrapper.vm.displayContent).toEqual([]);
+ });
+ });
+
+ describe('Match Figma Scenarios', () => {
+ figmaScenarios.forEach((scenario) => {
+ scenario.iterations.forEach((iteration) => {
+ it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => {
+ // Arrange
+ const props = generateDefaultProps();
+ props.damage = scenario.params.damage;
+ props.glassParts = scenario.params.glassParts;
+ props.lineItems.supportingItems = scenario.params.supportingItems;
+ props.lineItems.vaps = iteration.vapsCombo;
+
+ const { wrapper } = getShallowMountedComponent({
+ ...props
+ });
+
+ wrapper.vm.initializeComponent({
+ wipers: scenario.params.wiperResponse,
+ rainDefense: scenario.params.rainDefenseResponse
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.packageNameWidget).toEqual(iteration.expected.packageNameWidget);
+ expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent);
+ });
+ });
+ });
+ });
+});
diff --git a/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue b/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue
new file mode 100644
index 00000000..56655945
--- /dev/null
+++ b/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
diff --git a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js
new file mode 100644
index 00000000..fd4a3d64
--- /dev/null
+++ b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js
@@ -0,0 +1,47 @@
+// Components
+import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue';
+
+// Supporting Files
+import { shallowMount } from '@vue/test-utils';
+import { getMountOptions } from '@/helpers/unit-test-helper.js';
+
+jest.mock('@/helpers/cms-content-helper', () => ({
+ fetchCmsContentForPage: () => Promise.resolve('content')
+}));
+
+function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
+ const mountOptions = getMountOptions({
+ router: {
+ navigate: jest.fn()
+ }
+ });
+
+ methodToRun();
+
+ mountOptions.data = () => (
+ initialData
+ );
+
+ const wrapper = shallowMount(vehicleReview, mountOptions);
+ wrapper.vm.setCmsContent = jest.fn();
+ return { wrapper };
+}
+
+describe('Vehicle Review Block', () => {
+ test('Correctly assembles vehicle info into a display string', async () => {
+ // Arrange
+ const { wrapper } = getShallowMountedComponent({
+ vehicle: {
+ year: '2019',
+ make: 'Honda',
+ model: 'Odyssey'
+ }
+ });
+
+ // Act
+ await wrapper.vm.$nextTick();
+
+ // Assert
+ expect(wrapper.vm.displayContent).toStrictEqual(['2019 Honda Odyssey']);
+ });
+});
diff --git a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue
new file mode 100644
index 00000000..cfc9ee09
--- /dev/null
+++ b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
diff --git a/src/router/index.js b/src/router/index.js
index e9945601..b0e1b123 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -218,6 +218,7 @@ function navigate(
optionalPageData = {}
) {
/*eslint-disable-line*/
+ console.log(scenario);
if (!scenario) {
window.console.error('No scenario provided. Please review the routing table.');
return;
@@ -225,6 +226,7 @@ function navigate(
// Match our maps up and navigate if we have a destination.
const matchingScenarioMap = getNavigationMap(scenario, currentRoute);
+ console.log(matchingScenarioMap);
if (!matchingScenarioMap) {
window.console.error('No matching scenario found. Please review the routing table.');
diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js
index 3a03cf51..13733fc6 100644
--- a/src/router/router-constants/navigation-scenarios.js
+++ b/src/router/router-constants/navigation-scenarios.js
@@ -74,6 +74,14 @@ const navigationScenarios = Object.freeze({
CLICKED_FORWARD_WITH_TPA_DISABLED: 'CLICKED_FORWARD_WITH_TPA_DISABLED',
CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES',
+ // Review Page
+ CLICKED_CUSTOMER_EDIT: 'CLICKED_CUSTOMER_EDIT',
+ CLICKED_DAMAGE_EDIT: 'CLICKED_DAMAGE_EDIT',
+ CLICKED_SCHEDULE_EDIT: 'CLICKED_SCHEDULE_EDIT',
+ CLICKED_SERVICE_LOCATION_EDIT: 'CLICKED_SERVICE_LOCATION_EDIT',
+ CLICKED_SERVICE_PACKAGE_EDIT: 'CLICKED_SERVICE_PACKAGE_EDIT',
+ CLICKED_VEHICLE_EDIT: 'CLICKED_VEHICLE_EDIT',
+
// Bailout
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT'
});
diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js
index 7f064f9b..189100df 100644
--- a/src/router/router-constants/routing-table.js
+++ b/src/router/router-constants/routing-table.js
@@ -609,6 +609,30 @@ const routingTable = () => [
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationIssPageValue: issPageValues.PAYMENT_PAGE
+ },
+ {
+ scenario: navigationScenarios.CLICKED_CUSTOMER_EDIT,
+ destinationIssPageValue: issPageValues.CONTACT_DETAILS
+ },
+ {
+ scenario: navigationScenarios.CLICKED_DAMAGE_EDIT,
+ destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
+ },
+ {
+ scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT,
+ destinationIssPageValue: issPageValues.SCHEDULE_PAGE
+ },
+ {
+ scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT,
+ destinationIssPageValue: issPageValues.SERVICE_LOCATION
+ },
+ {
+ scenario: navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT,
+ destinationIssPageValue: issPageValues.SERVICE_PACKAGES
+ },
+ {
+ scenario: navigationScenarios.CLICKED_VEHICLE_EDIT,
+ destinationIssPageValue: issPageValues.VEHICLE_SELECTION
}
]
},
diff --git a/src/store/index.js b/src/store/index.js
index 7848a8fc..67026854 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -14,10 +14,47 @@ import coverageStatuses from '@/constants/coverage-statuses';
import { deepEqual } from '@/helpers/object-helper';
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
import getDateDifferenceInDays from '@/helpers/date-helper';
-import endorsementOptions from '@/constants/endorsement-options';
+// import endorsementOptions from '@/constants/endorsement-options';
const storeId = 'main';
+function convertDateStringToDate(dateString) {
+ // dateString must be YYYY-MM-DD format
+ if (typeof dateString !== 'string') return null;
+ const dateParts = dateString.split('-');
+ return new Date(dateParts[0], parseInt(dateParts[1], 10) - 1, dateParts[2]);
+}
+
+function militaryToTwelveHourTime(timeString) {
+ // Expected input: "HH:MM"
+ if (typeof timeString !== 'string') return null;
+ let hours = parseInt(timeString.split(':')[0], 10);
+ const minutes = timeString.split(':')[1];
+ const meridianNotation = hours > 11 ? 'PM' : 'AM';
+
+ if (hours > 12) {
+ hours -= 12;
+ }
+
+ return `${hours}:${minutes} ${meridianNotation}`;
+}
+
+function getDisplayTextForDurationLength(durationMinimum, durationMaximum) {
+ const isLongAppointment = durationMaximum >= 120;
+ const isDurationRange = durationMinimum !== durationMaximum;
+
+ const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum;
+ const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum;
+
+ const durationText = isDurationRange
+ ? `${adjustedMinimum} - ${adjustedMaximum}`
+ : adjustedMinimum;
+
+ const unitText = isLongAppointment ? 'hours' : 'minutes';
+
+ return `${durationText} ${unitText}`;
+}
+
function getTimeSlotsAdditionalEventData(
provisionalTriggers,
zipCode,
@@ -201,7 +238,7 @@ export const useMainStore = defineStore({
lineItems: (state) => state.order.lineItems,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
- hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly,
+ hasAnyNonWindshieldGlassParts: (s) => !s.order.policy.isDamageGlassOnly,
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
@@ -250,6 +287,30 @@ export const useMainStore = defineStore({
requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false,
notesForTechnician: s.order.contactInfo.notesForTechnician
}),
+ scheduleDisplayText: (s) => {
+ const dateModel = convertDateStringToDate(s.order.schedule.date);
+ const readableDate = dateModel?.toLocaleDateString('en-us', {
+ weekday: 'long',
+ month: 'long',
+ day: 'numeric',
+ year: 'numeric'
+ });
+
+ const readableStartTime = militaryToTwelveHourTime(s.order.schedule.startTime);
+ const readableEndTime = militaryToTwelveHourTime(s.order.schedule.endTime);
+
+ const readableDuration = getDisplayTextForDurationLength(
+ s.order.schedule.jobMinMinutes,
+ s.order.schedule.jobMaxMinutes
+ );
+
+ return {
+ date: readableDate,
+ startTime: readableStartTime,
+ endTime: readableEndTime,
+ duration: readableDuration
+ };
+ },
experimentOrder: (state) => ({
issVehicleYear: state.order.vehicle.year,
issVehicleMake: state.order.vehicle.make,
@@ -1589,11 +1650,9 @@ export const useMainStore = defineStore({
updateIsSafeliteProvider(isSafelite) {
this.order.serviceLocation.IsSafeliteProvider = isSafelite;
},
-
updateDeductible(finalDeductible) {
this.order.currentDeductible = finalDeductible;
},
-
savePartQuestionAnswers(partQuestionAnswersArray) {
// if part question answers have changed, reset subsequent question answers
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.partQuestionAnswers, 'result');
@@ -1636,7 +1695,6 @@ export const useMainStore = defineStore({
// Save new values
this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray);
},
-
saveCapabilityQuestionAnswers(capabilityQuestionAnswersArray) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.capabilityQuestionAnswers, 'result');
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswersArray, 'result');
@@ -1654,16 +1712,15 @@ export const useMainStore = defineStore({
this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray);
},
saveGlassParts(glassParts) {
- if (!deepEqual(glassParts, this.order.lineItems.glassParts)) {
- this.resetServiceLocationAndDependencies();
- }
+ // if (!deepEqual(glassParts, this.order.lineItems.glassParts)) {
+ // this.resetServiceLocationAndDependencies();
+ // }
this.order.lineItems.glassParts = glassParts;
},
saveSupportingItems(supportingItems) {
- if (!deepEqual(supportingItems, this.order.lineItems.supportingItems)) {
- this.resetServiceLocationAndDependencies();
- }
-
+ // if (!deepEqual(supportingItems, this.order.lineItems.supportingItems)) {
+ // this.resetServiceLocationAndDependencies();
+ // }
this.order.lineItems.supportingItems = supportingItems;
},
saveSupportingItemsSuppressingStateResetting(supportingItems) {