feat: Replace SLA validationMixin within the component (#9804)

# Pull Request Template

## Description

This PR will completely remove the SLA `validationMixin` and be used in
the component as it is with a name change.

Fixes
https://linear.app/chatwoot/issue/CW-3456/rewrite-sla-validationmixin-mixin-to-a-composable

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Take a look at these components
1. `dashboard/routes/dashboard/settings/sla/AddSLA.vue` **(Not used)**
2. `dashboard/routes/dashboard/settings/sla/SlaForm.vue`
3. `dashboard/routes/dashboard/settings/sla/SlaTimeInput.vue`


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
This commit is contained in:
Sivin Varghese
2024-07-22 13:05:55 +05:30
committed by GitHub
parent cb0642564c
commit 84c380c8c4
5 changed files with 28 additions and 143 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div class="h-auto overflow-auto flex flex-col">
<div class="flex flex-col h-auto overflow-auto">
<woot-modal-header
:header-title="$t('SLA.ADD.TITLE')"
:header-content="$t('SLA.ADD.DESC')"
@@ -14,17 +14,14 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import validationMixin from './validationMixin';
import { mapGetters } from 'vuex';
import validations from './validations';
import SlaForm from './SlaForm.vue';
export default {
components: {
SlaForm,
},
mixins: [alertMixin, validationMixin],
validations,
mixins: [alertMixin],
computed: {
...mapGetters({
uiFlags: 'sla/getUIFlags',

View File

@@ -12,7 +12,7 @@
}"
:label="$t('SLA.FORM.NAME.LABEL')"
:placeholder="$t('SLA.FORM.NAME.PLACEHOLDER')"
:error="getSlaNameErrorMessage"
:error="slaNameErrorMessage"
@input="$v.name.$touch"
/>
<woot-input
@@ -70,7 +70,6 @@
<script>
import { mapGetters } from 'vuex';
import { convertSecondsToTimeUnit } from '@chatwoot/utils';
import validationMixin from './validationMixin';
import validations from './validations';
import SlaTimeInput from './SlaTimeInput.vue';
@@ -78,7 +77,6 @@ export default {
components: {
SlaTimeInput,
},
mixins: [validationMixin],
props: {
selectedResponse: {
type: Object,
@@ -130,6 +128,17 @@ export default {
this.uiFlags.isUpdating
);
},
slaNameErrorMessage() {
let errorMessage = '';
if (this.$v.name.$error) {
if (!this.$v.name.required) {
errorMessage = this.$t('SLA.FORM.NAME.REQUIRED_ERROR');
} else if (!this.$v.name.minLength) {
errorMessage = this.$t('SLA.FORM.NAME.MINIMUM_LENGTH_ERROR');
}
}
return errorMessage;
},
},
mounted() {
if (this.selectedResponse) this.setFormValues();

View File

@@ -11,7 +11,7 @@
}"
:label="label"
:placeholder="placeholder"
:error="getThresholdTimeErrorMessage"
:error="thresholdTimeErrorMessage"
@input="onThresholdTimeChange"
/>
<!-- the mt-7 handles the label offset -->
@@ -34,11 +34,9 @@
</template>
<script>
import validationMixin from './validationMixin';
import validations from './validations';
export default {
mixins: [validationMixin],
props: {
threshold: {
type: Number,
@@ -69,6 +67,19 @@ export default {
};
},
validations,
computed: {
thresholdTimeErrorMessage() {
let errorMessage = '';
if (this.$v.thresholdTime.$error) {
if (!this.$v.thresholdTime.numeric || !this.$v.thresholdTime.minValue) {
errorMessage = this.$t(
'SLA.FORM.THRESHOLD_TIME.INVALID_FORMAT_ERROR'
);
}
}
return errorMessage;
},
},
watch: {
threshold: {
immediate: true,

View File

@@ -1,106 +0,0 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import validationMixin from '../validationMixin';
import validations from '../validations';
import i18n from 'dashboard/i18n';
const localVue = createLocalVue();
localVue.use(VueI18n);
localVue.use(Vuelidate);
const i18nConfig = new VueI18n({
locale: 'en',
messages: i18n,
});
const TestComponent = {
render() {},
mixins: [validationMixin],
validations,
};
describe('validationMixin', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(TestComponent, {
localVue,
i18n: i18nConfig,
data() {
return {
name: '',
thresholdTime: '',
};
},
});
});
it('should not return required error message if name is empty but not touched', () => {
wrapper.setData({ name: '' });
expect(wrapper.vm.getSlaNameErrorMessage).toBe('');
});
it('should return empty error message if name is valid', () => {
wrapper.setData({ name: 'ValidName' });
wrapper.vm.$v.name.$touch();
expect(wrapper.vm.getSlaNameErrorMessage).toBe('');
});
it('should return required error message if name is empty', () => {
wrapper.setData({ name: '' });
wrapper.vm.$v.name.$touch();
expect(wrapper.vm.getSlaNameErrorMessage).toBe(
wrapper.vm.$t('SLA.FORM.NAME.REQUIRED_ERROR')
);
});
it('should return minimum length error message if name is too short', () => {
wrapper.setData({ name: 'a' });
wrapper.vm.$v.name.$touch();
expect(wrapper.vm.getSlaNameErrorMessage).toBe(
wrapper.vm.$t('SLA.FORM.NAME.MINIMUM_LENGTH_ERROR')
);
});
it('should accept valid threshold values', () => {
wrapper.setData({ thresholdTime: 10 });
wrapper.vm.$v.thresholdTime.$touch();
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe(wrapper.vm.$t(''));
wrapper.setData({ thresholdTime: 10.5 });
wrapper.vm.$v.thresholdTime.$touch();
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe(wrapper.vm.$t(''));
});
it('should not return invalid format error message if thresholdTime is empty but not touched', () => {
wrapper.setData({ thresholdTime: '' });
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe('');
});
it('should return invalid format error message if thresholdTime has an invalid format', () => {
wrapper.setData({ thresholdTime: 'fsdfsdfsdfsd' });
wrapper.vm.$v.thresholdTime.$touch();
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe(
wrapper.vm.$t('SLA.FORM.THRESHOLD_TIME.INVALID_FORMAT_ERROR')
);
});
it('should reject invalid threshold values', () => {
wrapper.setData({ thresholdTime: 0 });
wrapper.vm.$v.thresholdTime.$touch();
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe(
wrapper.vm.$t('SLA.FORM.THRESHOLD_TIME.INVALID_FORMAT_ERROR')
);
});
it('should reject invalid threshold values', () => {
wrapper.setData({ thresholdTime: -1 });
wrapper.vm.$v.thresholdTime.$touch();
expect(wrapper.vm.getThresholdTimeErrorMessage).toBe(
wrapper.vm.$t('SLA.FORM.THRESHOLD_TIME.INVALID_FORMAT_ERROR')
);
});
});

View File

@@ -1,26 +0,0 @@
export default {
computed: {
getSlaNameErrorMessage() {
let errorMessage = '';
if (this.$v.name.$error) {
if (!this.$v.name.required) {
errorMessage = this.$t('SLA.FORM.NAME.REQUIRED_ERROR');
} else if (!this.$v.name.minLength) {
errorMessage = this.$t('SLA.FORM.NAME.MINIMUM_LENGTH_ERROR');
}
}
return errorMessage;
},
getThresholdTimeErrorMessage() {
let errorMessage = '';
if (this.$v.thresholdTime.$error) {
if (!this.$v.thresholdTime.numeric || !this.$v.thresholdTime.minValue) {
errorMessage = this.$t(
'SLA.FORM.THRESHOLD_TIME.INVALID_FORMAT_ERROR'
);
}
}
return errorMessage;
},
},
};