Adding tests for textarea question component

This commit is contained in:
brydon1 2023-07-10 13:22:31 -04:00
parent 51daeb0028
commit a1f5d577a0
5 changed files with 376 additions and 25 deletions

View file

@ -1 +1,348 @@
// TODO finish
// Components
import textareaQuestion from '@/digital-components/textarea-question/textarea-question.vue';
// Supporting Files
import { shallowMount } from '@vue/test-utils';
import { getRandomString, getRandomInt } from '@/helpers/data-generation';
import { nextTick } from 'vue';
import { defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
describe('textarea-question.vue', () => {
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() =>
getRandomString(10, 20)),
setCmsContent: jest.fn()
}
};
describe('Expected components rendered', () => {
test('Label rendered', () => {
// Arrange
const questionText = getRandomString(10, 20);
const mixinWithQuestion = {
methods: {
getCmsContent: jest.fn().mockImplementation(() =>
questionText),
setCmsContent: jest.fn()
}
};
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20)
},
mixins: [mixinWithQuestion]
});
// Act
const label = wrapper.find('label');
// Assert
expect(label.exists()).toBe(true);
expect(wrapper.text()).toContain(questionText);
});
test('Textarea rendered', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20)
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.exists()).toBe(true);
});
test('Character count rendered', () => {
// Arrange
const maxLength = getRandomInt(100, 900);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
maxLength
},
mixins: [mockMixin]
});
const expected = `0/${maxLength}`;
// Act
// Assert
expect(wrapper.text()).toContain(expected);
});
test('Error rendered', async () => {
// Arrange
const maxLength = getRandomInt(100, 900);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
maxLength
},
mixins: [mockMixin]
});
// Act
const errorComponent = wrapper.find('#error-message');
expect(errorComponent.text()).toBe('');
const errorMessage = getRandomString(20, 30);
wrapper.vm.resetField({
errors: [errorMessage]
});
await nextTick();
// Assert
expect(errorComponent.text()).toBe(errorMessage);
});
test('Not required => optional text rendered', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
isRequired: false
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.text()).toContain('Optional');
});
test('Required => optional text not rendered', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
isRequired: true
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.text()).not.toContain('Optional');
});
});
describe('Computed properties rendered', () => {
describe('characterCount', () => {
test('Model value null => character count is 0 ', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue: null
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.vm.characterCount).toBe(0);
});
test('Model value undefined => character count is 0', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue: undefined
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.vm.characterCount).toBe(0);
});
test('Model value empty string => character count is 0', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue: ''
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.vm.characterCount).toBe(0);
});
test('Model value non-empty string => character count is as expected', () => {
// Arrange
const length = getRandomInt(10, 30);
const value = getRandomString(length, length);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue: value
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.vm.characterCount).toBe(length);
});
});
describe('value', () => {
test('Get value corresponds to modelValue', () => {
// Arrange
const modelValue = getRandomString(10, 20);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue
},
mixins: [mockMixin]
});
// Act
// Assert
expect(wrapper.vm.value).toBe(modelValue);
});
test('Set value => update modelValue event emitted with new value', () => {
// Arrange
const modelValue = getRandomString(10, 20);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
modelValue
},
mixins: [mockMixin]
});
const newValue = getRandomString(10, 20);
// Act
wrapper.vm.value = newValue;
// Assert
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
expect(wrapper.emitted('update:modelValue')[0][0]).toEqual(newValue);
});
});
});
describe('Properties properly affect initial state', () => {
test('Placeholder text sets placeholder text of text area', () => {
// Arrange
const placeholderText = getRandomString(10, 20);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
placeholderText
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().placeholder).toBe(placeholderText);
});
test('isDisabled true => textarea disabled', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
isDisabled: true
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().disabled).toBeDefined();
});
test('isRequired true => textarea required', () => {
// Arrange
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
isRequired: true
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().required).toBeDefined();
});
test('validationRules set rules of text area', () => {
// Arrange
const rule = getRandomString(10, 20);
const errorMessage = getRandomString(20, 30);
defineRule(rule, required(errorMessage));
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
validationRules: rule
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().validationrules).toBe(rule);
});
test('maxLength set max length of text area', () => {
// Arrange
const maxLength = toString(getRandomInt(100, 900));
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
maxLength
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().maxlength).toBe(maxLength);
});
test('inputRows set input rows of text area', () => {
// Arrange
const inputRows = getRandomInt(10, 20);
const wrapper = shallowMount(textareaQuestion, {
propsData: {
inputId: getRandomString(10, 20),
cmsWidgetName: getRandomString(10, 20),
inputRows
},
mixins: [mockMixin]
});
// Act
const textarea = wrapper.find('textarea');
// Assert
expect(textarea.attributes().rows).toBe(`${inputRows}`);
});
});
});

