Skip to content

Commit e82d81f

Browse files
chore: fix form validation
1 parent 7b5ef7c commit e82d81f

File tree

2 files changed

+93
-4
lines changed

2 files changed

+93
-4
lines changed

Diff for: src/composables/__tests__/useFormValidation.test.ts

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { describe, expect, test } from 'vitest'
2+
import { useFormValidation } from '../useFormValidation'
3+
import { ref, nextTick } from 'vue'
4+
5+
describe('useFormValidation', () => {
6+
const createFormData = (data = {}) => ref({
7+
title: '',
8+
body: '',
9+
userId: '',
10+
...data
11+
})
12+
13+
test('validates title length', async () => {
14+
const formData = createFormData({ title: 'ab' })
15+
const { errors, touchField } = useFormValidation(formData)
16+
17+
// Initially no errors (not touched)
18+
expect(errors.value.title).toBeUndefined()
19+
20+
// Touch the field to trigger validation
21+
touchField('title')
22+
await nextTick()
23+
expect(errors.value.title).toBe('Title must be at least 3 characters')
24+
25+
// Update to valid length
26+
formData.value.title = 'abc'
27+
touchField('title')
28+
await nextTick()
29+
expect(errors.value.title).toBeUndefined()
30+
})
31+
32+
test('tracks form validity', async () => {
33+
const formData = createFormData()
34+
const { isValid, touchAll, setSubmitted } = useFormValidation(formData)
35+
36+
// Initially valid (no validation yet)
37+
expect(isValid.value).toBe(true)
38+
39+
// Validate all fields
40+
touchAll()
41+
setSubmitted()
42+
await nextTick()
43+
expect(isValid.value).toBe(false)
44+
45+
// Set valid data
46+
formData.value = {
47+
title: 'Valid Title',
48+
body: 'Valid content that is long enough',
49+
userId: '1'
50+
}
51+
touchAll()
52+
await nextTick()
53+
expect(isValid.value).toBe(true)
54+
})
55+
56+
test('resets validation state', async () => {
57+
const formData = createFormData()
58+
const { errors, touchField, resetValidation } = useFormValidation(formData)
59+
60+
// Set up error state
61+
touchField('title')
62+
await nextTick()
63+
expect(errors.value.title).toBe('Title is required')
64+
65+
// Reset validation
66+
resetValidation()
67+
await nextTick()
68+
expect(errors.value.title).toBeUndefined()
69+
})
70+
71+
test('validates in real-time when fields are touched', async () => {
72+
const formData = createFormData()
73+
const { errors, touchField } = useFormValidation(formData)
74+
75+
// Initially no validation
76+
expect(errors.value.title).toBeUndefined()
77+
78+
// Touch field to start validation
79+
touchField('title')
80+
await nextTick()
81+
expect(errors.value.title).toBe('Title is required')
82+
83+
// Update field and touch again
84+
formData.value.title = 'Valid Title'
85+
touchField('title')
86+
await nextTick()
87+
expect(errors.value.title).toBeUndefined()
88+
})
89+
})

Diff for: src/composables/useFormValidation.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ref, computed, watch, type Ref } from "vue";
1+
import { ref, computed, type Ref } from "vue";
22

33
interface FormData {
44
title: string;
@@ -54,12 +54,14 @@ export function useFormValidation(formData: Ref<FormData>) {
5454

5555
const touchField = (field: keyof TouchedFields) => {
5656
touched.value[field] = true;
57+
validateForm(); // Only validate when field is touched
5758
};
5859

5960
const touchAll = () => {
6061
for (const field of Object.keys(touched.value)) {
6162
touched.value[field as keyof TouchedFields] = true;
6263
}
64+
validateForm(); // Validate when all fields are touched
6365
};
6466

6567
const resetValidation = () => {
@@ -74,11 +76,9 @@ export function useFormValidation(formData: Ref<FormData>) {
7476

7577
const setSubmitted = () => {
7678
isSubmitted.value = true;
77-
validateForm();
79+
validateForm(); // Validate on form submission
7880
};
7981

80-
watch(formData, validateForm, { deep: true });
81-
8282
const isValid = computed(() => Object.keys(errors.value).length === 0);
8383

8484
const visibleErrors = computed(() => ({

0 commit comments

Comments
 (0)