@tsed/tailwind-formio 3.0.0-alpha.2 → 3.0.0-alpha.4

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.
@@ -0,0 +1,466 @@
1
+ import { expect, fn, userEvent, waitFor, within } from "@storybook/test";
2
+ import { InputText } from "@tsed/react-formio";
3
+ import React, { useEffect, useState } from "react";
4
+
5
+ import form from "./__fixtures__/form.fixtures.js";
6
+ import formFirstname from "./__fixtures__/form-firstname.fixture.json";
7
+ import { WrapperForm } from "./__fixtures__/WrapperForm.jsx";
8
+
9
+ async function delay(number) {
10
+ return new Promise((resolve) => {
11
+ setTimeout(resolve, number);
12
+ });
13
+ }
14
+
15
+ /**
16
+ * The form component is the primary component of the system. It is what takes the form definition (json) and renders the
17
+ * form into html. There are multiple ways to send the form to the Form component. The two main ways are to pass the `src`
18
+ * prop with an url to the form definition, usually a form.io server. The other is to pass the `form` prop with the json
19
+ * definition and optionally a `url` prop with the location of the form.
20
+ */
21
+ export default {
22
+ title: "Formiojs/Form",
23
+ component: WrapperForm,
24
+ argTypes: {
25
+ form: {
26
+ description:
27
+ "Instead of loading a form from the `src` url, you can preload the form definition and pass it in with the `form` prop. You should also set `url` if you are using any advanced components like file upload or oauth.",
28
+ control: {
29
+ type: "object"
30
+ }
31
+ },
32
+ src: {
33
+ description:
34
+ "The src of the form definition. This is commonly from a form.io server. When using src, the form will automatically submit the data to that url as well.",
35
+ control: {
36
+ type: "text"
37
+ }
38
+ },
39
+ submission: {
40
+ description:
41
+ "Submission data to fill the form. You can either load a previous submission or create a submission with some pre-filled data. If you do not provide a submissions the form will initialize an empty submission using default values from the form.",
42
+ control: {
43
+ type: "object"
44
+ }
45
+ },
46
+ options: {
47
+ description:
48
+ "An options object that can pass options to the formio.js Form that is rendered. You can set options such as `readOnly`, `noAlerts` or `hide`. There are [many options to be found in the formio.js library](https://github.com/formio/formio.js/wiki/Form-Renderer#options).",
49
+ control: {
50
+ type: "object"
51
+ }
52
+ },
53
+ onFormReady: {
54
+ description:
55
+ "A callback function that gets called when the form has rendered. It is useful for accessing the underlying @formio/js Webform instance.",
56
+ action: "onFormReady"
57
+ },
58
+ onPrevPage: {
59
+ description: 'A callback function for Wizard forms that gets called when the "Previous" button is pressed.',
60
+ action: "onPrevPage"
61
+ },
62
+ onNextPage: {
63
+ description: 'A callback function for Wizard forms that gets called when the "Next" button is pressed.',
64
+ action: "onNextPage"
65
+ },
66
+ onCancelSubmit: {
67
+ description: "A callback function that gets called when the submission has been canceled.",
68
+ action: "onCancelSubmit"
69
+ },
70
+ onCancelComponent: {
71
+ description: "A callback function that gets called when a component has been canceled.",
72
+ action: "onCancelComponent"
73
+ },
74
+ // FIXME adding this event causes the story to fail
75
+ // onChange: {
76
+ // description: "A callback function that gets called when a value in the submission has changed.",
77
+ // action: "onChange"
78
+ // },
79
+ onCustomEvent: {
80
+ description: 'A callback function that is triggered from a button component configured with "Event" type.',
81
+ action: "onCustomEvent"
82
+ },
83
+ // FIXME adding this event causes the story to fail
84
+ // onComponentChange: {
85
+ // description: "A callback function that gets called when a specific component changes.",
86
+ // action: "onComponentChange"
87
+ // },
88
+ onSubmit: {
89
+ description:
90
+ "A callback function that gets called when the submission has started. If src is not a Form.io server URL, this will be the final submit event.",
91
+ action: "onSubmit"
92
+ },
93
+ onSubmitDone: {
94
+ description:
95
+ "A callback function that gets called when the submission has successfully been made to the server. This will only fire if src is set to a Form.io server URL.",
96
+ action: "onSubmitDone"
97
+ },
98
+ onSubmitError: {
99
+ description: "A callback function that gets called when an error occurs during submission (e.g. a validation error).",
100
+ action: "onSubmitError"
101
+ },
102
+ onFormLoad: {
103
+ description: "A callback function that gets called when the form is finished loading.",
104
+ action: "onFormLoad"
105
+ },
106
+ onError: {
107
+ description: "A callback function that gets called when an error occurs during submission (e.g. a validation error).",
108
+ action: "onError"
109
+ },
110
+ onRender: {
111
+ description:
112
+ "A callback function that gets called when the form is finished rendering. param will depend on the form and display type.",
113
+ action: "onRender"
114
+ },
115
+ onAttach: {
116
+ description: "Event",
117
+ action: "onAttach"
118
+ },
119
+ onBuild: {
120
+ description: "Event",
121
+ action: "onBuild"
122
+ },
123
+ onInitialized: {
124
+ description: "Event",
125
+ action: "onInitialized"
126
+ },
127
+ onLanguageChanged: {
128
+ description: "Event",
129
+ action: "onLanguageChanged"
130
+ },
131
+ onBeforeSetSubmission: {
132
+ description: "Event",
133
+ action: "onBeforeSetSubmission"
134
+ },
135
+ onSaveDraftBegin: {
136
+ description: "Event",
137
+ action: "onSaveDraftBegin"
138
+ },
139
+ onSaveDraft: {
140
+ description: "Event",
141
+ action: "onSaveDraft"
142
+ },
143
+ onRestoreDraft: {
144
+ description: "Event",
145
+ action: "onRestoreDraft"
146
+ },
147
+ onSubmissionDeleted: {
148
+ description: "Event",
149
+ action: "onSubmissionDeleted"
150
+ },
151
+ onRequestDone: {
152
+ description: "Event",
153
+ action: "onRequestDone"
154
+ },
155
+ otherEvents: {
156
+ description:
157
+ 'A "catch-all" prop for subscribing to other events (for a complete list, see [our documentation](https://help.form.io/developers/form-development/form-renderer#form-events)).',
158
+ control: {
159
+ type: "object"
160
+ }
161
+ }
162
+ },
163
+ tags: ["autodocs"]
164
+ };
165
+ /**
166
+ * Form with `form` property.
167
+ */
168
+ export const BasicUsageUsingForm = {
169
+ args: {
170
+ form,
171
+ onFormReady: fn(),
172
+ options: {
173
+ template: "tailwind",
174
+ iconset: "bx"
175
+ }
176
+ },
177
+ async play({ canvasElement, args }) {
178
+ const canvas = within(canvasElement);
179
+
180
+ await waitFor(() => {
181
+ expect(canvas.getByTestId("formio-container")).toBeInTheDocument();
182
+ });
183
+
184
+ await waitFor(() => {
185
+ expect(canvas.getByTestId("formio-container")).toHaveClass("formio-form-ready");
186
+ });
187
+
188
+ expect(args.onFormReady).toHaveBeenCalled();
189
+
190
+ expect(canvas.getByRole("textbox", { name: "Text Field" })).toBeInTheDocument();
191
+ }
192
+ };
193
+ /**
194
+ * Form with `src` property.
195
+ */
196
+ export const BasicUsageUsingSrc = {
197
+ args: {
198
+ src: "https://example.form.io/example",
199
+ options: {
200
+ template: "tailwind",
201
+ iconset: "bx"
202
+ }
203
+ },
204
+ async play({ canvasElement }) {
205
+ const canvas = within(canvasElement);
206
+
207
+ await waitFor(() => {
208
+ expect(canvas.getByTestId("formio-container")).toBeInTheDocument();
209
+ });
210
+
211
+ await waitFor(() => {
212
+ expect(canvas.getByTestId("formio-container")).toHaveClass("formio-form-ready");
213
+ });
214
+
215
+ expect(canvas.getByRole("textbox", { name: "First Name" })).toBeInTheDocument();
216
+ }
217
+ };
218
+ /**
219
+ * Form with `submission` property.
220
+ */
221
+ export const WithSubmissionData = {
222
+ args: {
223
+ form: formFirstname,
224
+ options: {
225
+ template: "tailwind",
226
+ iconset: "bx"
227
+ },
228
+ submission: {
229
+ data: {
230
+ firstName: "John",
231
+ lastName: "Doe"
232
+ }
233
+ }
234
+ },
235
+ async play({ canvasElement }) {
236
+ const canvas = within(canvasElement);
237
+
238
+ await waitFor(() => {
239
+ expect(canvas.getByTestId("formio-container")).toBeInTheDocument();
240
+ });
241
+
242
+ await waitFor(() => {
243
+ expect(canvas.getByTestId("formio-container")).toHaveClass("formio-form-ready");
244
+ });
245
+
246
+ const firstnameInput = canvas.getByRole("textbox", { name: "First name" });
247
+ const lastNameInput = canvas.getByRole("textbox", { name: "Last name" });
248
+
249
+ expect(firstnameInput).toHaveValue("John");
250
+ expect(lastNameInput).toHaveValue("Doe");
251
+ }
252
+ };
253
+ /**
254
+ * Form with `onSubmit` property.
255
+ */
256
+ export const WithOnSubmit = {
257
+ render(args) {
258
+ // eslint-disable-next-line react-hooks/rules-of-hooks
259
+ const [data, setData] = useState(() => args.submission.data);
260
+
261
+ // eslint-disable-next-line react-hooks/rules-of-hooks
262
+ useEffect(() => {
263
+ setData(args.submission.data);
264
+ }, [args.submission]);
265
+
266
+ return (
267
+ <>
268
+ <WrapperForm
269
+ {...args}
270
+ submission={{
271
+ data: data
272
+ }}
273
+ onSubmit={(submission) => {
274
+ setTimeout(() => {
275
+ setData(submission.data);
276
+ }, 1000);
277
+ }}
278
+ />
279
+ <div className='flex flex-col space-y-5 pt-5'>
280
+ <strong>Preview:</strong>
281
+ <pre className='bg-gray-200 p-5 rounded-sm text-sm'>
282
+ <code>{JSON.stringify(data, null, 2)}</code>
283
+ </pre>
284
+
285
+ <InputText
286
+ name={"raw-firstName"}
287
+ label={"Raw First name"}
288
+ value={data.firstName}
289
+ onChange={(_, value) => setData({ ...data, firstName: value })}
290
+ />
291
+ </div>
292
+ </>
293
+ );
294
+ },
295
+ args: {
296
+ form: formFirstname,
297
+ options: {
298
+ template: "tailwind",
299
+ iconset: "bx"
300
+ },
301
+ submission: {
302
+ data: {
303
+ firstName: "John",
304
+ lastName: "Doe"
305
+ }
306
+ }
307
+ },
308
+ async play({ canvasElement }) {
309
+ const canvas = within(canvasElement);
310
+
311
+ await waitFor(() => {
312
+ expect(canvas.getByTestId("formio-container")).toBeInTheDocument();
313
+ });
314
+
315
+ await waitFor(() => {
316
+ expect(canvas.getByTestId("formio-container")).toHaveClass("formio-form-ready");
317
+ });
318
+
319
+ let firstnameInput = canvas.getByRole("textbox", { name: "First name" });
320
+ let lastNameInput = canvas.getByRole("textbox", { name: "Last name" });
321
+
322
+ expect(firstnameInput).toHaveValue("John");
323
+ expect(lastNameInput).toHaveValue("Doe");
324
+
325
+ userEvent.clear(firstnameInput);
326
+ userEvent.type(firstnameInput, "Jane", { delay: 100 });
327
+
328
+ await waitFor(() => {
329
+ expect(firstnameInput).toHaveValue("Jane");
330
+ });
331
+
332
+ userEvent.clear(lastNameInput);
333
+ userEvent.type(lastNameInput, "Smith", { delay: 100 });
334
+
335
+ await waitFor(() => {
336
+ expect(lastNameInput).toHaveValue("Smith");
337
+ });
338
+
339
+ let submitButton = canvas.getByRole("button", { name: "Submit" });
340
+
341
+ userEvent.click(submitButton);
342
+
343
+ await delay(1200);
344
+
345
+ firstnameInput = canvas.getByRole("textbox", { name: "First name" });
346
+ lastNameInput = canvas.getByRole("textbox", { name: "Last name" });
347
+
348
+ userEvent.clear(lastNameInput);
349
+ userEvent.type(lastNameInput, "Endo", { delay: 100 });
350
+
351
+ await delay(1100);
352
+
353
+ await waitFor(() => {
354
+ expect(lastNameInput).toHaveValue("Endo");
355
+ });
356
+
357
+ submitButton = canvas.getByRole("button", { name: "Submit" });
358
+
359
+ userEvent.click(submitButton);
360
+
361
+ await delay(1200);
362
+
363
+ const rawFirstNameInput = canvas.getByRole("textbox", { name: "Raw First name" });
364
+
365
+ await waitFor(() => {
366
+ expect(rawFirstNameInput).toHaveValue("Jane");
367
+ });
368
+
369
+ userEvent.clear(rawFirstNameInput);
370
+
371
+ await delay(100);
372
+
373
+ userEvent.type(rawFirstNameInput, "Romeo", { delay: 100 });
374
+
375
+ await waitFor(() => {
376
+ expect(rawFirstNameInput).toHaveValue("Romeo");
377
+ });
378
+
379
+ firstnameInput = canvas.getByRole("textbox", { name: "First name" });
380
+
381
+ await waitFor(() => {
382
+ expect(firstnameInput).toHaveValue("Romeo");
383
+ });
384
+ }
385
+ };
386
+ /**
387
+ * Form with custom validation hook
388
+ */
389
+ export const CustomValidation = {
390
+ parameters: {
391
+ mockData: [
392
+ {
393
+ url: "https://test.dev/todos/1",
394
+ method: "GET",
395
+ status: 500,
396
+ response: {
397
+ message: "My custom message about this field",
398
+ type: "custom",
399
+ path: ["firstName"],
400
+ level: "error"
401
+ },
402
+ delay: 800
403
+ }
404
+ ]
405
+ },
406
+ args: {
407
+ form: formFirstname,
408
+ options: {
409
+ hooks: {
410
+ async customValidation(submission, callback) {
411
+ const response = await fetch("https://test.dev/todos/1", {
412
+ headers: {
413
+ Accept: "application/json",
414
+ "Content-Type": "application/json"
415
+ },
416
+ method: "GET"
417
+ });
418
+
419
+ const responseData = await response.json();
420
+
421
+ if (response.ok) {
422
+ callback(null);
423
+ } else {
424
+ callback(responseData);
425
+ }
426
+ }
427
+ }
428
+ }
429
+ },
430
+ play: async ({ canvasElement }) => {
431
+ const canvas = within(canvasElement);
432
+
433
+ await waitFor(() => {
434
+ expect(canvas.getByTestId("formio-container")).toBeInTheDocument();
435
+ });
436
+
437
+ await waitFor(() => {
438
+ expect(canvas.getByTestId("formio-container")).toHaveClass("formio-form-ready");
439
+ });
440
+
441
+ let firstnameInput = canvas.getByRole("textbox", { name: "First name" });
442
+ let lastNameInput = canvas.getByRole("textbox", { name: "Last name" });
443
+
444
+ userEvent.clear(firstnameInput);
445
+ userEvent.type(firstnameInput, "Jane", { delay: 100 });
446
+
447
+ await waitFor(() => {
448
+ expect(firstnameInput).toHaveValue("Jane");
449
+ });
450
+
451
+ userEvent.clear(lastNameInput);
452
+ userEvent.type(lastNameInput, "Smith", { delay: 100 });
453
+
454
+ await waitFor(() => {
455
+ expect(lastNameInput).toHaveValue("Smith");
456
+ });
457
+
458
+ let submitButton = canvas.getByRole("button", { name: "Submit" });
459
+
460
+ userEvent.click(submitButton);
461
+
462
+ await waitFor(async () => {
463
+ expect(canvas.getByText("Please fix the following errors before submitting.")).toBeInTheDocument();
464
+ });
465
+ }
466
+ };