@homebound/form-state 2.18.1 → 2.20.0
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/FormStateApp.d.ts +2 -3
- package/dist/FormStateApp.js +8 -47
- package/dist/FormStateApp.test.js +14 -14
- package/dist/config.d.ts +6 -6
- package/dist/fields/fragmentField.js +3 -3
- package/dist/fields/listField.js +12 -12
- package/dist/fields/objectField.d.ts +4 -4
- package/dist/fields/objectField.js +10 -10
- package/dist/fields/valueField.d.ts +13 -0
- package/dist/fields/valueField.js +49 -14
- package/dist/formState.stories.d.ts +2 -4
- package/dist/formState.stories.js +1 -1
- package/dist/formState.test.js +171 -77
- package/dist/formStateDomain.js +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +0 -11
- package/dist/proxies.d.ts +5 -0
- package/dist/proxies.js +21 -0
- package/dist/rules.d.ts +1 -1
- package/dist/rules.js +1 -1
- package/dist/setupTests.js +2 -2
- package/dist/useFormState.d.ts +4 -4
- package/dist/useFormState.js +13 -17
- package/dist/useFormState.test.js +141 -198
- package/dist/useFormStates.d.ts +3 -3
- package/dist/useFormStates.js +7 -11
- package/dist/useFormStates.test.js +56 -89
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +8 -8
- package/dist/utils.test.js +49 -49
- package/package.json +44 -39
- package/dist/AutoSaveStatus/AutoSaveStatusProvider.d.ts +0 -24
- package/dist/AutoSaveStatus/AutoSaveStatusProvider.js +0 -91
- package/dist/AutoSaveStatus/index.d.ts +0 -2
- package/dist/AutoSaveStatus/index.js +0 -9
- package/dist/AutoSaveStatus/useAutoSaveStatus.d.ts +0 -1
- package/dist/AutoSaveStatus/useAutoSaveStatus.js +0 -9
- package/dist/AutoSaveStatus/useAutoSaveStatus.test.d.ts +0 -1
- package/dist/AutoSaveStatus/useAutoSaveStatus.test.js +0 -152
|
@@ -3,14 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
4
|
const rtl_utils_1 = require("@homebound/rtl-utils");
|
|
5
5
|
const react_1 = require("@testing-library/react");
|
|
6
|
-
const react_hooks_1 = require("@testing-library/react-hooks");
|
|
7
6
|
const mobx_1 = require("mobx");
|
|
8
7
|
const mobx_react_1 = require("mobx-react");
|
|
9
8
|
const react_2 = require("react");
|
|
10
9
|
const FormStateApp_1 = require("./FormStateApp");
|
|
11
10
|
const rules_1 = require("./rules");
|
|
12
|
-
const AutoSaveStatus_1 = require("./AutoSaveStatus/index");
|
|
13
|
-
const AutoSaveStatusProvider_1 = require("./AutoSaveStatus/AutoSaveStatusProvider");
|
|
14
11
|
const useFormState_1 = require("./useFormState");
|
|
15
12
|
describe("useFormState", () => {
|
|
16
13
|
it("calls init.map if init.input is defined", async () => {
|
|
@@ -19,32 +16,31 @@ describe("useFormState", () => {
|
|
|
19
16
|
const config = { firstName: { type: "value" } };
|
|
20
17
|
// And we have query data that may or may not be defined
|
|
21
18
|
const data = { firstName: "bob" };
|
|
22
|
-
const form = useFormState_1.useFormState({
|
|
19
|
+
const form = (0, useFormState_1.useFormState)({
|
|
23
20
|
config,
|
|
24
21
|
// Then the lambda is passed the "de-undefined" data, i.e. `d.firstName` is not a compile error
|
|
25
22
|
init: { input: data, map: (d) => ({ firstName: d.firstName }) },
|
|
26
23
|
});
|
|
27
|
-
return jsx_runtime_1.jsx("div", { children: form.firstName.value }
|
|
24
|
+
return (0, jsx_runtime_1.jsx)("div", { children: form.firstName.value });
|
|
28
25
|
}
|
|
29
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
26
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
30
27
|
expect(r.baseElement).toHaveTextContent("bob");
|
|
31
28
|
});
|
|
32
29
|
it("memoizes on init.input being an array", async () => {
|
|
33
30
|
const config = { firstName: { type: "value" } };
|
|
34
31
|
function TestComponent() {
|
|
35
|
-
const [, setTick] = react_2.useState(0);
|
|
36
|
-
const form = useFormState_1.useFormState({
|
|
32
|
+
const [, setTick] = (0, react_2.useState)(0);
|
|
33
|
+
const form = (0, useFormState_1.useFormState)({
|
|
37
34
|
config,
|
|
38
35
|
init: { input: ["a", "b"], map: ([a, b]) => ({ firstName: a + b }) },
|
|
39
36
|
});
|
|
40
37
|
const onClick = () => [form.firstName.set("fred"), setTick(1)];
|
|
41
|
-
return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("button", { "data-testid": "change", onClick: onClick },
|
|
42
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: form.firstName.value }), void 0)] }, void 0));
|
|
38
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("button", { "data-testid": "change", onClick: onClick }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value })] }));
|
|
43
39
|
}
|
|
44
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
45
|
-
expect(r.firstName
|
|
46
|
-
rtl_utils_1.click(r.change);
|
|
47
|
-
expect(r.firstName
|
|
40
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
41
|
+
expect(r.firstName).toHaveTextContent("ab");
|
|
42
|
+
(0, rtl_utils_1.click)(r.change);
|
|
43
|
+
expect(r.firstName).toHaveTextContent("fred");
|
|
48
44
|
});
|
|
49
45
|
it("uses default if init.input is undefined", async () => {
|
|
50
46
|
// Given a component
|
|
@@ -52,13 +48,13 @@ describe("useFormState", () => {
|
|
|
52
48
|
const config = { firstName: { type: "value" } };
|
|
53
49
|
// And we have query data that may or may not be defined (but is actually undefined)
|
|
54
50
|
const data = Math.random() >= 0 ? undefined : { firstName: "bob" };
|
|
55
|
-
const form = useFormState_1.useFormState({
|
|
51
|
+
const form = (0, useFormState_1.useFormState)({
|
|
56
52
|
config,
|
|
57
53
|
init: { input: data, map: (d) => ({ firstName: d.firstName }) },
|
|
58
54
|
});
|
|
59
|
-
return jsx_runtime_1.jsx("div", { children: form.firstName.value }
|
|
55
|
+
return (0, jsx_runtime_1.jsx)("div", { children: form.firstName.value });
|
|
60
56
|
}
|
|
61
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
57
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
62
58
|
// Then we init.map wasn't called, and we used {} instead
|
|
63
59
|
expect(r.baseElement.textContent).toEqual("");
|
|
64
60
|
});
|
|
@@ -71,7 +67,7 @@ describe("useFormState", () => {
|
|
|
71
67
|
};
|
|
72
68
|
// And we have query data that may or may not be defined (but is actually undefined)
|
|
73
69
|
const data = Math.random() >= 0 ? undefined : { firstName: "bob" };
|
|
74
|
-
const form = useFormState_1.useFormState({
|
|
70
|
+
const form = (0, useFormState_1.useFormState)({
|
|
75
71
|
config,
|
|
76
72
|
// And we pass `ifUndefined`
|
|
77
73
|
init: {
|
|
@@ -80,10 +76,9 @@ describe("useFormState", () => {
|
|
|
80
76
|
ifUndefined: { firstName: "default" },
|
|
81
77
|
},
|
|
82
78
|
});
|
|
83
|
-
return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div",
|
|
84
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "changedValue" }, { children: JSON.stringify(form.changedValue) }), void 0)] }, void 0));
|
|
79
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "changedValue", children: JSON.stringify(form.changedValue) })] }));
|
|
85
80
|
}
|
|
86
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
81
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
87
82
|
// Then we use the ifUndefined value
|
|
88
83
|
expect(r.firstName.textContent).toEqual("default");
|
|
89
84
|
expect(r.changedValue.textContent).toEqual(JSON.stringify({ firstName: "default" }));
|
|
@@ -91,33 +86,32 @@ describe("useFormState", () => {
|
|
|
91
86
|
it("uses init if set as a value", async () => {
|
|
92
87
|
const config = { firstName: { type: "value" } };
|
|
93
88
|
function TestComponent() {
|
|
94
|
-
const [, setTick] = react_2.useState(0);
|
|
95
|
-
const form = useFormState_1.useFormState({
|
|
89
|
+
const [, setTick] = (0, react_2.useState)(0);
|
|
90
|
+
const form = (0, useFormState_1.useFormState)({
|
|
96
91
|
config,
|
|
97
92
|
// That's using a raw init value
|
|
98
93
|
init: { firstName: "bob" },
|
|
99
94
|
});
|
|
100
|
-
return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("button", { "data-testid": "change", onClick: () => {
|
|
95
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("button", { "data-testid": "change", onClick: () => {
|
|
101
96
|
// When that value changes
|
|
102
97
|
form.firstName.set("fred");
|
|
103
98
|
// And also we re-render the component
|
|
104
99
|
setTick(1);
|
|
105
|
-
} },
|
|
106
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "firstName" }, { children: form.firstName.value }), void 0)] }, void 0));
|
|
100
|
+
} }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value })] }));
|
|
107
101
|
}
|
|
108
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
109
|
-
expect(r.firstName
|
|
110
|
-
rtl_utils_1.click(r.change);
|
|
102
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
103
|
+
expect(r.firstName).toHaveTextContent("bob");
|
|
104
|
+
(0, rtl_utils_1.click)(r.change);
|
|
111
105
|
// Then the change didn't get dropped due to init being unstable
|
|
112
|
-
expect(r.firstName
|
|
106
|
+
expect(r.firstName).toHaveTextContent("fred");
|
|
113
107
|
});
|
|
114
108
|
it("doesn't required an init value", async () => {
|
|
115
109
|
function TestComponent() {
|
|
116
110
|
const config = { firstName: { type: "value" } };
|
|
117
|
-
const form = useFormState_1.useFormState({ config });
|
|
118
|
-
return jsx_runtime_1.jsx("div", { children: form.firstName.value }
|
|
111
|
+
const form = (0, useFormState_1.useFormState)({ config });
|
|
112
|
+
return (0, jsx_runtime_1.jsx)("div", { children: form.firstName.value });
|
|
119
113
|
}
|
|
120
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
114
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
121
115
|
expect(r.baseElement.textContent).toEqual("");
|
|
122
116
|
});
|
|
123
117
|
it("keeps local changed values when a query refreshes", async () => {
|
|
@@ -159,63 +153,53 @@ describe("useFormState", () => {
|
|
|
159
153
|
],
|
|
160
154
|
};
|
|
161
155
|
// And we start out with data1
|
|
162
|
-
const [data, setData] = react_2.useState(data1);
|
|
163
|
-
const form = useFormState_1.useFormState({ config, init: { input: data, map: (d) => d } });
|
|
156
|
+
const [data, setData] = (0, react_2.useState)(data1);
|
|
157
|
+
const form = (0, useFormState_1.useFormState)({ config, init: { input: data, map: (d) => d } });
|
|
164
158
|
function makeLocalChanges() {
|
|
165
159
|
form.firstName.value = "local";
|
|
166
160
|
form.address.street.value = "local";
|
|
167
161
|
form.books.rows[0].title.value = "local";
|
|
168
162
|
}
|
|
169
|
-
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div",
|
|
170
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "lastName" }, { children: form.lastName.value }), void 0),
|
|
171
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "street" }, { children: form.address.street.value }), void 0),
|
|
172
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "city" }, { children: form.address.city.value }), void 0),
|
|
173
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "title1" }, { children: form.books.rows[0].title.value }), void 0),
|
|
174
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "title2" }, { children: form.books.rows[1].title.value }), void 0),
|
|
175
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "booksLength" }, { children: form.books.rows.length }), void 0),
|
|
176
|
-
jsx_runtime_1.jsx("button", { "data-testid": "makeLocalChanges", onClick: makeLocalChanges }, void 0),
|
|
177
|
-
jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) }, void 0),
|
|
178
|
-
jsx_runtime_1.jsx("button", { "data-testid": "saveData", onClick: () => setData(data3) }, void 0),
|
|
179
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "changedValue" }, { children: JSON.stringify(form.changedValue) }), void 0)] }, void 0)) }, void 0));
|
|
163
|
+
return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "lastName", children: form.lastName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "street", children: form.address.street.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "city", children: form.address.city.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "title1", children: form.books.rows[0].title.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "title2", children: form.books.rows[1].title.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "booksLength", children: form.books.rows.length }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "makeLocalChanges", onClick: makeLocalChanges }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "refreshData", onClick: () => setData(data2) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "saveData", onClick: () => setData(data3) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "changedValue", children: JSON.stringify(form.changedValue) })] })) }));
|
|
180
164
|
}
|
|
181
165
|
// And we start out with the initial query data
|
|
182
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
183
|
-
expect(r.firstName
|
|
184
|
-
expect(r.street
|
|
185
|
-
expect(r.title1
|
|
166
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
167
|
+
expect(r.firstName.textContent).toEqual("f1");
|
|
168
|
+
expect(r.street.textContent).toEqual("s1");
|
|
169
|
+
expect(r.title1.textContent).toEqual("a1");
|
|
186
170
|
// When we make some local changes
|
|
187
|
-
rtl_utils_1.click(r.makeLocalChanges);
|
|
171
|
+
(0, rtl_utils_1.click)(r.makeLocalChanges);
|
|
188
172
|
// Then we see them
|
|
189
|
-
expect(r.firstName
|
|
190
|
-
expect(r.street
|
|
191
|
-
expect(r.title1
|
|
192
|
-
expect(JSON.parse(r.changedValue
|
|
173
|
+
expect(r.firstName.textContent).toEqual("local");
|
|
174
|
+
expect(r.street.textContent).toEqual("local");
|
|
175
|
+
expect(r.title1.textContent).toEqual("local");
|
|
176
|
+
expect(JSON.parse(r.changedValue.textContent)).toEqual({
|
|
193
177
|
id: "a:1",
|
|
194
178
|
address: { id: "address:1", street: "local" },
|
|
195
179
|
books: [{ id: "b:1", title: "local" }, { id: "b:2" }],
|
|
196
180
|
firstName: "local",
|
|
197
181
|
});
|
|
198
182
|
// And when the new query is ran i.e. due to a cache refresh
|
|
199
|
-
rtl_utils_1.click(r.refreshData);
|
|
183
|
+
(0, rtl_utils_1.click)(r.refreshData);
|
|
200
184
|
// Then we kept our local changes
|
|
201
|
-
expect(r.firstName
|
|
202
|
-
expect(r.street
|
|
203
|
-
expect(r.title1
|
|
185
|
+
expect(r.firstName.textContent).toEqual("local");
|
|
186
|
+
expect(r.street.textContent).toEqual("local");
|
|
187
|
+
expect(r.title1.textContent).toEqual("local");
|
|
204
188
|
// But we also see the new data for fields we have not changed
|
|
205
|
-
expect(r.lastName
|
|
206
|
-
expect(r.city
|
|
207
|
-
expect(r.title2
|
|
208
|
-
expect(r.booksLength
|
|
209
|
-
expect(JSON.parse(r.changedValue
|
|
189
|
+
expect(r.lastName.textContent).toEqual("l2");
|
|
190
|
+
expect(r.city.textContent).toEqual("c2");
|
|
191
|
+
expect(r.title2.textContent).toEqual("b2");
|
|
192
|
+
expect(r.booksLength.textContent).toEqual("3");
|
|
193
|
+
expect(JSON.parse(r.changedValue.textContent)).toEqual({
|
|
210
194
|
id: "a:1",
|
|
211
195
|
address: { id: "address:1", street: "local" },
|
|
212
196
|
books: [{ id: "b:1", title: "local" }, { id: "b:2" }, { id: "b:3" }],
|
|
213
197
|
firstName: "local",
|
|
214
198
|
});
|
|
215
199
|
// And then when our mutation results come back
|
|
216
|
-
rtl_utils_1.click(r.saveData);
|
|
200
|
+
(0, rtl_utils_1.click)(r.saveData);
|
|
217
201
|
// Then changedValue doesn't show our local changes anymore
|
|
218
|
-
expect(JSON.parse(r.changedValue
|
|
202
|
+
expect(JSON.parse(r.changedValue.textContent)).toEqual({
|
|
219
203
|
id: "a:1",
|
|
220
204
|
});
|
|
221
205
|
});
|
|
@@ -235,29 +219,26 @@ describe("useFormState", () => {
|
|
|
235
219
|
books: [{ title: "a2" }],
|
|
236
220
|
};
|
|
237
221
|
// And we start out with data1
|
|
238
|
-
const [data, setData] = react_2.useState(data1);
|
|
239
|
-
const form = useFormState_1.useFormState({
|
|
222
|
+
const [data, setData] = (0, react_2.useState)(data1);
|
|
223
|
+
const form = (0, useFormState_1.useFormState)({
|
|
240
224
|
config,
|
|
241
225
|
init: { input: data, map: (d) => d },
|
|
242
226
|
// And the form is read only
|
|
243
227
|
readOnly: true,
|
|
244
228
|
});
|
|
245
|
-
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div",
|
|
246
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "street" }, { children: form.address.street.value }), void 0),
|
|
247
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "title1" }, { children: form.books.rows[0].title.value }), void 0),
|
|
248
|
-
jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) }, void 0)] }, void 0)) }, void 0));
|
|
229
|
+
return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "street", children: form.address.street.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "title1", children: form.books.rows[0].title.value }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "refreshData", onClick: () => setData(data2) })] })) }));
|
|
249
230
|
}
|
|
250
231
|
// And we start out with the initial query data
|
|
251
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
252
|
-
expect(r.firstName
|
|
253
|
-
expect(r.street
|
|
254
|
-
expect(r.title1
|
|
232
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
233
|
+
expect(r.firstName.textContent).toEqual("f1");
|
|
234
|
+
expect(r.street.textContent).toEqual("s1");
|
|
235
|
+
expect(r.title1.textContent).toEqual("a1");
|
|
255
236
|
// When the new query is ran i.e. due to a cache refresh
|
|
256
|
-
rtl_utils_1.click(r.refreshData);
|
|
237
|
+
(0, rtl_utils_1.click)(r.refreshData);
|
|
257
238
|
// Then we see the latest data
|
|
258
|
-
expect(r.firstName
|
|
259
|
-
expect(r.street
|
|
260
|
-
expect(r.title1
|
|
239
|
+
expect(r.firstName.textContent).toEqual("f2");
|
|
240
|
+
expect(r.street.textContent).toEqual("s2");
|
|
241
|
+
expect(r.title1.textContent).toEqual("a2");
|
|
261
242
|
});
|
|
262
243
|
it("useFormState can accept new data with computed fields", async () => {
|
|
263
244
|
// Given a component
|
|
@@ -276,59 +257,54 @@ describe("useFormState", () => {
|
|
|
276
257
|
const data1 = { firstName: "f1", lastName: "l1" };
|
|
277
258
|
const data2 = { firstName: "f2", lastName: "l2" };
|
|
278
259
|
// And we start out with data1
|
|
279
|
-
const [data, setData] = react_2.useState(data1);
|
|
280
|
-
const author = react_2.useMemo(() => new AuthorRow(data.firstName, data.lastName), [data]);
|
|
281
|
-
const config = react_2.useMemo(() => ({
|
|
260
|
+
const [data, setData] = (0, react_2.useState)(data1);
|
|
261
|
+
const author = (0, react_2.useMemo)(() => new AuthorRow(data.firstName, data.lastName), [data]);
|
|
262
|
+
const config = (0, react_2.useMemo)(() => ({
|
|
282
263
|
firstName: { type: "value" },
|
|
283
264
|
lastName: { type: "value" },
|
|
284
265
|
fullName: { type: "value", computed: true },
|
|
285
266
|
}), []);
|
|
286
|
-
const form = useFormState_1.useFormState({ config, init: { input: author, map: (a) => a } });
|
|
287
|
-
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div",
|
|
288
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "fullName" }, { children: form.fullName.value }), void 0),
|
|
289
|
-
jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) }, void 0)] }, void 0)) }, void 0));
|
|
267
|
+
const form = (0, useFormState_1.useFormState)({ config, init: { input: author, map: (a) => a } });
|
|
268
|
+
return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "firstName", children: form.firstName.value }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "fullName", children: form.fullName.value }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "refreshData", onClick: () => setData(data2) })] })) }));
|
|
290
269
|
}
|
|
291
270
|
// And we start out with the initial query data
|
|
292
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
293
|
-
expect(r.firstName
|
|
294
|
-
expect(r.fullName
|
|
271
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
272
|
+
expect(r.firstName.textContent).toEqual("f1");
|
|
273
|
+
expect(r.fullName.textContent).toEqual("f1 l1");
|
|
295
274
|
// When the new query is ran i.e. due to a cache refresh
|
|
296
|
-
rtl_utils_1.click(r.refreshData);
|
|
297
|
-
expect(r.firstName
|
|
298
|
-
expect(r.fullName
|
|
275
|
+
(0, rtl_utils_1.click)(r.refreshData);
|
|
276
|
+
expect(r.firstName.textContent).toEqual("f2");
|
|
277
|
+
expect(r.fullName.textContent).toEqual("f2 l2");
|
|
299
278
|
});
|
|
300
279
|
it("can trigger auto save for fields in list that were initially undefined", async () => {
|
|
301
280
|
const autoSave = jest.fn();
|
|
302
281
|
// Given a component
|
|
303
282
|
function TestComponent() {
|
|
304
283
|
// When the data is initially undefined
|
|
305
|
-
const [data, setData] = react_2.useState();
|
|
284
|
+
const [data, setData] = (0, react_2.useState)();
|
|
306
285
|
const data2 = { books: [{ title: "Title 1" }] };
|
|
307
|
-
const form = useFormState_1.useFormState({
|
|
286
|
+
const form = (0, useFormState_1.useFormState)({
|
|
308
287
|
config: authorWithBooksConfig,
|
|
309
288
|
init: { input: data, map: (d) => d, ifUndefined: { books: [] } },
|
|
310
289
|
autoSave,
|
|
311
290
|
});
|
|
312
|
-
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("button", { "data-testid": "refreshData", onClick: () => setData(data2) },
|
|
313
|
-
jsx_runtime_1.jsx("button", { "data-testid": "add", onClick: () => form.books.add({ title: "New Book" }) }, void 0),
|
|
314
|
-
jsx_runtime_1.jsx("button", { "data-testid": "blurBookOne", onClick: () => focusAndBlur(form.books.rows[0].title) }, void 0),
|
|
315
|
-
jsx_runtime_1.jsx("button", { "data-testid": "blurBookTwo", onClick: () => focusAndBlur(form.books.rows[1].title) }, void 0)] }, void 0)) }, void 0));
|
|
291
|
+
return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("button", { "data-testid": "refreshData", onClick: () => setData(data2) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "add", onClick: () => form.books.add({ title: "New Book" }) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "blurBookOne", onClick: () => focusAndBlur(form.books.rows[0].title) }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "blurBookTwo", onClick: () => focusAndBlur(form.books.rows[1].title) })] })) }));
|
|
316
292
|
}
|
|
317
293
|
// Given a formState with `onBlur` set
|
|
318
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
294
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
319
295
|
// When the data/child is now available
|
|
320
|
-
rtl_utils_1.click(r.refreshData);
|
|
296
|
+
(0, rtl_utils_1.click)(r.refreshData);
|
|
321
297
|
// And the field is blurred
|
|
322
|
-
await rtl_utils_1.clickAndWait(r.blurBookOne);
|
|
298
|
+
await (0, rtl_utils_1.clickAndWait)(r.blurBookOne);
|
|
323
299
|
// Then we don't auto-save because nothing has changed
|
|
324
300
|
expect(autoSave).toBeCalledTimes(0);
|
|
325
301
|
// And when adding a new book
|
|
326
|
-
await rtl_utils_1.clickAndWait(r.add);
|
|
302
|
+
await (0, rtl_utils_1.clickAndWait)(r.add);
|
|
327
303
|
// We autoSave the new row right away (because we don't have any validation rules
|
|
328
304
|
// that say the new row can't be empty)
|
|
329
305
|
expect(autoSave).toBeCalledTimes(1);
|
|
330
306
|
// And the new book is blurred
|
|
331
|
-
await rtl_utils_1.clickAndWait(r.blurBookTwo);
|
|
307
|
+
await (0, rtl_utils_1.clickAndWait)(r.blurBookTwo);
|
|
332
308
|
// Then we auto save again
|
|
333
309
|
expect(autoSave).toBeCalledTimes(2);
|
|
334
310
|
});
|
|
@@ -338,7 +314,7 @@ describe("useFormState", () => {
|
|
|
338
314
|
function TestComponent() {
|
|
339
315
|
const config = authorConfig;
|
|
340
316
|
const data = { firstName: "f1", lastName: "f1" };
|
|
341
|
-
const form = useFormState_1.useFormState({
|
|
317
|
+
const form = (0, useFormState_1.useFormState)({
|
|
342
318
|
config,
|
|
343
319
|
init: data,
|
|
344
320
|
// And there is reactive business logic in the `autoSave` method
|
|
@@ -347,11 +323,11 @@ describe("useFormState", () => {
|
|
|
347
323
|
autoSaves++;
|
|
348
324
|
},
|
|
349
325
|
});
|
|
350
|
-
return (jsx_runtime_1.jsx("div", { children: jsx_runtime_1.jsx("button", { "data-testid": "setFirst", onClick: () => form.firstName.set("f2") }
|
|
326
|
+
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("button", { "data-testid": "setFirst", onClick: () => form.firstName.set("f2") }) }));
|
|
351
327
|
}
|
|
352
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
328
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
353
329
|
// When we change firstName
|
|
354
|
-
await rtl_utils_1.clickAndWait(r.setFirst);
|
|
330
|
+
await (0, rtl_utils_1.clickAndWait)(r.setFirst);
|
|
355
331
|
// When autoSave didn't infinite loop
|
|
356
332
|
expect(autoSaves).toEqual(1);
|
|
357
333
|
});
|
|
@@ -361,20 +337,20 @@ describe("useFormState", () => {
|
|
|
361
337
|
function TestComponent() {
|
|
362
338
|
const config = authorConfig;
|
|
363
339
|
const data = { firstName: "f1", lastName: "f1" };
|
|
364
|
-
const form = useFormState_1.useFormState({
|
|
340
|
+
const form = (0, useFormState_1.useFormState)({
|
|
365
341
|
config,
|
|
366
342
|
init: data,
|
|
367
343
|
autoSave: (form) => autoSave(form.changedValue),
|
|
368
344
|
});
|
|
369
|
-
return (jsx_runtime_1.jsx("div", { children: jsx_runtime_1.jsx("button", { "data-testid": "set", onClick: () => {
|
|
345
|
+
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("button", { "data-testid": "set", onClick: () => {
|
|
370
346
|
// And it sets two fields in a single callback
|
|
371
347
|
form.firstName.set("f2");
|
|
372
348
|
form.lastName.set("l2");
|
|
373
|
-
} }
|
|
349
|
+
} }) }));
|
|
374
350
|
}
|
|
375
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
351
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
376
352
|
// When we change both
|
|
377
|
-
await rtl_utils_1.clickAndWait(r.set);
|
|
353
|
+
await (0, rtl_utils_1.clickAndWait)(r.set);
|
|
378
354
|
// Then we only call autoSave once
|
|
379
355
|
expect(autoSave).toBeCalledTimes(1);
|
|
380
356
|
expect(autoSave).toBeCalledWith({ firstName: "f2", lastName: "l2" });
|
|
@@ -388,8 +364,8 @@ describe("useFormState", () => {
|
|
|
388
364
|
};
|
|
389
365
|
// Given a component using `getObjectState` for lazily creating ObjectStates
|
|
390
366
|
function TestComponent() {
|
|
391
|
-
const [apiData, setApiData] = react_2.useState({ id: "a:1", firstName: "Brandon", lastName: "Dow" });
|
|
392
|
-
const state = useFormState_1.useFormState({ config, autoSave, init: { input: apiData, map: (v) => v } });
|
|
367
|
+
const [apiData, setApiData] = (0, react_2.useState)({ id: "a:1", firstName: "Brandon", lastName: "Dow" });
|
|
368
|
+
const state = (0, useFormState_1.useFormState)({ config, autoSave, init: { input: apiData, map: (v) => v } });
|
|
393
369
|
async function autoSave(form) {
|
|
394
370
|
autoSaveStub(form.changedValue);
|
|
395
371
|
const changed = form.changedValue;
|
|
@@ -397,34 +373,32 @@ describe("useFormState", () => {
|
|
|
397
373
|
await Promise.resolve(1);
|
|
398
374
|
setApiData((prevState) => ({ ...prevState, ...changed }));
|
|
399
375
|
}
|
|
400
|
-
return (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsxs("div",
|
|
401
|
-
jsx_runtime_1.jsx("button", { "data-testid": "focusSetAndSaveField", onClick: () => {
|
|
376
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { "data-testid": "name", children: [apiData.firstName, " ", apiData.lastName] }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "focusSetAndSaveField", onClick: () => {
|
|
402
377
|
state.firstName.focus();
|
|
403
378
|
state.firstName.set("Foo");
|
|
404
379
|
state.firstName.maybeAutoSave();
|
|
405
380
|
state.firstName.blur();
|
|
406
|
-
} },
|
|
407
|
-
jsx_runtime_1.jsx("button", { "data-testid": "focusSetAndSaveFieldLastName", onClick: () => {
|
|
381
|
+
} }), (0, jsx_runtime_1.jsx)("button", { "data-testid": "focusSetAndSaveFieldLastName", onClick: () => {
|
|
408
382
|
state.lastName.focus();
|
|
409
383
|
state.lastName.set("Bar");
|
|
410
384
|
state.lastName.maybeAutoSave();
|
|
411
|
-
} }
|
|
385
|
+
} })] }));
|
|
412
386
|
}
|
|
413
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
387
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
414
388
|
// And triggering the auto save behavior before awaiting the initial promise to
|
|
415
389
|
// resolve so we have pending changes.
|
|
416
|
-
rtl_utils_1.click(r.focusSetAndSaveField
|
|
390
|
+
(0, rtl_utils_1.click)(r.focusSetAndSaveField, { allowAsync: true });
|
|
417
391
|
// Let the initial autoSave be called
|
|
418
|
-
react_1.act(() => {
|
|
392
|
+
(0, react_1.act)(() => {
|
|
419
393
|
jest.runOnlyPendingTimers();
|
|
420
394
|
});
|
|
421
|
-
expect(r.name
|
|
395
|
+
expect(r.name).toHaveTextContent("Brandon Dow");
|
|
422
396
|
expect(autoSaveStub).toBeCalledTimes(1);
|
|
423
397
|
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo" });
|
|
424
398
|
// And while that is in flight, trigger another user action
|
|
425
|
-
rtl_utils_1.click(r.focusSetAndSaveFieldLastName
|
|
399
|
+
(0, rtl_utils_1.click)(r.focusSetAndSaveFieldLastName, { allowAsync: true });
|
|
426
400
|
// (Use `wait` so that our timer flushes before the Promise.resolve(1) is ran)
|
|
427
|
-
await rtl_utils_1.wait();
|
|
401
|
+
await (0, rtl_utils_1.wait)();
|
|
428
402
|
// Then expect the auto save to only have been called twice. Once with each changedValues.
|
|
429
403
|
expect(autoSaveStub).toBeCalledTimes(2);
|
|
430
404
|
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "Foo" });
|
|
@@ -439,20 +413,20 @@ describe("useFormState", () => {
|
|
|
439
413
|
};
|
|
440
414
|
// Given a component that is using autoSave
|
|
441
415
|
function TestComponent() {
|
|
442
|
-
const fs = useFormState_1.useFormState({
|
|
416
|
+
const fs = (0, useFormState_1.useFormState)({
|
|
443
417
|
config,
|
|
444
418
|
addRules(fs) {
|
|
445
419
|
// And also has calculated values
|
|
446
|
-
mobx_1.reaction(() => fs.firstName.value, (curr) => (fs.lastName.value = curr));
|
|
420
|
+
(0, mobx_1.reaction)(() => fs.firstName.value, (curr) => (fs.lastName.value = curr));
|
|
447
421
|
},
|
|
448
422
|
autoSave: (fs) => autoSaveStub(fs.changedValue),
|
|
449
423
|
init: { id: "a:1" },
|
|
450
424
|
});
|
|
451
|
-
return jsx_runtime_1.jsx(FormStateApp_1.TextField, { field: fs.firstName }
|
|
425
|
+
return (0, jsx_runtime_1.jsx)(FormStateApp_1.TextField, { field: fs.firstName });
|
|
452
426
|
}
|
|
453
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
427
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
454
428
|
// When the user sets one field
|
|
455
|
-
await rtl_utils_1.typeAndWait(r.firstName, "first");
|
|
429
|
+
await (0, rtl_utils_1.typeAndWait)(r.firstName, "first");
|
|
456
430
|
// Then we only called autoSave once
|
|
457
431
|
expect(autoSaveStub).toBeCalledTimes(1);
|
|
458
432
|
expect(autoSaveStub).toBeCalledWith({ id: "a:1", firstName: "first", lastName: "first" });
|
|
@@ -460,108 +434,77 @@ describe("useFormState", () => {
|
|
|
460
434
|
it("sets loading if opts.loading is true", async () => {
|
|
461
435
|
const config = { firstName: { type: "value" } };
|
|
462
436
|
function TestComponent({ loading }) {
|
|
463
|
-
const form = useFormState_1.useFormState({ config, loading });
|
|
464
|
-
return jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => jsx_runtime_1.jsx("div",
|
|
437
|
+
const form = (0, useFormState_1.useFormState)({ config, loading });
|
|
438
|
+
return (0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => (0, jsx_runtime_1.jsx)("div", { "data-testid": "loading", children: String(form.loading) }) });
|
|
465
439
|
}
|
|
466
440
|
// And we initially pass in `init.query.loading: true`
|
|
467
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { loading: true }
|
|
441
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { loading: true }));
|
|
468
442
|
// Then the form is marked as loading
|
|
469
|
-
expect(r.loading
|
|
443
|
+
expect(r.loading).toHaveTextContent("true");
|
|
470
444
|
// And when the query is not loading
|
|
471
|
-
await r.rerender(jsx_runtime_1.jsx(TestComponent, { loading: false }
|
|
445
|
+
await r.rerender((0, jsx_runtime_1.jsx)(TestComponent, { loading: false }));
|
|
472
446
|
// Then the form is marked as not loading
|
|
473
|
-
expect(r.loading
|
|
447
|
+
expect(r.loading).toHaveTextContent("false");
|
|
474
448
|
});
|
|
475
449
|
it("sets loading if input.data is undefined", async () => {
|
|
476
450
|
const config = { firstName: { type: "value" } };
|
|
477
451
|
function TestComponent({ data }) {
|
|
478
|
-
const form = useFormState_1.useFormState({ config, init: { input: data, map: (d) => d } });
|
|
479
|
-
return jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => jsx_runtime_1.jsx("div",
|
|
452
|
+
const form = (0, useFormState_1.useFormState)({ config, init: { input: data, map: (d) => d } });
|
|
453
|
+
return (0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => (0, jsx_runtime_1.jsx)("div", { "data-testid": "loading", children: String(form.loading) }) });
|
|
480
454
|
}
|
|
481
455
|
// And we initially pass in `init.input: undefined`
|
|
482
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { data: undefined }
|
|
456
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { data: undefined }));
|
|
483
457
|
// Then the form is marked as loading
|
|
484
|
-
expect(r.loading
|
|
458
|
+
expect(r.loading).toHaveTextContent("true");
|
|
485
459
|
// And when the data is no longer undefined
|
|
486
|
-
await r.rerender(jsx_runtime_1.jsx(TestComponent, { data: { firstName: "first" } }
|
|
460
|
+
await r.rerender((0, jsx_runtime_1.jsx)(TestComponent, { data: { firstName: "first" } }));
|
|
487
461
|
// Then the form is marked as not loading
|
|
488
|
-
expect(r.loading
|
|
462
|
+
expect(r.loading).toHaveTextContent("false");
|
|
489
463
|
});
|
|
490
464
|
it("sets loading if query.loading is true", async () => {
|
|
491
465
|
const config = { firstName: { type: "value" } };
|
|
492
466
|
function TestComponent({ loading, data }) {
|
|
493
|
-
const form = useFormState_1.useFormState({ config, init: { query: { data, loading, error: null }, map: (d) => d } });
|
|
494
|
-
return jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => jsx_runtime_1.jsx("div",
|
|
467
|
+
const form = (0, useFormState_1.useFormState)({ config, init: { query: { data, loading, error: null }, map: (d) => d } });
|
|
468
|
+
return (0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => (0, jsx_runtime_1.jsx)("div", { "data-testid": "loading", children: String(form.loading) }) });
|
|
495
469
|
}
|
|
496
470
|
// And we initially pass in `init.query.loading: true`
|
|
497
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, { loading: true, data: undefined }
|
|
471
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, { loading: true, data: undefined }));
|
|
498
472
|
// Then the form is marked as loading
|
|
499
|
-
expect(r.loading
|
|
473
|
+
expect(r.loading).toHaveTextContent("true");
|
|
500
474
|
// And when the query is not loading
|
|
501
|
-
await r.rerender(jsx_runtime_1.jsx(TestComponent, { loading: false, data: { firstName: "first" } }
|
|
475
|
+
await r.rerender((0, jsx_runtime_1.jsx)(TestComponent, { loading: false, data: { firstName: "first" } }));
|
|
502
476
|
// Then the form is marked as not loading
|
|
503
|
-
expect(r.loading
|
|
504
|
-
});
|
|
505
|
-
it("updates AutoSaveStatusProvider when autoSaving", async () => {
|
|
506
|
-
const config = { firstName: { type: "value" } };
|
|
507
|
-
const { result } = react_hooks_1.renderHook(() => ({
|
|
508
|
-
fs: useFormState_1.useFormState({ config, autoSave: async () => { } }),
|
|
509
|
-
autoSave: AutoSaveStatus_1.useAutoSaveStatus(),
|
|
510
|
-
}), {
|
|
511
|
-
wrapper: ({ children }) => (jsx_runtime_1.jsx(AutoSaveStatus_1.AutoSaveStatusProvider, { children: jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: children }, void 0) }, void 0) }, void 0)),
|
|
512
|
-
});
|
|
513
|
-
expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.IDLE);
|
|
514
|
-
// When we invoke a change and autoSave fires
|
|
515
|
-
react_hooks_1.act(() => {
|
|
516
|
-
result.current.fs.set({ firstName: "test" });
|
|
517
|
-
});
|
|
518
|
-
react_hooks_1.act(() => {
|
|
519
|
-
// useFormState has a setTimeout(..., 0) that needs to run
|
|
520
|
-
jest.advanceTimersToNextTimer();
|
|
521
|
-
});
|
|
522
|
-
expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.SAVING);
|
|
523
|
-
// Idk why this needs to be async but it doesn't work otherwise
|
|
524
|
-
await react_hooks_1.act(async () => {
|
|
525
|
-
jest.runAllTimers();
|
|
526
|
-
});
|
|
527
|
-
// Then we expect AutoSaveStatus to be notiied of Doneness
|
|
528
|
-
expect(result.current.autoSave.status).toBe(AutoSaveStatusProvider_1.AutoSaveStatus.DONE);
|
|
529
|
-
jest.clearAllTimers();
|
|
477
|
+
expect(r.loading).toHaveTextContent("false");
|
|
530
478
|
});
|
|
531
479
|
it("treats the id changing as a whole new entity instead of a delete", async () => {
|
|
532
480
|
const config = { firstName: { type: "value" } };
|
|
533
481
|
function TestComponent() {
|
|
534
482
|
// Given an initial author a1
|
|
535
|
-
const [author, setAuthor] = react_2.useState({ id: "a:1", firstName: "a1" });
|
|
536
|
-
const form = useFormState_1.useFormState({ config, init: { input: author, map: (a) => a } });
|
|
537
|
-
return (jsx_runtime_1.jsx(mobx_react_1.Observer, { children: () => (jsx_runtime_1.jsxs("div", { children: [jsx_runtime_1.jsx("div",
|
|
538
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "dirty" }, { children: String(form.firstName.dirty) }), void 0),
|
|
539
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "originalValue" }, { children: String(form.firstName.originalValue) }), void 0),
|
|
540
|
-
jsx_runtime_1.jsx("div", Object.assign({ "data-testid": "objectValue" }, { children: String(form.value.firstName) }), void 0),
|
|
541
|
-
jsx_runtime_1.jsx("div", { "data-testid": "a1", onClick: () => setAuthor({ id: "a:1", firstName: "a1" }) }, void 0),
|
|
542
|
-
jsx_runtime_1.jsx("div", { "data-testid": "a2", onClick: () => setAuthor({ id: "a:2", firstName: undefined }) }, void 0)] }, void 0)) }, void 0));
|
|
483
|
+
const [author, setAuthor] = (0, react_2.useState)({ id: "a:1", firstName: "a1" });
|
|
484
|
+
const form = (0, useFormState_1.useFormState)({ config, init: { input: author, map: (a) => a } });
|
|
485
|
+
return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "value", children: String(form.firstName.value) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "dirty", children: String(form.firstName.dirty) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "originalValue", children: String(form.firstName.originalValue) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "objectValue", children: String(form.value.firstName) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "a1", onClick: () => setAuthor({ id: "a:1", firstName: "a1" }) }), (0, jsx_runtime_1.jsx)("div", { "data-testid": "a2", onClick: () => setAuthor({ id: "a:2", firstName: undefined }) })] })) }));
|
|
543
486
|
}
|
|
544
|
-
const r = await rtl_utils_1.render(jsx_runtime_1.jsx(TestComponent, {}
|
|
487
|
+
const r = await (0, rtl_utils_1.render)((0, jsx_runtime_1.jsx)(TestComponent, {}));
|
|
545
488
|
// And the value is initially a1/and not dirty
|
|
546
|
-
expect(r.value
|
|
547
|
-
expect(r.dirty
|
|
548
|
-
expect(r.originalValue
|
|
549
|
-
expect(r.objectValue
|
|
489
|
+
expect(r.value).toHaveTextContent("a1");
|
|
490
|
+
expect(r.dirty).toHaveTextContent("false");
|
|
491
|
+
expect(r.originalValue).toHaveTextContent("a1");
|
|
492
|
+
expect(r.objectValue).toHaveTextContent("a1");
|
|
550
493
|
// When we switch to a completely separate author
|
|
551
|
-
rtl_utils_1.click(r.a2);
|
|
494
|
+
(0, rtl_utils_1.click)(r.a2);
|
|
552
495
|
// Then it switches to the next author
|
|
553
|
-
expect(r.value
|
|
496
|
+
expect(r.value).toHaveTextContent("undefined");
|
|
554
497
|
// And the field is not dirty (which had been the case before this bug fix)
|
|
555
|
-
expect(r.dirty
|
|
556
|
-
expect(r.originalValue
|
|
557
|
-
expect(r.objectValue
|
|
498
|
+
expect(r.dirty).toHaveTextContent("false");
|
|
499
|
+
expect(r.originalValue).toHaveTextContent("undefined");
|
|
500
|
+
expect(r.objectValue).toHaveTextContent("undefined");
|
|
558
501
|
// And when we switch back to the original author
|
|
559
|
-
rtl_utils_1.click(r.a1);
|
|
502
|
+
(0, rtl_utils_1.click)(r.a1);
|
|
560
503
|
// It again restores the value and does not think an edit was WIP
|
|
561
|
-
expect(r.value
|
|
562
|
-
expect(r.dirty
|
|
563
|
-
expect(r.originalValue
|
|
564
|
-
expect(r.objectValue
|
|
504
|
+
expect(r.value).toHaveTextContent("a1");
|
|
505
|
+
expect(r.dirty).toHaveTextContent("false");
|
|
506
|
+
expect(r.originalValue).toHaveTextContent("a1");
|
|
507
|
+
expect(r.objectValue).toHaveTextContent("a1");
|
|
565
508
|
});
|
|
566
509
|
});
|
|
567
510
|
const authorConfig = {
|