View file

@ -1,7 +1,7 @@
<template>
<div
class="textarea-question"
:class="(errors && errors.length) || hasError ? 'has-error' : ''">
:class="(errors && errors.length) ? 'has-error' : ''">
<label
:for="inputId"
class="form-label">
@ -17,12 +17,14 @@
v-model.trim="value"
class="form-control"
:name="inputId"
:rows="[inputRows ?? 3]"
:rows="[inputRows ?? 10]"
:placeholder="placeholderText"
:disabled="isDisabled"
:required="isRequired"
:maxlength="maxLength"
:validationRules="validationRules"
@change="validationRules ? handleChange : () => {}"
@blur="validationRules ? handleBlur : () => {}"
@paste="trimOnPaste"
@drop="trimOnPaste">
</textarea>
@ -32,6 +34,7 @@
</p>
<div
v-show="errorMessage"
id="error-message"
class="row my-1 form-test-error">
<span
class="d-inline-flex mt-0"
@ -58,13 +61,18 @@ export default {
modelValue: String,
isDisabled: Boolean,
isRequired: Boolean,
hasError: Boolean,
validationRules: String,
cmsWidgetName: String,
maxLength: String,
cmsWidgetName: {
type: String,
required: true
},
maxLength: {
type: String,
default: '300'
},
inputRows: Number
},
emits: ['update:modelValue', 'textareaQuestionEvent.inputIdAssigned'],
emits: ['update:modelValue'],
setup(props) {
const propsClone = { ...props };
const { modelValue } = propsClone;
@ -78,8 +86,10 @@ export default {
const { errorMessage,
handleChange,
handleBlur,
validate,
errors }
errors,
resetField }
= useField(props.inputId,
props.validationRules,
fieldOptions);
@ -87,8 +97,10 @@ export default {
return {
errorMessage,
handleChange,
handleBlur,
validate,
errors
errors,
resetField
};
},
computed: {
@ -107,18 +119,6 @@ export default {
}
}
},
watch: {
async value(newValue) {
const result = await this.validate(newValue, this.validationRules);
if (result.valid) {
this.handleChange(newValue);
}
}
},
mounted() {
// TODO do we need to do anything else for this event?
this.$emit('textareaQuestionEvent.inputIdAssigned', this.inputId);
},
methods: {
trimOnPaste(evt) {
evt.stopPropagation();
@ -147,7 +147,7 @@ export default {
}
.form-control {
max-height: 5rem;
max-height: 30rem;
border: 1px solid $gray-500;
border-radius: 0.5rem;
padding: 12px 16px;

View file

@ -62,10 +62,9 @@
inputId="technicianNotes"
:isDisabled="false"
:isRequired="false"
hasError="hasError"
:cmsWidgetName="widget.notesQuestion"
maxLength="500"
inputRows="30" />
:inputRows="3" />
<p
ref="disclaimerText"

View file

@ -26,7 +26,7 @@ import { issPageValues } from "@/router/router-constants/issPage-values";
import { Form } from "vee-validate";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import globalRules from '@/helpers/global-rules';
import globalRules from '@/constants/global-rules';
export default {
name: "part-questions",

View file

@ -8,6 +8,10 @@ import {vinLookupMethodSelections} from '@/constants/vin-lookup-methods';
import { useMainStore } from '@/store';
import { createTestingPinia } from '@pinia/testing';
import { mapStores } from "pinia";
import { defineRule } from 'vee-validate';
import { errorMessages } from '@/constants/error-messages';
import globalRules from '@/constants/global-rules';
import { required } from '@/helpers/validation-rules';
const pinia = createTestingPinia();
useMainStore(pinia);
@ -44,6 +48,7 @@ const siteFooterWidgetMockData = {
};
function setupMocks() {
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
const mockRoute = {
query: {
issPage: 'vehicle-lookup',