DigitalConsumer.ISS/src/digital-components/textbox-question/textbox-question.spec.js
2023-11-02 09:42:43 -04:00

954 lines
37 KiB
JavaScript

import { shallowMount } from '@vue/test-utils';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import { useField, validate } from 'vee-validate';
// Mock CMS content
const questionText = 'Question Text';
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() => questionText)
}
};
jest.mock('vee-validate', () => ({
useField: jest.fn(),
validate: jest.fn()
}));
useField.mockImplementation(() => Promise.resolve({}));
validate.mockImplementation(() => Promise.resolve({}));
const searchButtonSelector = 'button[type="submit"][aria-label="Search button"]';
const selectButtonSelector = 'button[type="submit"][aria-label="Select button"]';
const errorMessageSelector = { ref: 'errorMessageDiv' };
describe('TextboxQuestion', () => {
describe('should render', () => {
describe('an input element', () => {
test('that exists with expected classes', () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.exists()).toBeTruthy();
expect(input.classes()).toContain('form-control');
});
describe('with correct attributes and classes given prop', () => {
test('type', () => {
// Arrange
const type = 'crocodile';
const wrapper = shallowMount(textboxQuestion, {
propsData: { type },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().type).toBe(type);
});
test('placeholderText', () => {
// Arrange
const placeholderText = 'text in place';
const wrapper = shallowMount(textboxQuestion, {
propsData: { placeholderText },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().placeholder).toBe(placeholderText);
});
test('inputId', () => {
// Arrange
const inputId = '123009';
const wrapper = shallowMount(textboxQuestion, {
propsData: { inputId },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('id')).toBe(inputId);
expect(input.attributes('name')).toBe(inputId);
});
describe('isDisabled', () => {
test('with value "true"', () => {
// Arrange
const isDisabled = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { isDisabled },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('aria-disabled')).toBe(String(isDisabled));
expect(input.attributes().disabled).toBeDefined();
});
test('with value "false"', () => {
// Arrange
const isDisabled = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { isDisabled },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('aria-disabled')).toBe(String(isDisabled));
expect(input.attributes().disabled).not.toBeDefined();
});
});
describe('isRequired', () => {
test('with value "true"', () => {
// Arrange
const isRequired = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { isRequired },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().required).toBeDefined();
});
test('with value "false"', () => {
// Arrange
const isRequired = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { isRequired },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().required).not.toBeDefined();
});
});
describe('hasIcon', () => {
test('with value "true"', () => {
// Arrange
const hasIcon = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { hasIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).toContain('has-icon');
});
test('with value "false"', () => {
// Arrange
const hasIcon = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { hasIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).not.toContain('has-icon');
});
});
describe('iconRight', () => {
test('with value "true"', () => {
// Arrange
const iconRight = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { iconRight },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).toContain('icon-right');
});
test('with value "false"', () => {
// Arrange
const iconRight = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { iconRight },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).not.toContain('icon-right');
});
});
test('validationRules', () => {
// Arrange
const validationRules = 'random validation rules';
const wrapper = shallowMount(textboxQuestion, {
propsData: { validationRules },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().validationrules).toBe(validationRules);
});
test('cmsWidgetName', () => {
// Arrange
const cmsWidgetName = 'name of widget';
const wrapper = shallowMount(textboxQuestion, {
propsData: { cmsWidgetName },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const expected = '#name of widget';
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('data-bs-target')).toBe(expected);
});
describe('maxLength', () => {
test('with no value', () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const expected = '999';
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('maxlength')).toBe(expected);
});
test('with some value', () => {
// Arrange
const maxLength = '123';
const wrapper = shallowMount(textboxQuestion, {
propsData: { maxLength },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('maxlength')).toBe(maxLength);
});
});
describe('cornerStyle', () => {
test('with value "rounded"', () => {
// Arrange
const cornerStyle = 'rounded';
const wrapper = shallowMount(textboxQuestion, {
propsData: { cornerStyle },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).toContain('rounded-pill');
});
test('with value other than "rounded"', () => {
// Arrange
const cornerStyle = 'decidedly not rounded';
const wrapper = shallowMount(textboxQuestion, {
propsData: { cornerStyle },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.classes()).not.toContain('rounded-pill');
});
});
describe('includeSelectIcon', () => {
test('with value "true"', () => {
// Arrange
const includeSelectIcon = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSelectIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('data-bs-toggle')).toBe('modal');
});
test('with value "false"', () => {
// Arrange
const includeSelectIcon = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSelectIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes('data-bs-toggle')).toBe('');
});
});
test('min', () => {
// Arrange
const min = 'some value';
const wrapper = shallowMount(textboxQuestion, {
propsData: { min },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().min).toBe(min);
});
test('max', () => {
// Arrange
const max = 'some value';
const wrapper = shallowMount(textboxQuestion, {
propsData: { max },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const input = wrapper.find('input');
// Assert
expect(input.attributes().max).toBe(max);
});
});
});
describe('a label element given that displayQuestionText is true with correct attributes and classes set with prop', () => {
const displayQuestionText = true;
test('inputId', () => {
// Arrange
const inputId = '123758';
const wrapper = shallowMount(textboxQuestion, {
propsData: { displayQuestionText, inputId },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const label = wrapper.find('label');
// Assert
expect(label.exists()).toBeTruthy();
expect(label.attributes().for).toBe(inputId);
expect(label.attributes('aria-label')).toBe(questionText);
expect(label.classes()).toContain('form-label');
});
describe('questionAlignment', () => {
test('having value "center"', () => {
// Arrange
const questionAlignment = 'center';
const wrapper = shallowMount(textboxQuestion, {
propsData: { displayQuestionText, questionAlignment },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const label = wrapper.find('label');
// Assert
expect(label.exists()).toBeTruthy();
expect(label.attributes('aria-label')).toBe(questionText);
expect(label.classes()).toContain('form-label');
expect(label.classes()).toContain('text-center');
expect(label.classes()).toContain('w-100');
expect(label.classes()).toContain('mb-5');
});
test('having value other than "center"', () => {
// Arrange
const questionAlignment = 'not center';
const wrapper = shallowMount(textboxQuestion, {
propsData: { displayQuestionText, questionAlignment },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const label = wrapper.find('label');
// Assert
expect(label.exists()).toBeTruthy();
expect(label.attributes('aria-label')).toBe(questionText);
expect(label.classes()).toContain('form-label');
expect(label.classes()).not.toContain('text-center');
expect(label.classes()).not.toContain('w-100');
expect(label.classes()).not.toContain('mb-5');
});
});
});
test('a search button with the correct attributes and classes if includeSearchIcon is true', () => {
// Arrange
const includeSearchIcon = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSearchIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const searchButton = wrapper.find(searchButtonSelector);
// Assert
expect(searchButton.exists()).toBeTruthy();
expect(searchButton.attributes('type')).toBe('submit');
expect(searchButton.attributes('aria-label')).toBe('Search button');
});
describe('a select button with the correct attributes and classes if includeSelectIcon is true', () => {
const includeSelectIcon = true;
test('where cmsWidgetName defined', () => {
// Arrange
const cmsWidgetName = 'name of cms widget';
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSelectIcon, cmsWidgetName },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const expectedDataBsTarget = '#name of cms widget';
// Act
const selectButton = wrapper.find(selectButtonSelector);
// Assert
expect(selectButton.exists()).toBeTruthy();
expect(selectButton.attributes().type).toBe('submit');
expect(selectButton.attributes('data-bs-toggle')).toBe('modal');
expect(selectButton.attributes('data-bs-target')).toBe(expectedDataBsTarget);
expect(selectButton.attributes('aria-label')).toBe('Select button');
});
test('where cmsWidgetName not defined', () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSelectIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const expectedDataBsTarget = '#';
// Act
const selectButton = wrapper.find(selectButtonSelector);
// Assert
expect(selectButton.exists()).toBeTruthy();
expect(selectButton.attributes().type).toBe('submit');
expect(selectButton.attributes('data-bs-toggle')).toBe('modal');
expect(selectButton.attributes('data-bs-target')).toBe(expectedDataBsTarget);
expect(selectButton.attributes('aria-label')).toBe('Select button');
});
});
test('an error with the correct attributes and classes if errorMessage is not empty', () => {
// Arrange
const errorMessage = 'some not empty message';
useField.mockReturnValueOnce({ errorMessage });
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const error = wrapper.find(errorMessageSelector);
// Assert
expect(error.exists()).toBeTruthy();
expect(error.attributes().style).not.toBeDefined();
expect(error.classes()).toContain('form-test-error');
expect(error.classes()).toContain('row');
expect(error.classes()).toContain('my-1');
});
});
describe('does not render', () => {
test('a label element if displayQuestionText is false', () => {
// Arrange
const displayQuestionText = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { displayQuestionText },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const label = wrapper.find('label');
// Assert
expect(label.exists()).not.toBeTruthy();
});
test('a search button element if includeSearchIcon is false', () => {
// Arrange
const includeSearchIcon = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSearchIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const searchButton = wrapper.find(searchButtonSelector);
// Assert
expect(searchButton.exists()).not.toBeTruthy();
});
test('a select button if includeSelectIcon is false', () => {
// Arrange
const includeSelectIcon = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { includeSelectIcon },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const selectButton = wrapper.find(selectButtonSelector);
// Assert
expect(selectButton.exists()).not.toBeTruthy();
});
test('an error span if errorMessage is empty', () => {
// Arrange
const errorMessage = '';
const wrapper = shallowMount(textboxQuestion, {
propsData: { errorMessage },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
const errorSpan = wrapper.find(errorMessageSelector);
// Assert
expect(errorSpan.attributes().style).toContain('display: none;');
});
});
test('should return the errorMessage, handleBlur, handleChange, meta, validate and errors values from the useField hook', () => {
// Arrange
const errorMessage = 'some not empty message';
const handleBlur = () => { console.log('blur'); };
const handleChange = () => { console.log('change'); };
const meta = 'meta content';
const setValidate = () => { console.log('validate'); };
const errors = 'content of errors';
useField.mockReturnValueOnce({
errorMessage, handleBlur, handleChange, meta, errors, validate: setValidate
});
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Assert
expect(wrapper.vm.errorMessage).toBe(errorMessage);
expect(wrapper.vm.handleBlur).toBe(handleBlur);
expect(wrapper.vm.handleChange).toBe(handleChange);
expect(wrapper.vm.meta).toBe(meta);
expect(wrapper.vm.validate).toBe(setValidate);
expect(wrapper.vm.errors).toBe(errors);
});
describe('computed', () => {
test('"questionText" should return value based on getCmsContent result', () => {
// Arrange
const cmsContent = 'content from cms';
mockMixin.methods.getCmsContent.mockReturnValueOnce(cmsContent);
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Assert
expect(wrapper.vm.questionText).toBe(cmsContent);
});
describe('"value" should', () => {
test('get the modelValue prop', () => {
// Arrange
const modelValue = 'value of modelValue';
const wrapper = shallowMount(textboxQuestion, {
propsData: { modelValue },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Assert
expect(wrapper.vm.value).toBe(modelValue);
});
test('emit the "update:modelValue" event when updated', () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const newValue = 'updated value';
// Act
wrapper.vm.value = newValue;
// Assert
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
expect(wrapper.emitted('update:modelValue').length).toBe(1); // event emitted once
expect(wrapper.emitted('update:modelValue')[0]).toEqual([newValue]); // emitted with expected payload
});
});
describe('labelText', () => {
test('should return the question text with no break characters if disableAutoFill is true', () => {
// Arrange
const disableAutoFill = true;
const wrapper = shallowMount(textboxQuestion, {
propsData: { disableAutoFill },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// TODO this seems like strange behavior to me
const expectedLabelText = 'Q⁠uestion T⁠ext';
// Assert
expect(wrapper.vm.labelText).toBe(expectedLabelText);
});
test('should return the question text as it is if disableAutoFill is false', () => {
// Arrange
const disableAutoFill = false;
const wrapper = shallowMount(textboxQuestion, {
propsData: { disableAutoFill },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Assert
expect(wrapper.vm.labelText).toBe(questionText);
});
});
});
describe('watch', () => {
test('should validate the new value and trigger full validation if valid', async () => {
// Arrange
const handleChange = jest.fn();
const modelValue = 'initial value';
const validationRules = 'required';
validate.mockReturnValueOnce({ valid: true });
useField.mockReturnValueOnce({ handleChange });
const wrapper = shallowMount(textboxQuestion, {
propsData: { modelValue, validationRules },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const newValue = 'new value';
// Act
await wrapper.vm.$options.watch.value.call(wrapper.vm, newValue);
// Assert
expect(validate).toHaveBeenCalledWith(newValue, validationRules);
expect(handleChange).toHaveBeenCalledWith(newValue);
});
test('should not trigger full validation if invalid', async () => {
// Arrange
const handleChange = jest.fn();
const modelValue = 'initial value';
const validationRules = 'required';
validate.mockReturnValueOnce({ valid: false });
useField.mockReturnValueOnce({ handleChange });
const wrapper = shallowMount(textboxQuestion, {
propsData: { modelValue, validationRules },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
const newValue = 'failing value';
// Act
await wrapper.vm.$options.watch.value.call(wrapper.vm, newValue);
// Assert
expect(validate).toHaveBeenCalledWith(newValue, validationRules);
expect(handleChange).not.toHaveBeenCalled();
});
test('should emit new value when modelValue is changed', async () => {
// Act
const wrapper = shallowMount(textboxQuestion, {
global: {
directives: { maska: jest.fn() }
},
propsData: {
modelValue: 'val'
},
mixins: [mockMixin]
});
await wrapper.find('input').setValue('val2');
// Assert
expect(wrapper.emitted()).toHaveProperty('change');
});
});
describe('mounted hook', () => {
test('should emit an inputId assigned event with the inputId prop as an argument', () => {
// Arrange
const inputId = '126743';
const wrapper = shallowMount(textboxQuestion, {
propsData: { inputId },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Assert
expect(wrapper.emitted()['textboxQuestionEvent.inputIdAssigned']).toBeTruthy();
expect(wrapper.emitted()['textboxQuestionEvent.inputIdAssigned'][0]).toEqual([inputId]);
});
});
describe('method', () => {
describe('trimOnPaste', () => {
test('should trim the pasted text and update the model value', () => {
// Arrange
document.getElementById = jest.fn(() => ({
value: ' hello ',
selectionStart: 7,
selectionEnd: 7
}));
const stopPropagation = jest.fn();
const preventDefault = jest.fn();
const data = { getData: jest.fn(() => ' world ') };
const inputId = '123758';
const pasteEvent = {
type: 'paste',
srcElement: { id: inputId },
clipboardData: data,
stopPropagation,
preventDefault
};
const wrapper = shallowMount(textboxQuestion, {
propsData: { inputId },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
wrapper.vm.trimOnPaste(pasteEvent);
// Assert
expect(stopPropagation).toHaveBeenCalled();
expect(preventDefault).toHaveBeenCalled();
expect(data.getData).toHaveBeenCalledWith('Text');
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([' hello world ']);
});
test('should trim the dropped text and update the model value', () => {
// Arrange
document.getElementById = jest.fn(() => ({
value: ' hello ',
selectionStart: 7,
selectionEnd: 7
}));
const stopPropagation = jest.fn();
const preventDefault = jest.fn();
const data = { getData: jest.fn(() => ' world ') };
const inputId = '123758';
const dropEvent = {
type: 'drop',
srcElement: { id: inputId },
dataTransfer: data,
stopPropagation,
preventDefault
};
const wrapper = shallowMount(textboxQuestion, {
propsData: { inputId },
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
wrapper.vm.trimOnPaste(dropEvent);
// Assert
expect(stopPropagation).toHaveBeenCalled();
expect(preventDefault).toHaveBeenCalled();
expect(data.getData).toHaveBeenCalledWith('Text');
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([' hello world ']);
});
});
describe('clickedSearch', () => {
test('should emit a click event if the meta valid flag is true', () => {
// Arrange
const meta = { valid: true };
useField.mockReturnValueOnce({ meta });
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
wrapper.vm.clickedSearch();
// Assert
expect(wrapper.emitted()['click-event']).toBeTruthy();
});
test('should not emit a click event if the meta valid flag is falsy', () => {
// Arrange
const meta = { };
useField.mockReturnValueOnce({ meta });
const wrapper = shallowMount(textboxQuestion, {
mixins: [mockMixin],
global: {
directives: { maska: jest.fn() }
}
});
// Act
wrapper.vm.clickedSearch();
// Assert
expect(wrapper.emitted()['click-event']).not.toBeTruthy();
});
});
});
});