Merge pull request #539 from Safelite/feature/digital/SSR-792.3

Fixing vehicle damage lines
This commit is contained in:
michaela-brydon-safelite 2024-01-23 11:35:58 -05:00 committed by GitHub
commit bd190d2bbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 633 additions and 550 deletions

View file

@ -0,0 +1,71 @@
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
function getLocationAnswer(damageLocation, locationAnswers) {
return locationAnswers?.find((answer) => answer.Name === damageLocation);
}
function getGlassPieces(damageLocation, glassToReplace) {
return glassToReplace?.filter((item) => item.glassLocation === damageLocation);
}
function getWindshieldCopy(answerContent, glassToReplace, isRepair) {
const windshieldPieces = getGlassPieces(damageLocationsSelected.WINDSHIELD, glassToReplace);
return isRepair || !!windshieldPieces?.length ? [answerContent?.Text] : [];
}
function getRearCopy(answerContent, glassToReplace) {
const rearPieces = getGlassPieces(damageLocationsSelected.REAR, glassToReplace);
return rearPieces?.length ? [answerContent?.Text] : [];
}
function generateBulletedListFromAnswers(answers) {
const items = answers.map((answer) => `<li>${answer.Text}</li>`);
return `<ul>${items.join('')}</ul>`;
}
function getSideCopy(location, locationAnswers, damageAnswers, glassToReplace) {
const sideItems = getGlassPieces(location, glassToReplace);
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
sideItems?.some((glassPiece) => answer.Name === glassPiece.glassName));
return sideItems?.length
? [
locationAnswers?.Text,
generateBulletedListFromAnswers(damageAnswersOnOrder)
]
: [];
}
function getDamageDisplayContent(
locationAnswers,
driverSideDamageAnswers,
passengerSideDamageAnswers,
glassToReplace,
isRepair
) {
return [
...getWindshieldCopy(
getLocationAnswer(damageLocationsSelected.WINDSHIELD, locationAnswers),
glassToReplace,
isRepair
),
...getSideCopy(
damageLocationsSelected.DRIVER,
getLocationAnswer(damageLocationsSelected.DRIVER, locationAnswers),
driverSideDamageAnswers,
glassToReplace
),
...getSideCopy(
damageLocationsSelected.PASSENGER,
getLocationAnswer(damageLocationsSelected.PASSENGER, locationAnswers),
passengerSideDamageAnswers,
glassToReplace
),
...getRearCopy(
getLocationAnswer(damageLocationsSelected.REAR, locationAnswers),
glassToReplace
)
];
}
export { getDamageDisplayContent, getLocationAnswer };

View file

