-
-
-
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/layouts/schedule-page/helpers/schedule-helper.js b/src/layouts/schedule-page/helpers/schedule-helper.js
index eb5657f8..a2e1fae9 100644
--- a/src/layouts/schedule-page/helpers/schedule-helper.js
+++ b/src/layouts/schedule-page/helpers/schedule-helper.js
@@ -1,72 +1,8 @@
import { useMainStore } from '@/store';
-export async function getAlertReasons(ctu) {
+export default async function getAlertReasons(ctu) {
const store = useMainStore();
const alertReasons = await store.getAlertReasonsByCtu(ctu);
return Promise.resolve(alertReasons);
}
-
-export function calcDaysBetweenDates(dateString1, dateString2) {
- const date1 = new Date(dateString1);
- const date2 = new Date(dateString2);
- const timeDifference = Math.abs(date2 - date1); // Calculate the time difference in milliseconds
- return Math.ceil(timeDifference / (1000 * 60 * 60 * 24)); // Convert milliseconds to days
-}
-
-export function convertDateToDateString(date) {
- // returns YYYY-MM-DD format
- if (date instanceof Date !== true) return null;
- return (
- `${date.getFullYear()
- }-${
- (`0${date.getMonth() + 1}`).slice(-2)
- }-${
- (`0${date.getDate()}`).slice(-2)}`
- );
-}
-
-export 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]);
-}
-
-export function sumDateString(dateString, daysToAdd) {
- // dateString must be YYYY-MM-DD format
- if (typeof dateString !== 'string') return null;
- const date = convertDateStringToDate(dateString);
- date.setDate(date.getDate() + daysToAdd);
- return convertDateToDateString(date);
-}
-
-export 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}`;
-}
-
-export 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}`;
-}
diff --git a/src/layouts/schedule-page/location-alerts/location-alerts.vue b/src/layouts/schedule-page/location-alerts/location-alerts.vue
index 1730320e..f47b3704 100644
--- a/src/layouts/schedule-page/location-alerts/location-alerts.vue
+++ b/src/layouts/schedule-page/location-alerts/location-alerts.vue
@@ -9,7 +9,7 @@