@refinedev/react-hook-form 4.8.14 → 4.8.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js.map +1 -1
- package/dist/iife/index.js +18 -18
- package/dist/iife/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/useForm/index.d.ts.map +1 -1
- package/dist/useModalForm/index.d.ts +13 -13
- package/dist/useModalForm/index.d.ts.map +1 -1
- package/dist/useStepsForm/index.d.ts +10 -10
- package/dist/useStepsForm/index.d.ts.map +1 -1
- package/package.json +32 -32
- package/src/index.ts +6 -6
- package/src/useForm/index.spec.tsx +210 -222
- package/src/useForm/index.ts +227 -229
- package/src/useModalForm/index.spec.ts +243 -243
- package/src/useModalForm/index.ts +256 -265
- package/src/useStepsForm/index.spec.ts +103 -107
- package/src/useStepsForm/index.ts +120 -120
|
@@ -7,242 +7,230 @@ import { Route, Routes } from "react-router-dom";
|
|
|
7
7
|
import { IRefineOptions } from "@refinedev/core/dist/interfaces";
|
|
8
8
|
|
|
9
9
|
interface IPost {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
title: string;
|
|
11
|
+
content: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
category: { id: number };
|
|
14
|
+
tags: string[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const renderForm = ({
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
refineCoreProps,
|
|
19
|
+
refineOptions,
|
|
20
|
+
useFormProps,
|
|
21
21
|
}: {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
useFormProps?: any;
|
|
23
|
+
refineCoreProps?: any;
|
|
24
|
+
refineOptions?: IRefineOptions;
|
|
25
25
|
}) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
26
|
+
const EditPage = () => {
|
|
27
|
+
const {
|
|
28
|
+
refineCore: { formLoading },
|
|
29
|
+
saveButtonProps,
|
|
30
|
+
register,
|
|
31
|
+
formState: { errors },
|
|
32
|
+
} = useForm<IPost, HttpError, IPost>({
|
|
33
|
+
...useFormProps,
|
|
34
|
+
refineCoreProps: {
|
|
35
|
+
resource: "posts",
|
|
36
|
+
...refineCoreProps,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div>
|
|
42
|
+
{formLoading && <p>loading</p>}
|
|
43
|
+
<input {...register("title")} />
|
|
44
|
+
{errors.title && <span>{errors?.title?.message?.toString()}</span>}
|
|
45
|
+
|
|
46
|
+
<input {...register("content")} />
|
|
47
|
+
{errors.content && <span>{errors?.content?.message?.toString()}</span>}
|
|
48
|
+
|
|
49
|
+
<input {...register("slug")} />
|
|
50
|
+
{errors.slug && <span>{errors?.slug?.message?.toString()}</span>}
|
|
51
|
+
|
|
52
|
+
<select
|
|
53
|
+
{...register("category.id", {
|
|
54
|
+
required: true,
|
|
55
|
+
})}
|
|
56
|
+
>
|
|
57
|
+
{["1", "2", "3"]?.map((category) => (
|
|
58
|
+
<option key={category} value={category}>
|
|
59
|
+
{category}
|
|
60
|
+
</option>
|
|
61
|
+
))}
|
|
62
|
+
</select>
|
|
63
|
+
{errors.category && <span>{`${errors.category?.id?.message}`}</span>}
|
|
64
|
+
|
|
65
|
+
<button
|
|
66
|
+
{...saveButtonProps}
|
|
67
|
+
onClick={(e) => {
|
|
68
|
+
saveButtonProps?.onClick(e);
|
|
69
|
+
}}
|
|
70
|
+
data-testid="refine-save-button"
|
|
71
|
+
type="submit"
|
|
72
|
+
>
|
|
73
|
+
save
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return render(
|
|
80
|
+
<Routes>
|
|
81
|
+
<Route path="/" element={<EditPage />} />
|
|
82
|
+
</Routes>,
|
|
83
|
+
{
|
|
84
|
+
wrapper: TestWrapper({
|
|
85
|
+
options: refineOptions,
|
|
86
|
+
i18nProvider: {
|
|
87
|
+
changeLocale: () => Promise.resolve(),
|
|
88
|
+
getLocale: () => "en",
|
|
89
|
+
translate: (key: string) => {
|
|
90
|
+
if (key === "form.error.content") {
|
|
91
|
+
return "Translated content error";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return key;
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
dataProvider: {
|
|
98
|
+
...MockJSONServer,
|
|
99
|
+
update: async () => {
|
|
100
|
+
const error: HttpError = {
|
|
101
|
+
message: "An error occurred while updating the record.",
|
|
102
|
+
statusCode: 400,
|
|
103
|
+
errors: {
|
|
104
|
+
title: ["Title is required"],
|
|
105
|
+
"category.id": ["Category is required"],
|
|
106
|
+
slug: true,
|
|
107
|
+
content: {
|
|
108
|
+
key: "form.error.content",
|
|
109
|
+
message: "Content is required",
|
|
104
110
|
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return Promise.reject(error);
|
|
124
|
-
},
|
|
125
|
-
create: async () => {
|
|
126
|
-
const error: HttpError = {
|
|
127
|
-
message:
|
|
128
|
-
"An error occurred while creating the record.",
|
|
129
|
-
statusCode: 400,
|
|
130
|
-
slug: true,
|
|
131
|
-
errors: {
|
|
132
|
-
title: ["Title is required"],
|
|
133
|
-
"category.id": ["Category is required"],
|
|
134
|
-
slug: true,
|
|
135
|
-
content: {
|
|
136
|
-
key: "form.error.content",
|
|
137
|
-
message: "Content is required",
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
return Promise.reject(error);
|
|
143
|
-
},
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return Promise.reject(error);
|
|
115
|
+
},
|
|
116
|
+
create: async () => {
|
|
117
|
+
const error: HttpError = {
|
|
118
|
+
message: "An error occurred while creating the record.",
|
|
119
|
+
statusCode: 400,
|
|
120
|
+
slug: true,
|
|
121
|
+
errors: {
|
|
122
|
+
title: ["Title is required"],
|
|
123
|
+
"category.id": ["Category is required"],
|
|
124
|
+
slug: true,
|
|
125
|
+
content: {
|
|
126
|
+
key: "form.error.content",
|
|
127
|
+
message: "Content is required",
|
|
144
128
|
},
|
|
145
|
-
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return Promise.reject(error);
|
|
133
|
+
},
|
|
146
134
|
},
|
|
147
|
-
|
|
135
|
+
}),
|
|
136
|
+
},
|
|
137
|
+
);
|
|
148
138
|
};
|
|
149
139
|
|
|
150
140
|
describe("useForm hook", () => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
141
|
+
it.each(["edit", "create"] as const)(
|
|
142
|
+
"should set %s-form errors from data provider",
|
|
143
|
+
async (action) => {
|
|
144
|
+
const onMutationError = jest.fn();
|
|
145
|
+
|
|
146
|
+
const { getByText, getByTestId } = renderForm({
|
|
147
|
+
refineCoreProps: {
|
|
148
|
+
onMutationError,
|
|
149
|
+
action: action,
|
|
150
|
+
id: action === "edit" ? "1" : undefined,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
expect(document.body).not.toHaveTextContent("loading");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await act(() => {
|
|
159
|
+
getByTestId("refine-save-button").click();
|
|
160
|
+
return Promise.resolve();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(document.body).not.toHaveTextContent("loading");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(onMutationError).toBeCalledTimes(1);
|
|
168
|
+
|
|
169
|
+
expect(getByText("Title is required")).toBeInTheDocument();
|
|
170
|
+
expect(getByText("Category is required")).toBeInTheDocument();
|
|
171
|
+
expect(getByText("Translated content error")).toBeInTheDocument();
|
|
172
|
+
expect(getByText("Field is not valid.")).toBeInTheDocument();
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
it.each([
|
|
177
|
+
{
|
|
178
|
+
action: "edit",
|
|
179
|
+
disableFromRefineOption: false,
|
|
180
|
+
disableFromHook: true,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
action: "edit",
|
|
184
|
+
disableFromRefineOption: true,
|
|
185
|
+
disableFromHook: false,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
action: "create",
|
|
189
|
+
disableFromRefineOption: false,
|
|
190
|
+
disableFromHook: true,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
action: "create",
|
|
194
|
+
disableFromRefineOption: true,
|
|
195
|
+
disableFromHook: false,
|
|
196
|
+
},
|
|
197
|
+
] as const)("should disable server-side validation", async (testCase) => {
|
|
198
|
+
const onMutationErrorMock = jest.fn();
|
|
199
|
+
|
|
200
|
+
const { getByTestId, queryByText } = renderForm({
|
|
201
|
+
refineOptions: {
|
|
202
|
+
disableServerSideValidation: testCase.disableFromRefineOption,
|
|
203
|
+
},
|
|
204
|
+
useFormProps: {
|
|
205
|
+
disableServerSideValidation: testCase.disableFromHook,
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
refineCoreProps: {
|
|
209
|
+
action: testCase.action,
|
|
210
|
+
onMutationError: onMutationErrorMock,
|
|
211
|
+
id: testCase.action === "edit" ? "1" : undefined,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
172
214
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
215
|
+
await waitFor(() => {
|
|
216
|
+
expect(document.body).not.toHaveTextContent("loading");
|
|
217
|
+
});
|
|
176
218
|
|
|
177
|
-
|
|
219
|
+
await act(() => {
|
|
220
|
+
getByTestId("refine-save-button").click();
|
|
221
|
+
return Promise.resolve();
|
|
222
|
+
});
|
|
178
223
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
);
|
|
224
|
+
await waitFor(() => {
|
|
225
|
+
expect(document.body).not.toHaveTextContent("loading");
|
|
226
|
+
expect(onMutationErrorMock).toBeCalledTimes(1);
|
|
227
|
+
});
|
|
185
228
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
action: "edit",
|
|
194
|
-
disableFromRefineOption: true,
|
|
195
|
-
disableFromHook: false,
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
action: "create",
|
|
199
|
-
disableFromRefineOption: false,
|
|
200
|
-
disableFromHook: true,
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
action: "create",
|
|
204
|
-
disableFromRefineOption: true,
|
|
205
|
-
disableFromHook: false,
|
|
206
|
-
},
|
|
207
|
-
] as const)("should disable server-side validation", async (testCase) => {
|
|
208
|
-
const onMutationErrorMock = jest.fn();
|
|
209
|
-
|
|
210
|
-
const { getByTestId, queryByText } = renderForm({
|
|
211
|
-
refineOptions: {
|
|
212
|
-
disableServerSideValidation: testCase.disableFromRefineOption,
|
|
213
|
-
},
|
|
214
|
-
useFormProps: {
|
|
215
|
-
disableServerSideValidation: testCase.disableFromHook,
|
|
216
|
-
},
|
|
217
|
-
|
|
218
|
-
refineCoreProps: {
|
|
219
|
-
action: testCase.action,
|
|
220
|
-
onMutationError: onMutationErrorMock,
|
|
221
|
-
id: testCase.action === "edit" ? "1" : undefined,
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
await waitFor(() => {
|
|
226
|
-
expect(document.body).not.toHaveTextContent("loading");
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
await act(() => {
|
|
230
|
-
getByTestId("refine-save-button").click();
|
|
231
|
-
return Promise.resolve();
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
await waitFor(() => {
|
|
235
|
-
expect(document.body).not.toHaveTextContent("loading");
|
|
236
|
-
expect(onMutationErrorMock).toBeCalledTimes(1);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
await waitFor(() => {
|
|
240
|
-
expect(queryByText("Title is required")).not.toBeInTheDocument();
|
|
241
|
-
expect(queryByText("Category is required")).not.toBeInTheDocument();
|
|
242
|
-
expect(
|
|
243
|
-
queryByText("Translated content error"),
|
|
244
|
-
).not.toBeInTheDocument();
|
|
245
|
-
expect(queryByText("Field is not valid.")).not.toBeInTheDocument();
|
|
246
|
-
});
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
expect(queryByText("Title is required")).not.toBeInTheDocument();
|
|
231
|
+
expect(queryByText("Category is required")).not.toBeInTheDocument();
|
|
232
|
+
expect(queryByText("Translated content error")).not.toBeInTheDocument();
|
|
233
|
+
expect(queryByText("Field is not valid.")).not.toBeInTheDocument();
|
|
247
234
|
});
|
|
235
|
+
});
|
|
248
236
|
});
|