@ -0,0 +1,411 @@
import { getDamageDisplayContent, getLocationAnswer } from '@/helpers/damage-review-content-generator.js';
import damageLocationsSelected from '@/constants/damage-locations-selected';
const testConstants = {
cmsConstants: {
widgetNames: {
locations: 'DamageLocationsWidget',
driverDamages: 'DriverDamagesWidget',
passengerDamages: 'PassengerDamagesWidget'
},
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'
},
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
}
}
}
};
const cmsContent = {
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-content-generator', () => {
describe('getLocationAnswer', () => {
test('answer with damage location name match', () => {
// Arrange
const damageLocation = 'matching name';
const expected = { Name: damageLocation };
const locationAnswers = [{ Name: 'non matching name' }, expected];
// Act
const result = getLocationAnswer(damageLocation, locationAnswers);
// Assert
expect(result).toEqual(expected);
});
test('no damage location name match', () => {
// Arrange
const damageLocation = 'random string';
const locationAnswers = [{ Name: 'non matching name' }];
// Act
const result = getLocationAnswer(damageLocation, locationAnswers);
// Assert
expect(result).toBe(undefined);
});
test.each([
[[]],
[null],
[undefined]
])('location answers %p', (locationAnswers) => {
// Arrange
const damageLocation = 'some string';
// Act
const result = getLocationAnswer(damageLocation, locationAnswers);
// Assert
expect(result).toBe(undefined);
});
});
describe('Correctly assembles damage info into a display string', () => {
const locationAnswers = cmsContent.DamageLocationsWidget.Answers;
test('Shows windshield copy when windshield damage is included', async () => {
// Arrange
const glassToReplace = [testConstants.glassItems.windshield];
const isRepair = false;
// Act
const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.windshield
]);
});
test('Windshield copy is shown when order is a repair', async () => {
// Arrange
const glassToReplace = [];
const isRepair = true;
// Act
const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.windshield
]);
});
test('Rear windshield copy shows when rear damage is present', async () => {
// Arrange
const glassToReplace = [testConstants.glassItems.rear];
const isRepair = false;
// Act
const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.rear
]);
});
test('Driver side copy and items are shown when driver side damage is present', async () => {
// Arrange
const driverSideDamageAnswers = cmsContent.DriverDamagesWidget.Answers;
const glassToReplace = [
testConstants.glassItems.driverItems.back,
testConstants.glassItems.driverItems.front
];
const isRepair = false;
const expectedList = '<ul>'
+ `<li>${testConstants.cmsConstants.damageCopy.front}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.back}</li>`
+ '</ul>';
// Act
const result = getDamageDisplayContent(
locationAnswers,
driverSideDamageAnswers,
null,
glassToReplace,
isRepair
);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.driver,
expectedList
]);
});
test('Passenger side copy and items are shown when passenger side damage is present', async () => {
// Arrange
const passengerSideDamageAnswers = cmsContent.PassengerDamagesWidget.Answers;
const glassToReplace = [
testConstants.glassItems.passengerItems.quarter,
testConstants.glassItems.passengerItems.vent,
testConstants.glassItems.passengerItems.side
];
const isRepair = false;
const expectedList = '<ul>'
+ `<li>${testConstants.cmsConstants.damageCopy.vent}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.quarter}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.side}</li>`
+ '</ul>';
// Act
const result = getDamageDisplayContent(
locationAnswers,
null,
passengerSideDamageAnswers,
glassToReplace,
isRepair
);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.passenger,
expectedList
]);
});
test('All relevant sections are shown in order in multiglass scenario', async () => {
// Arrange
const driverSideDamageAnswers = cmsContent.DriverDamagesWidget.Answers;
const passengerSideDamageAnswers = cmsContent.PassengerDamagesWidget.Answers;
const 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
];
const isRepair = false;
const expectedDriverDamageList = '<ul>'
+ `<li>${testConstants.cmsConstants.damageCopy.vent}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.front}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.back}</li>`
+ '</ul>';
const expectedPassengerDamageList = '<ul>'
+ `<li>${testConstants.cmsConstants.damageCopy.back}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.quarter}</li>`
+ `<li>${testConstants.cmsConstants.damageCopy.side}</li>`
+ '</ul>';
// Act
const result = getDamageDisplayContent(
locationAnswers,
driverSideDamageAnswers,
passengerSideDamageAnswers,
glassToReplace,
isRepair
);
// Assert
expect(result).toStrictEqual([
testConstants.cmsConstants.locationCopy.windshield,
testConstants.cmsConstants.locationCopy.driver,
expectedDriverDamageList,
testConstants.cmsConstants.locationCopy.passenger,
expectedPassengerDamageList,
testConstants.cmsConstants.locationCopy.rear
]);
});
});
});

View file

@ -2,113 +2,16 @@
import damageReview from '@/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue';
// Supporting Files
import { createTestingPinia } from '@pinia/testing';
import { useMainStore } from '@/store';
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import damageLocationsSelected from '@/constants/damage-locations-selected';
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
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 = '<ul>';
items.forEach((item) => {
list += `<li>${item}</li>`;
});
list += '</ul>';
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
}
}
}
};
jest.mock('@/helpers/damage-review-content-generator.js', () => ({
getDamageDisplayContent: jest.fn(),
getLocationAnswer: jest.fn()
}));
let cmsContent;
const mockMixin = {
@ -117,15 +20,22 @@ const mockMixin = {
}
};
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
function getShallowMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
}
});
const testingPinia = createTestingPinia({
initialState: {
main: mainInitialState
}
});
useMainStore(testingPinia);
methodToRun();
mountOptions.global.plugins = [testingPinia];
mountOptions.data = () => (
initialData
);
@ -137,300 +47,32 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
}
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: ''
}
]
}
};
getDamageDisplayContent.mockClear();
});
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,
test('computed displayContent calls getDamageDisplayContent with expected', () => {
// Arrange
const glassToReplace = ['front-window', 'side-window'];
const isRepair = false;
const initialStore = {
order: {
damage: {
isRepair: false,
glassToReplace: [testConstants.glassItems.windshield]
glassToReplace,
isRepair
}
});
}
};
const expected = ['a', 'v', 'n'];
getDamageDisplayContent.mockImplementationOnce(() => expected);
const { wrapper } = getShallowMountedComponent(initialStore, {});
// Act
await wrapper.vm.$nextTick();
// Act
const result = wrapper.vm.displayContent;
// 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
]);
});
// Assert
expect(result).toStrictEqual(expected);
expect(getDamageDisplayContent).toBeCalledTimes(1);
expect(getDamageDisplayContent).toBeCalledWith([], [], [], glassToReplace, isRepair);
});
});

