@dhis2/app-service-data 3.2.7 → 3.3.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.
@@ -23,7 +23,7 @@ export const isCreateFeedbackMessage = (type, {
23
23
  export const isCreateInterpretation = (type, {
24
24
  resource
25
25
  }) => {
26
- const pattern = /^interpretations\/(?:reportTable|chart|visualization|map|eventReport|eventChart|dataSetReport)\/[a-zA-Z0-9]{11}$/;
26
+ const pattern = /^interpretations\/(?:reportTable|chart|visualization|map|eventVisualization|eventReport|eventChart|dataSetReport)\/[a-zA-Z0-9]{11}$/;
27
27
  return type === 'create' && pattern.test(resource);
28
28
  }; // PUT to `interpretations/${id}` (update an interpretation)
29
29
 
@@ -1,72 +1,337 @@
1
1
  import { renderHook, act } from '@testing-library/react-hooks';
2
- import React from 'react';
2
+ import * as React from 'react';
3
3
  import { CustomDataProvider } from '../components/CustomDataProvider';
4
+ import { useDataEngine } from './useDataEngine';
4
5
  import { useDataMutation } from './useDataMutation';
5
- const customData = {
6
- answer: 42
7
- };
8
-
9
- const wrapper = ({
10
- children
11
- }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
12
- data: customData
13
- }, children);
14
-
15
- const mutation = {
16
- type: 'create',
17
- resource: 'answer',
18
- data: {
19
- answer: 42
20
- }
21
- };
22
- describe('useDataMustation', () => {
23
- const originalError = console.error;
24
- afterEach(() => {
25
- console.error = originalError;
6
+ describe('useDataMutation', () => {
7
+ it('should render without failing', async () => {
8
+ const mutation = {
9
+ type: 'create',
10
+ resource: 'answer',
11
+ data: {
12
+ answer: '?'
13
+ }
14
+ };
15
+ const data = {
16
+ answer: 42
17
+ };
18
+
19
+ const wrapper = ({
20
+ children
21
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
22
+ data: data
23
+ }, children);
24
+
25
+ const {
26
+ result,
27
+ waitFor
28
+ } = renderHook(() => useDataMutation(mutation), {
29
+ wrapper
30
+ });
31
+ const [mutate, beforeMutation] = result.current;
32
+ expect(beforeMutation).toMatchObject({
33
+ loading: false,
34
+ called: false
35
+ });
36
+ act(() => {
37
+ mutate();
38
+ });
39
+ await waitFor(() => {
40
+ const [, duringMutation] = result.current;
41
+ expect(duringMutation).toMatchObject({
42
+ loading: true,
43
+ called: true
44
+ });
45
+ });
46
+ await waitFor(() => {
47
+ const [, afterMutation] = result.current;
48
+ expect(afterMutation).toMatchObject({
49
+ loading: false,
50
+ called: true,
51
+ data: 42
52
+ });
53
+ });
54
+ });
55
+ it('should run immediately with lazy: false', async () => {
56
+ const mutation = {
57
+ type: 'create',
58
+ resource: 'answer',
59
+ data: {
60
+ answer: '?'
61
+ }
62
+ };
63
+ const data = {
64
+ answer: 42
65
+ };
66
+
67
+ const wrapper = ({
68
+ children
69
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
70
+ data: data
71
+ }, children);
72
+
73
+ const {
74
+ result,
75
+ waitFor
76
+ } = renderHook(() => useDataMutation(mutation, {
77
+ lazy: false
78
+ }), {
79
+ wrapper
80
+ });
81
+ const [, duringMutation] = result.current;
82
+ expect(duringMutation).toMatchObject({
83
+ loading: true,
84
+ called: true
85
+ });
86
+ await waitFor(() => {
87
+ const [, afterMutation] = result.current;
88
+ expect(afterMutation).toMatchObject({
89
+ loading: false,
90
+ called: true,
91
+ data: 42
92
+ });
93
+ });
26
94
  });
27
- it('Should render without failing', async () => {
28
- let hookState;
29
- console.error = jest.fn();
95
+ it('should call onComplete on success', async () => {
96
+ const onComplete = jest.fn();
97
+ const mutation = {
98
+ type: 'create',
99
+ resource: 'answer',
100
+ data: {
101
+ answer: '?'
102
+ }
103
+ };
104
+ const data = {
105
+ answer: 42
106
+ };
107
+
108
+ const wrapper = ({
109
+ children
110
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
111
+ data: data
112
+ }, children);
113
+
114
+ const {
115
+ result,
116
+ waitFor
117
+ } = renderHook(() => useDataMutation(mutation, {
118
+ onComplete
119
+ }), {
120
+ wrapper
121
+ });
122
+ expect(onComplete).toHaveBeenCalledTimes(0);
123
+ const [mutate] = result.current;
30
124
  act(() => {
31
- hookState = renderHook(() => useDataMutation(mutation), {
32
- wrapper
125
+ mutate();
126
+ });
127
+ await waitFor(() => {
128
+ const [, state] = result.current;
129
+ expect(state).toMatchObject({
130
+ loading: false,
131
+ called: true,
132
+ data: 42
33
133
  });
134
+ expect(onComplete).toHaveBeenCalledTimes(1);
135
+ expect(onComplete).toHaveBeenLastCalledWith(42);
34
136
  });
35
- let [mutate, state] = hookState.result.current;
36
- expect(state).toMatchObject({
37
- called: false,
38
- loading: false
137
+ });
138
+ it('should call onError on error', async () => {
139
+ const error = new Error('Something went wrong');
140
+ const onError = jest.fn();
141
+ const mutation = {
142
+ type: 'create',
143
+ resource: 'answer',
144
+ data: {
145
+ answer: 42
146
+ }
147
+ };
148
+ const data = {
149
+ answer: () => {
150
+ throw error;
151
+ }
152
+ };
153
+
154
+ const wrapper = ({
155
+ children
156
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
157
+ data: data
158
+ }, children);
159
+
160
+ const {
161
+ result,
162
+ waitFor
163
+ } = renderHook(() => useDataMutation(mutation, {
164
+ onError
165
+ }), {
166
+ wrapper
39
167
  });
168
+ expect(onError).toHaveBeenCalledTimes(0);
169
+ const [mutate] = result.current;
40
170
  act(() => {
41
171
  mutate();
42
172
  });
43
- mutate = hookState.result.current[0];
44
- state = hookState.result.current[1];
45
- expect(state).toMatchObject({
46
- called: true,
47
- loading: true
173
+ await waitFor(() => {
174
+ const [, state] = result.current;
175
+ expect(state).toMatchObject({
176
+ loading: false,
177
+ called: true,
178
+ error
179
+ });
48
180
  });
181
+ expect(onError).toHaveBeenCalledTimes(1);
182
+ expect(onError).toHaveBeenLastCalledWith(error);
49
183
  });
50
- it('Should run immediately with lazy: false', async () => {
51
- let hookState;
52
- console.error = jest.fn();
184
+ it('should resolve variables', async () => {
185
+ const mutation = {
186
+ type: 'update',
187
+ resource: 'answer',
188
+ id: ({
189
+ id
190
+ }) => id,
191
+ data: {
192
+ answer: '?'
193
+ }
194
+ };
195
+ const answerSpy = jest.fn(() => 42);
196
+ const data = {
197
+ answer: answerSpy
198
+ };
199
+
200
+ const wrapper = ({
201
+ children
202
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
203
+ data: data
204
+ }, children);
205
+
206
+ const {
207
+ result,
208
+ waitFor
209
+ } = renderHook(() => useDataMutation(mutation, {
210
+ lazy: false,
211
+ variables: {
212
+ id: '1'
213
+ }
214
+ }), {
215
+ wrapper
216
+ });
217
+ await waitFor(() => {
218
+ expect(answerSpy).toHaveBeenLastCalledWith(expect.any(String), expect.objectContaining({
219
+ id: '1'
220
+ }), expect.any(Object));
221
+ });
222
+ const [mutate] = result.current;
53
223
  act(() => {
54
- hookState = renderHook(() => useDataMutation(mutation, {
55
- lazy: false
56
- }), {
57
- wrapper
224
+ mutate({
225
+ id: '2'
58
226
  });
59
227
  });
60
- let [, state] = hookState.result.current;
61
- expect(state).toMatchObject({
62
- called: true,
63
- loading: true
228
+ await waitFor(() => {
229
+ expect(answerSpy).toHaveBeenLastCalledWith(expect.any(String), expect.objectContaining({
230
+ id: '2'
231
+ }), expect.any(Object));
64
232
  });
65
- await hookState.waitForNextUpdate();
66
- state = hookState.result.current[1];
233
+ });
234
+ it('should return a reference to the engine', async () => {
235
+ const mutation = {
236
+ type: 'create',
237
+ resource: 'answer',
238
+ data: {
239
+ answer: '?'
240
+ }
241
+ };
242
+
243
+ const wrapper = ({
244
+ children
245
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
246
+ data: {}
247
+ }, children);
248
+
249
+ const engineHook = renderHook(() => useDataEngine(), {
250
+ wrapper
251
+ });
252
+ const mutationHook = renderHook(() => useDataMutation(mutation), {
253
+ wrapper
254
+ });
255
+ /**
256
+ * Ideally we'd check referential equality here with .toBe, but since
257
+ * both hooks run in a different context that doesn't work.
258
+ */
259
+
260
+ expect(mutationHook.result.current[1].engine).toStrictEqual(engineHook.result.current);
261
+ });
262
+ it('should return a stable mutate function', async () => {
263
+ const mutation = {
264
+ type: 'create',
265
+ resource: 'answer',
266
+ data: {
267
+ answer: '?'
268
+ }
269
+ };
270
+ const data = {
271
+ answer: 42
272
+ };
273
+
274
+ const wrapper = ({
275
+ children
276
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
277
+ data: data
278
+ }, children);
279
+
280
+ const {
281
+ result
282
+ } = renderHook(() => useDataMutation(mutation), {
283
+ wrapper
284
+ });
285
+ const [firstMutate] = result.current;
286
+ await act(async () => {
287
+ await firstMutate({
288
+ variable: 'variable'
289
+ });
290
+ });
291
+ const [secondMutate, state] = result.current;
67
292
  expect(state).toMatchObject({
68
293
  loading: false,
69
- data: 42
294
+ called: true
295
+ });
296
+ expect(firstMutate).toBe(secondMutate);
297
+ });
298
+ it('should resolve with the data from mutate on success', async () => {
299
+ const mutation = {
300
+ type: 'create',
301
+ resource: 'answer',
302
+ data: {
303
+ answer: '?'
304
+ }
305
+ };
306
+ const data = {
307
+ answer: 42
308
+ };
309
+
310
+ const wrapper = ({
311
+ children
312
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
313
+ data: data
314
+ }, children);
315
+
316
+ const {
317
+ result,
318
+ waitFor
319
+ } = renderHook(() => useDataMutation(mutation), {
320
+ wrapper
321
+ });
322
+ let mutatePromise;
323
+ const [mutate] = result.current;
324
+ act(() => {
325
+ mutatePromise = mutate();
326
+ });
327
+ await waitFor(() => {
328
+ const [, state] = result.current;
329
+ expect(state).toMatchObject({
330
+ loading: false,
331
+ called: true,
332
+ data: 42
333
+ });
334
+ expect(mutatePromise).resolves.toBe(42);
70
335
  });
71
336
  });
72
337
  });
@@ -1,4 +1,5 @@
1
1
  import { ResolvedResourceQuery, FetchType } from '../../../engine';
2
+ export declare const isDataValue: (type: FetchType, { resource }: ResolvedResourceQuery) => boolean;
2
3
  export declare const isFileResourceUpload: (type: FetchType, { resource }: ResolvedResourceQuery) => boolean;
3
4
  export declare const isMessageConversationAttachment: (type: FetchType, { resource }: ResolvedResourceQuery) => boolean;
4
5
  export declare const isStaticContentUpload: (type: FetchType, { resource }: ResolvedResourceQuery) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhis2/app-service-data",
3
- "version": "3.2.7",
3
+ "version": "3.3.0",
4
4
  "main": "./build/cjs/index.js",
5
5
  "module": "./build/es/index.js",
6
6
  "types": "build/types/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "build/**"
23
23
  ],
24
24
  "peerDependencies": {
25
- "@dhis2/app-service-config": "3.2.7",
25
+ "@dhis2/app-service-config": "3.3.0",
26
26
  "@dhis2/cli-app-scripts": "^7.1.1",
27
27
  "prop-types": "^15.7.2",
28
28
  "react": "^16.8",