DigitalConsumer.ISS/src/iss-components/shop-list-button/shop-list-button.spec.js
2025-12-10 15:05:33 -05:00

786 lines
33 KiB
JavaScript

import { shallowMount, mount } from '@vue/test-utils';
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
const buttonLabelReference = 'span[id="buttonLabelSpan"]';
const buttonLabelCopyReference = 'span[id="buttonLabelSubCopySpan"]';
const availabilityIndicatorBlockReference = 'div[id="availabilityIndicatorBlock"]';
const loaderReference = { ref: 'availabilityIndicatorLoader' };
const availabilityBadgeReference = 'div[id="availabilityBadge"]';
const buttonBodyCopyReference = 'span[id="buttonBodyCopy"]';
const screenReaderOnlySpanReference = '#screenReaderOnlyTextSpan';
describe('Shop list button', () => {
describe('should render', () => {
test('correctly with required props', async () => {
// Arrange
const wrapper = shallowMount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group'
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.html()).toMatchSnapshot();
});
test('correctly with all relevant props', async () => {
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(null)
};
const wrapper = shallowMount(shopListButton, {
propsData: {
buttonLabel: 'Label of button',
buttonLabelSubCopy: 'Sub copy of button',
selectedValue: 'selected value',
buttonBodyCopy: 'button body copy',
screenReaderOnlyText: 'screen reader only text',
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.html()).toMatchSnapshot();
});
test('expected data with only required props', async () => {
// Arrange
const wrapper = shallowMount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group'
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.$data).toMatchSnapshot();
});
test('expected data with all relevant props', async () => {
// Arrange
const wrapper = shallowMount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
additionalButtonData: {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(null)
}
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.$data).toMatchSnapshot();
});
describe('button label with expected classes', () => {
test('when "textPosition" prop provided', async () => {
// Arrange
const textPosition = 'positionOfText';
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
textPosition
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonLabel = wrapper.find(buttonLabelReference);
// Assert
expect(buttonLabel.exists()).toBeTruthy();
expect(buttonLabel.classes()).toContain(textPosition);
});
test('when "textPosition" prop not provided', async () => {
// Arrange
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button'
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonLabel = wrapper.find(buttonLabelReference);
// Assert
expect(buttonLabel.exists()).toBeTruthy();
});
});
describe('button label sub copy with expected classes', () => {
test('when "textPosition" prop provided', async () => {
// Arrange
const textPosition = 'positionOfText';
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
textPosition
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonLabelSubCopy = wrapper.find(buttonLabelCopyReference);
// Assert
expect(buttonLabelSubCopy.exists()).toBeTruthy();
expect(buttonLabelSubCopy.classes().length).toBe(4);
expect(buttonLabelSubCopy.classes()).toContain('m-0');
expect(buttonLabelSubCopy.classes()).toContain('caption');
expect(buttonLabelSubCopy.classes()).toContain('ms-2');
expect(buttonLabelSubCopy.classes()).toContain(textPosition);
});
test('when "textPosition" prop not provided', async () => {
// Arrange
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button'
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonLabelSubCopy = wrapper.find(buttonLabelCopyReference);
// Assert
expect(buttonLabelSubCopy.exists()).toBeTruthy();
expect(buttonLabelSubCopy.classes().length).toBe(3);
expect(buttonLabelSubCopy.classes()).toContain('m-0');
expect(buttonLabelSubCopy.classes()).toContain('caption');
expect(buttonLabelSubCopy.classes()).toContain('ms-2');
});
});
describe('availability indicator block with expected when displayAvailabilityIndicators true', () => {
test('and availability rating is high', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve('high')
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorBlock = wrapper.find(availabilityIndicatorBlockReference);
// Assert
expect(availabilityIndicatorBlock.exists()).toBeTruthy();
expect(availabilityIndicatorBlock.classes()).toContain('availability-indicator');
expect(availabilityIndicatorBlock.classes()).toContain('rounded-pill');
expect(availabilityIndicatorBlock.classes()).toContain('green');
});
test.each(['low', ''])(
'and availability rating is not high or null',
async (availabilityBadge) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityBadge)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorBlock = wrapper.find(availabilityIndicatorBlockReference);
// Assert
expect(availabilityIndicatorBlock.exists()).toBeTruthy();
expect(availabilityIndicatorBlock.classes()).toContain('availability-indicator');
expect(availabilityIndicatorBlock.classes()).toContain('rounded-pill');
expect(availabilityIndicatorBlock.classes()).toContain('orange');
}
);
test.each([null, undefined])(
'and availability rating is null',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorBlock = wrapper.find(availabilityIndicatorBlockReference);
// Assert
expect(availabilityIndicatorBlock.exists()).toBeTruthy();
expect(availabilityIndicatorBlock.classes()).toContain('availability-indicator');
expect(availabilityIndicatorBlock.classes()).toContain('rounded-pill');
expect(availabilityIndicatorBlock.classes()).toContain('gray');
}
);
});
test('availability indicator block with expected classes when displayAvailabilityIndicators true', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorBlock = wrapper.find(availabilityIndicatorBlockReference);
// Assert
expect(availabilityIndicatorBlock.exists()).toBeTruthy();
expect(availabilityIndicatorBlock.classes()).toContain('availability-indicator');
expect(availabilityIndicatorBlock.classes()).toContain('rounded-pill');
});
describe('availability badge when displayAvailabilityIndicators true', () => {
test('and "availabilityRating" is "high"', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve('high')
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityBadge = wrapper.find(availabilityBadgeReference);
// Assert
expect(availabilityBadge.exists()).toBeTruthy();
expect(availabilityBadge.classes().length).toBe(2);
expect(availabilityBadge.classes()).toContain('availability-badge');
expect(availabilityBadge.classes()).toContain('green');
});
test.each(['low', ''])(
'and "availabilityRating" is not "high" or null',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityBadge = wrapper.find(availabilityBadgeReference);
// Assert
expect(availabilityBadge.exists()).toBeTruthy();
expect(availabilityBadge.classes().length).toBe(2);
expect(availabilityBadge.classes()).toContain('availability-badge');
expect(availabilityBadge.classes()).toContain('orange');
}
);
});
test('button body copy when buttonBodyCopy provided', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData,
buttonBodyCopy: 'body copy'
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonBodyCopy = wrapper.find(buttonBodyCopyReference);
// Assert
expect(buttonBodyCopy.exists()).toBeTruthy();
expect(buttonBodyCopy.classes()).toContain('m-0');
expect(buttonBodyCopy.classes()).toContain('button-label-sub-copy');
expect(buttonBodyCopy.classes()).toContain('small');
});
test('screen reader only text when screenReaderOnlyText provided', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const screenReaderOnlyText = 'text just for screen reader';
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData,
screenReaderOnlyText
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const screenReaderOnlySpan = wrapper.find(screenReaderOnlySpanReference);
// Assert
expect(screenReaderOnlySpan.exists()).toBeTruthy();
expect(screenReaderOnlySpan.classes()).toContain('sr-only');
expect(screenReaderOnlySpan.text()).toContain(screenReaderOnlyText);
});
});
describe('should not render', () => {
test('button body copy when buttonBodyCopy not provided', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const buttonBodyCopy = wrapper.find(buttonBodyCopyReference);
// Assert
expect(buttonBodyCopy.exists()).toBeFalsy();
});
test('screen reader only text when screenReaderOnlyText not provided', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const screenReaderOnlySpan = wrapper.find(screenReaderOnlySpanReference);
// Assert
expect(screenReaderOnlySpan.exists()).toBeFalsy();
});
});
describe('computed', () => {
describe('isLoaderDisplayed', () => {
test('should return false when availabilityRating is empty string', async () => {
// Arrange
const availabilityRating = '';
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const result = wrapper.vm.isLoaderDisplayed;
// Assert
expect(result).toBeFalsy();
});
test('should return false when availabilityRating is non-empty string', async () => {
// Arrange
const availabilityRating = 'not empty string';
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const result = wrapper.vm.isLoaderDisplayed;
// Assert
expect(result).toBeFalsy();
});
});
describe('availabilityRatingClass', () => {
test.each([null, undefined])(
'returns "gray" if availability rating null or undefined',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = 'gray';
// Act
const result = wrapper.vm.availabilityRatingClass;
// Assert
expect(result).toBe(expected);
}
);
test('returns green if availability rating is "high"', async () => {
// Arrange
const availabilityRating = 'high';
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = 'green';
// Act
const result = wrapper.vm.availabilityRatingClass;
// Assert
expect(result).toBe(expected);
});
test.each(['', 'not high'])(
'returns orange if availability not "high"',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = 'orange';
// Act
const result = wrapper.vm.availabilityRatingClass;
// Assert
expect(result).toBe(expected);
}
);
});
describe('badgeText', () => {
test.each([null, undefined])(
'returns empty string if availability rating null or undefined',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = '';
// Act
const result = wrapper.vm.badgeText;
// Assert
expect(result).toBe(expected);
}
);
test('returns "Appts available" if availability rating "high"', async () => {
// Arrange
const availabilityRating = 'high';
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = 'Appts available';
// Act
const result = wrapper.vm.badgeText;
// Assert
expect(result).toBe(expected);
});
test.each(['', 'not high'])(
'returns "Appts low" if availability rating not null or "high"',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const expected = 'Appts low';
// Act
const result = wrapper.vm.badgeText;
// Assert
expect(result).toBe(expected);
}
);
});
describe('selectedValue', () => {
test('"get" returns modalValue prop', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const modelValue = 'value of modal';
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue,
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const result = wrapper.vm.selectedValue;
// Assert
expect(result).toBe(modelValue);
});
test('"set" emits "update:modalValue" event', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve({})
};
const modelValue = 'value of modal';
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue,
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
const newValue = 'new value';
// Act
wrapper.vm.selectedValue = newValue;
// Assert
expect(wrapper.emitted()['update:modelValue'][0][0]).toEqual(newValue);
});
});
});
describe('before mount', () => {
test('should call availabilityRatingCallback with expected data if displayAvailabilityIndicators true', async () => {
// Arrange
const availabilityRating = 'rating';
const availabilityRatingCallback = jest.fn().mockImplementation(() => Promise.resolve(availabilityRating));
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(availabilityRatingCallback).toBeCalledTimes(1);
});
test('should not call availabilityRatingCallback if displayAvailabilityIndicators false', async () => {
// Arrange
const availabilityRating = 'rating';
const availabilityRatingCallback = jest.fn().mockImplementation(() => Promise.resolve(availabilityRating));
const additionalButtonData = {
displayAvailabilityIndicators: false,
availabilityRatingCallback
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Assert
expect(availabilityRatingCallback).toBeCalledTimes(0);
});
});
});