View file

@ -6,6 +6,8 @@
<script>
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
import { useMainStore } from '@/store';
import { getDamageDisplayContent, getLocationAnswer } from '@/helpers/damage-review-content-generator.js';
import reviewBlock from '@/layouts/payment-method/review-dropdown/review-block/review-block.vue';
export default {
@ -18,83 +20,24 @@ export default {
damageLocationsWidgetName: String,
damage: Object
},
data() {
return {};
},
computed: {
displayContent() {
return [
...this.windshieldCopy,
...this.driverSideCopy,
...this.passengerSideCopy,
...this.rearCopy
];
const { glassToReplace, isRepair } = useMainStore().order.damage;
return getDamageDisplayContent(
this.locationAnswers,
this.driverSideDamageAnswers,
this.passengerSideDamageAnswers,
glassToReplace,
isRepair
);
},
hasWindshieldDamage() {
const windshieldPieces = this.getGlassPieces(damageLocationsSelected.WINDSHIELD);
return this.damage.isRepair || !!windshieldPieces?.length;
driverSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
},
hasDriverSideDamage() {
const driverPieces = this.getGlassPieces(damageLocationsSelected.DRIVER);
return !!driverPieces?.length;
},
hasPassengerSideDamage() {
const passengerPieces = this.getGlassPieces(damageLocationsSelected.PASSENGER);
return !!passengerPieces?.length;
},
hasRearDamage() {
const rearPieces = this.getGlassPieces(damageLocationsSelected.REAR);
return !!rearPieces?.length;
},
windshieldCopy() {
const answerContent = this.getLocationAnswer(damageLocationsSelected.WINDSHIELD);
if (this.hasWindshieldDamage) {
return [answerContent?.Text];
}
return [];
},
driverSideCopy() {
const answerContent = this.getLocationAnswer(damageLocationsSelected.DRIVER);
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
const driverSideItems = this.getGlassPieces(damageLocationsSelected.DRIVER);
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
driverSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName));
if (this.hasDriverSideDamage) {
return [
answerContent?.Text,
this.generateBulletedListFromAnswers(damageAnswersOnOrder)
];
}
return [];
},
passengerSideCopy() {
const answerContent = this.getLocationAnswer(damageLocationsSelected.PASSENGER);
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
const passengerSideItems = this.getGlassPieces(damageLocationsSelected.PASSENGER);
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
passengerSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName));
if (this.hasPassengerSideDamage) {
return [
answerContent?.Text,
this.generateBulletedListFromAnswers(damageAnswersOnOrder)
];
}
return [];
},
rearCopy() {
const answerContent = this.getLocationAnswer(damageLocationsSelected.REAR);
if (this.hasRearDamage) {
return [answerContent?.Text];
}
return [];
passengerSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
},
locationAnswers() {
return this.getAnswersNullSafe(this.damageLocationsWidgetName);
@ -103,25 +46,7 @@ export default {
methods: {
getAnswersNullSafe(widgetName) {
const rawAnswers = this.getCmsContent(widgetName, 'Answers');
return rawAnswers || [];
},
getLocationAnswer(damageLocation) {
return this.locationAnswers?.find((answer) => answer.Name === damageLocation);
},
getGlassPieces(damageLocation) {
return this.damage?.glassToReplace?.filter((item) => item.glassLocation === damageLocation);
},
generateBulletedListFromAnswers(answers) {
let list = '<ul>';
answers.forEach((answer) => {
list += `<li>${answer.Text}</li>`;
});
list += '</ul>';
return list;
}
}
};

View file

@ -8,6 +8,7 @@ Object {
},
"sections": Array [],
"widget": Object {
"damageLocations": "DamageLocationsWidget",
"footer": "SiteFooterWidget",
"orderDetails": "OrderDetailsContent",
"serviceSummary": "ServiceSummaryContent",

View file

@ -21,8 +21,8 @@
<p
v-for="line in lines"
:key="line"
class="small review-block__body--line">
{{ line }}
class="small review-block__body--line"
v-html="line">
</p>
</div>
</template>

View file

@ -9,6 +9,8 @@ import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper.js';
import widgetFields from '@/constants/cms-widget-fields.js';
import { toTitleCase, formatAddress, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
// Mock fetchCmsContentForPage
jest.mock('@/helpers/cms-content-helper', () => ({
@ -25,6 +27,11 @@ jest.mock('@/helpers/text-helper.js', () => ({
toTitleCase: jest.fn()
}));
jest.mock('@/helpers/damage-review-content-generator.js', () => ({
getDamageDisplayContent: jest.fn(),
getLocationAnswer: jest.fn()
}));
// Mock our module for promises.
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -57,6 +64,12 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
return { wrapper };
}
beforeEach(() => {
formatAddress.mockClear();
toDisplayPhoneNumber.mockClear();
getDamageDisplayContent.mockClear();
});
describe('tpa-submit', () => {
test('returns the initial data', () => {
// Arrange
@ -337,37 +350,25 @@ describe('tpa-submit', () => {
expect(vehicleSection.lines).toStrictEqual(expectedLines);
}
);
test.each([
['Apple sauce', 'Apple sauce'],
['', ''],
['', undefined],
['', null]
])(
'damage line is %p when store damage is %p',
async (damageLine, storeDamage) => {
// Arrange
const initialStore = {
order: {
policy: { damageCause: storeDamage }
}
};
const { wrapper } = getMountedComponent(initialStore);
const damageSectionIndex = 1;
const expectedLines = [damageLine];
test('damage section lines equal result from getDamageDisplayContent', async () => {
// Arrange
const { wrapper } = getMountedComponent();
const damageSectionIndex = 1;
const expectedLines = ['hi', 'potato', 'vehicle 3'];
getDamageDisplayContent.mockImplementationOnce(() => expectedLines);
// Act
await tpaSubmit.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: 'tpa-submit' } },
undefined,
(c) => c(wrapper.vm)
);
// Act
await tpaSubmit.beforeRouteEnter.call(
wrapper.vm,
{ query: { issPage: 'tpa-submit' } },
undefined,
(c) => c(wrapper.vm)
);
// Assert
const damageSection = wrapper.vm.sections[damageSectionIndex];
expect(damageSection.lines).toStrictEqual(expectedLines);
}
);
// Assert
const damageSection = wrapper.vm.sections[damageSectionIndex];
expect(damageSection.lines).toEqual(expectedLines);
});
describe('preferred shop section', () => {
test('has three lines', async () => {
// Arrange
@ -386,15 +387,12 @@ describe('tpa-submit', () => {
const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex];
expect(preferredShopSection.lines.length).toBe(3);
});
test.each([
['some value', 'some value'],
['', ''],
['', null],
['', undefined]
])('first line is %p when company name is %p', async (line, companyName) => {
test('first line is value returned from toTitleCase method', async () => {
// Arrange
const initialData = { companyName };
const initialData = { companyName: 'some value' };
const { wrapper } = getMountedComponent({}, initialData);
const expectedName = 'some expected name';
toTitleCase.mockImplementationOnce(() => expectedName);
const preferredShopSectionIndex = 2;
// Act
@ -407,7 +405,7 @@ describe('tpa-submit', () => {
// Assert
const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex];
expect(preferredShopSection.lines[0]).toBe(line);
expect(preferredShopSection.lines[0]).toBe(expectedName);
});
test('second line is expected and formatAddress called', async () => {
// Arrange
@ -426,7 +424,7 @@ describe('tpa-submit', () => {
};
const { wrapper } = getMountedComponent(initialStore);
const line = 'some returned line';
wrapper.vm.formatAddress = jest.fn().mockImplementationOnce(() => line);
formatAddress.mockImplementationOnce(() => line);
const preferredShopSectionIndex = 2;
// Act
@ -440,8 +438,8 @@ describe('tpa-submit', () => {
// Assert
const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex];
expect(preferredShopSection.lines[1]).toBe(line);
expect(wrapper.vm.formatAddress).toHaveBeenCalledTimes(1);
expect(wrapper.vm.formatAddress).toHaveBeenCalledWith(
expect(formatAddress).toHaveBeenCalledTimes(1);
expect(formatAddress).toHaveBeenCalledWith(
address.streetAddress,
null,
address.city,
@ -461,7 +459,7 @@ describe('tpa-submit', () => {
};
const { wrapper } = getMountedComponent(initialStore);
const expectedLine = 'returned from to display phone num';
wrapper.vm.toDisplayPhoneNumber = jest.fn().mockImplementationOnce(() => expectedLine);
toDisplayPhoneNumber.mockImplementationOnce(() => expectedLine);
const preferredShopSectionIndex = 2;
// Act
@ -475,7 +473,7 @@ describe('tpa-submit', () => {
// Assert
const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex];
expect(preferredShopSection.lines[2]).toBe(expectedLine);
expect(wrapper.vm.toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber);
expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber);
});
});
test('contact info section has expected content', async () => {
@ -498,7 +496,7 @@ describe('tpa-submit', () => {
const expectedLine1 = 'Jones Eddison';
const expectedLine2 = emailAddress;
const expectedLine3 = 'some value returned';
wrapper.vm.toDisplayPhoneNumber = jest.fn().mockImplementation((number) => (number === phoneNumber ? expectedLine3 : ''));
toDisplayPhoneNumber.mockImplementation((number) => (number === phoneNumber ? expectedLine3 : ''));
const contactInfoSectionIndex = 3;
// Act
@ -514,7 +512,7 @@ describe('tpa-submit', () => {
expect(contactInfoSection.lines[0]).toBe(expectedLine1);
expect(contactInfoSection.lines[1]).toBe(expectedLine2);
expect(contactInfoSection.lines[2]).toBe(expectedLine3);
expect(wrapper.vm.toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber);
expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber);
});
});
describe('computed', () => {
@ -762,5 +760,22 @@ describe('tpa-submit', () => {
expect(result).toBe(null);
});
});
test.each([
[[1, 5, 6], [1, 5, 6]],
[[], []],
[undefined, []],
[null, []]
])('getAnswersNullSafe', (rawAnswers, expected) => {
// Arrange
const widgetName = 'WidgetName';
const { wrapper } = getMountedComponent();
wrapper.vm.getCmsContent = jest.fn().mockImplementationOnce(() => rawAnswers);
// Act
const result = wrapper.vm.getAnswersNullSafe(widgetName);
// Assert
expect(result).toEqual(expected);
});
});
});

View file

@ -78,7 +78,9 @@
:customText="orderDetailsBody"
:marginTopSizeOverride="4"
class="mb-4 px-4 small text-color--darker-gray" />
<deductibleBox ref="deductibleBox" :value="deductibleBoxValue" />
<deductibleBox
ref="deductibleBox"
:value="deductibleBoxValue" />
</div>
<siteFooter
ref="siteFooter"
@ -109,6 +111,8 @@ import BaseFormMixin from '@/mixins/base-form-mixin.js';
import widgetFields from '@/constants/cms-widget-fields.js';
import { useMainStore } from '@/store';
import { toTitleCase, toDisplayPhoneNumber, formatAddress, formatAmountInDollars } from '@/helpers/text-helper.js';
import { getDamageDisplayContent, getLocationAnswer } from '@/helpers/damage-review-content-generator.js';
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
const VERIFYING_COVERAGE = 'Verifying coverage';
@ -148,6 +152,7 @@ export default {
shop: 'PreferredShopSubTitle',
contactInfo: 'ContactDetailsSubTitle'
},
damageLocations: 'DamageLocationsWidget',
orderDetails: 'OrderDetailsContent',
footer: 'SiteFooterWidget'
},
@ -166,7 +171,7 @@ export default {
},
subHeaderBodyTwo() {
const cmsContent = this.getCmsContent(this.widget.siteSubHeader, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
return this.getStringWithCustomValues(cmsContent, this.customValueMap);
return getStringWithCustomValues(cmsContent, this.customValueMap);
},
serviceSummaryText() {
return this.getCmsContent(this.widget.serviceSummary, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
@ -176,7 +181,7 @@ export default {
},
orderDetailsBody() {
const orderDetailsBodyText = this.getCmsContent(this.widget.orderDetails, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
return this.processIfStatements(orderDetailsBodyText, 'custom', this.getCustomValueFromString);
return processIfStatements(orderDetailsBodyText, 'custom', this.getCustomValueFromString);
},
forwardButtonText() {
return this.getCmsContent(this.widget.footer, widgetFields.FOOTER_WIDGET.FORWARD_BUTTON_TEXT);
@ -188,7 +193,7 @@ export default {
return useMainStore().order.currentDeductible;
},
deductibleBoxValue() {
return this.isVerified ? this.formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE;
return this.isVerified ? formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE;
},
getVehicleLines() {
const { year, make, model } = useMainStore().order.vehicle;
@ -197,22 +202,40 @@ export default {
.join(' ');
return [line];
},
locationAnswers() {
return this.getAnswersNullSafe(this.widget.damageLocations);
},
driverSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
},
passengerSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
},
getDamageLines() {
return [useMainStore().order.policy.damageCause ?? ''];
const { glassToReplace, isRepair } = useMainStore().order.damage;
return getDamageDisplayContent(
this.locationAnswers,
this.driverSideDamageAnswers,
this.passengerSideDamageAnswers,
glassToReplace,
isRepair
);
},
getPreferredShopLines() {
const { phoneNumber, address } = useMainStore().order.serviceLocation.provider;
const { streetAddress, city, state, zipCode } = address;
const displayAddress = this.formatAddress(streetAddress, null, city, state, zipCode);
const displayPhoneNumber = this.toDisplayPhoneNumber(phoneNumber);
return [this.companyName ?? '', displayAddress, displayPhoneNumber];
const displayAddress = formatAddress(streetAddress, null, city, state, zipCode);
const displayPhoneNumber = toDisplayPhoneNumber(phoneNumber);
return [toTitleCase(this.companyName ?? ''), displayAddress, displayPhoneNumber];
},
getContactInfoLines() {
const { firstName, lastName, emailAddress, phoneNumber } = useMainStore().contactInfo;
return [
`${firstName} ${lastName}`,
emailAddress ?? '',
this.toDisplayPhoneNumber(phoneNumber)
toDisplayPhoneNumber(phoneNumber)
];
}
},
@ -231,15 +254,12 @@ export default {
return {
title: this.getCmsContent(widgetName, widgetFields.TEXT_BLOCK_WIDGET.TEXT),
lines,
onClickEdit: this.getNavigateByScenarioMethod(scenario)
onClickEdit: () => this.navigate(scenario)
};
},
forwardButtonAction() {
this.navigate(this.navigationScenarios.CLICKED_FORWARD);
},
getNavigateByScenarioMethod(scenario) {
return () => this.navigate(scenario);
},
navigate(scenario) {
this.$router.navigate(scenario, this.$route);
},
@ -255,12 +275,10 @@ export default {
return null;
}
},
processIfStatements,
getStringWithCustomValues,
toDisplayPhoneNumber,
toTitleCase,
formatAddress,
formatAmountInDollars
getAnswersNullSafe(widgetName) {
const rawAnswers = this.getCmsContent(widgetName, 'Answers');
return rawAnswers || [];
}
}
};
</script>

View file

@ -13,7 +13,6 @@ import damageLocationsSelected from '@/constants/damage-locations-selected';
import coverageStatuses from '@/constants/coverage-statuses';
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
// import endorsementOptions from '@/constants/endorsement-options';
const storeId = 'main';
@ -220,6 +219,7 @@ export const useMainStore = defineStore({
lineItems: (state) => state.order.lineItems,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
hasExactlyOneChip: () => state.order.damage.numberOfChips === 1,
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,