Skip to content

Commit a9d319d

Browse files
authored
feat(valibot): add more tests, support of criteriaMode and reduce size (#620)
* feat(valibot): add more tests, support of criteriaMode and reduce size * tests(valibot): remove only * test
1 parent c1d5433 commit a9d319d

File tree

6 files changed

+627
-53
lines changed

6 files changed

+627
-53
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React from 'react';
2+
import { useForm } from 'react-hook-form';
3+
import { render, screen } from '@testing-library/react';
4+
import user from '@testing-library/user-event';
5+
import { string, required, object, minLength } from 'valibot';
6+
import { valibotResolver } from '..';
7+
8+
const USERNAME_REQUIRED_MESSAGE = 'username field is required';
9+
const PASSWORD_REQUIRED_MESSAGE = 'password field is required';
10+
11+
const schema = required(
12+
object({
13+
username: string(USERNAME_REQUIRED_MESSAGE, [
14+
minLength(2, USERNAME_REQUIRED_MESSAGE),
15+
]),
16+
password: string(PASSWORD_REQUIRED_MESSAGE, [
17+
minLength(2, PASSWORD_REQUIRED_MESSAGE),
18+
]),
19+
}),
20+
);
21+
22+
type FormData = { username: string; password: string };
23+
24+
interface Props {
25+
onSubmit: (data: FormData) => void;
26+
}
27+
28+
function TestComponent({ onSubmit }: Props) {
29+
const { register, handleSubmit } = useForm<FormData>({
30+
resolver: valibotResolver(schema),
31+
shouldUseNativeValidation: true,
32+
});
33+
34+
return (
35+
<form onSubmit={handleSubmit(onSubmit)}>
36+
<input {...register('username')} placeholder="username" />
37+
38+
<input {...register('password')} placeholder="password" />
39+
40+
<button type="submit">submit</button>
41+
</form>
42+
);
43+
}
44+
45+
test("form's native validation with Zod", async () => {
46+
const handleSubmit = vi.fn();
47+
render(<TestComponent onSubmit={handleSubmit} />);
48+
49+
// username
50+
let usernameField = screen.getByPlaceholderText(
51+
/username/i,
52+
) as HTMLInputElement;
53+
expect(usernameField.validity.valid).toBe(true);
54+
expect(usernameField.validationMessage).toBe('');
55+
56+
// password
57+
let passwordField = screen.getByPlaceholderText(
58+
/password/i,
59+
) as HTMLInputElement;
60+
expect(passwordField.validity.valid).toBe(true);
61+
expect(passwordField.validationMessage).toBe('');
62+
63+
await user.click(screen.getByText(/submit/i));
64+
65+
// username
66+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
67+
expect(usernameField.validity.valid).toBe(false);
68+
expect(usernameField.validationMessage).toBe(USERNAME_REQUIRED_MESSAGE);
69+
70+
// password
71+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
72+
expect(passwordField.validity.valid).toBe(false);
73+
expect(passwordField.validationMessage).toBe(PASSWORD_REQUIRED_MESSAGE);
74+
75+
await user.type(screen.getByPlaceholderText(/password/i), 'password');
76+
77+
// password
78+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
79+
expect(passwordField.validity.valid).toBe(true);
80+
expect(passwordField.validationMessage).toBe('');
81+
});

valibot/src/__tests__/Form.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import user from '@testing-library/user-event';
4+
import { useForm } from 'react-hook-form';
5+
import { string, required, object, minLength } from 'valibot';
6+
import { valibotResolver } from '..';
7+
8+
const USERNAME_REQUIRED_MESSAGE = 'username field is required';
9+
const PASSWORD_REQUIRED_MESSAGE = 'password field is required';
10+
11+
const schema = required(
12+
object({
13+
username: string(USERNAME_REQUIRED_MESSAGE, [
14+
minLength(2, USERNAME_REQUIRED_MESSAGE),
15+
]),
16+
password: string(PASSWORD_REQUIRED_MESSAGE, [
17+
minLength(2, PASSWORD_REQUIRED_MESSAGE),
18+
]),
19+
}),
20+
);
21+
22+
type FormData = { username: string; password: string };
23+
24+
interface Props {
25+
onSubmit: (data: FormData) => void;
26+
}
27+
28+
function TestComponent({ onSubmit }: Props) {
29+
const {
30+
register,
31+
handleSubmit,
32+
formState: { errors },
33+
} = useForm<FormData>({
34+
resolver: valibotResolver(schema), // Useful to check TypeScript regressions
35+
});
36+
37+
return (
38+
<form onSubmit={handleSubmit(onSubmit)}>
39+
<input {...register('username')} />
40+
{errors.username && <span role="alert">{errors.username.message}</span>}
41+
42+
<input {...register('password')} />
43+
{errors.password && <span role="alert">{errors.password.message}</span>}
44+
45+
<button type="submit">submit</button>
46+
</form>
47+
);
48+
}
49+
50+
test("form's validation with Valibot and TypeScript's integration", async () => {
51+
const handleSubmit = vi.fn();
52+
render(<TestComponent onSubmit={handleSubmit} />);
53+
54+
expect(screen.queryAllByRole('alert')).toHaveLength(0);
55+
56+
await user.click(screen.getByText(/submit/i));
57+
58+
expect(screen.getByText(/username field is required/i)).toBeInTheDocument();
59+
expect(screen.getByText(/password field is required/i)).toBeInTheDocument();
60+
expect(handleSubmit).not.toHaveBeenCalled();
61+
});

valibot/src/__tests__/__fixtures__/data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
array,
1313
boolean,
1414
required,
15+
union
1516
} from 'valibot';
1617

1718
export const schema = required(
@@ -28,7 +29,7 @@ export const schema = required(
2829
minLength(8, 'Must be at least 8 characters in length'),
2930
]),
3031
repeatPassword: string('Repeat Password is required'),
31-
accessToken: string('Access token is required'),
32+
accessToken: union([string('Access token should be a string'), number('Access token should be a number')], "access token is required"),
3233
birthYear: number('Please enter your birth year', [
3334
minValue(1900),
3435
maxValue(2013),

0 commit comments

Comments
 (0)