@data-client/core 0.1.0 → 0.2.1

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.
Files changed (247) hide show
  1. package/dist/index.js +134 -409
  2. package/dist/index.umd.min.js +1 -1
  3. package/dist/next.js +61 -101
  4. package/legacy/actionTypes.js +2 -2
  5. package/legacy/controller/Controller.js +276 -6
  6. package/legacy/controller/createFetch.js +3 -14
  7. package/legacy/controller/createInvalidate.js +1 -1
  8. package/legacy/controller/createInvalidateAll.js +1 -1
  9. package/legacy/controller/createOptimistic.js +1 -7
  10. package/legacy/controller/createReset.js +1 -1
  11. package/legacy/controller/createSet.js +31 -0
  12. package/legacy/controller/createSubscription.js +3 -7
  13. package/legacy/index.js +2 -5
  14. package/legacy/internal.js +2 -2
  15. package/legacy/manager/DevtoolsManager.js +2 -2
  16. package/legacy/manager/LogoutManager.js +2 -2
  17. package/legacy/manager/NetworkManager.js +28 -59
  18. package/legacy/manager/PollingSubscription.js +18 -27
  19. package/legacy/manager/SubscriptionManager.js +16 -42
  20. package/legacy/manager/applyManager.js +2 -1
  21. package/legacy/middlewareTypes.js +1 -1
  22. package/legacy/newActions.js +1 -1
  23. package/legacy/next/index.js +3 -3
  24. package/legacy/state/reducer/createReducer.js +2 -6
  25. package/legacy/state/reducer/fetchReducer.js +3 -13
  26. package/legacy/state/reducer/invalidateReducer.js +1 -1
  27. package/legacy/state/reducer/setReducer.js +9 -16
  28. package/legacy/types.js +2 -6
  29. package/lib/actionTypes.d.ts +1 -0
  30. package/lib/actionTypes.d.ts.map +1 -1
  31. package/lib/actionTypes.js +2 -2
  32. package/lib/controller/Controller.d.ts +126 -6
  33. package/lib/controller/Controller.d.ts.map +1 -1
  34. package/lib/controller/Controller.js +276 -6
  35. package/lib/controller/createFetch.d.ts +2 -2
  36. package/lib/controller/createFetch.d.ts.map +1 -1
  37. package/lib/controller/createFetch.js +3 -14
  38. package/lib/controller/createInvalidate.d.ts +1 -1
  39. package/lib/controller/createInvalidate.d.ts.map +1 -1
  40. package/lib/controller/createInvalidate.js +1 -1
  41. package/lib/controller/createInvalidateAll.d.ts +1 -1
  42. package/lib/controller/createInvalidateAll.d.ts.map +1 -1
  43. package/lib/controller/createInvalidateAll.js +1 -1
  44. package/lib/controller/createOptimistic.d.ts +2 -2
  45. package/lib/controller/createOptimistic.d.ts.map +1 -1
  46. package/lib/controller/createOptimistic.js +1 -7
  47. package/lib/controller/createReset.d.ts +1 -1
  48. package/lib/controller/createReset.d.ts.map +1 -1
  49. package/lib/controller/createReset.js +1 -1
  50. package/lib/controller/{createReceive.d.ts → createSet.d.ts} +6 -6
  51. package/lib/controller/createSet.d.ts.map +1 -0
  52. package/lib/controller/createSet.js +31 -0
  53. package/lib/controller/createSubscription.d.ts +3 -3
  54. package/lib/controller/createSubscription.d.ts.map +1 -1
  55. package/lib/controller/createSubscription.js +3 -7
  56. package/lib/index.d.ts +2 -6
  57. package/lib/index.d.ts.map +1 -1
  58. package/lib/index.js +2 -5
  59. package/lib/internal.d.ts +1 -1
  60. package/lib/internal.d.ts.map +1 -1
  61. package/lib/internal.js +2 -2
  62. package/lib/manager/DevtoolsManager.d.ts +1 -1
  63. package/lib/manager/DevtoolsManager.js +2 -2
  64. package/lib/manager/LogoutManager.d.ts +4 -5
  65. package/lib/manager/LogoutManager.d.ts.map +1 -1
  66. package/lib/manager/LogoutManager.js +2 -2
  67. package/lib/manager/NetworkManager.d.ts +4 -5
  68. package/lib/manager/NetworkManager.d.ts.map +1 -1
  69. package/lib/manager/NetworkManager.js +28 -61
  70. package/lib/manager/PollingSubscription.d.ts +9 -9
  71. package/lib/manager/PollingSubscription.d.ts.map +1 -1
  72. package/lib/manager/PollingSubscription.js +18 -27
  73. package/lib/manager/SubscriptionManager.d.ts +10 -15
  74. package/lib/manager/SubscriptionManager.d.ts.map +1 -1
  75. package/lib/manager/SubscriptionManager.js +16 -42
  76. package/lib/manager/applyManager.d.ts.map +1 -1
  77. package/lib/manager/applyManager.js +2 -1
  78. package/lib/middlewareTypes.d.ts +5 -5
  79. package/lib/middlewareTypes.d.ts.map +1 -1
  80. package/lib/middlewareTypes.js +1 -1
  81. package/lib/newActions.d.ts +26 -18
  82. package/lib/newActions.d.ts.map +1 -1
  83. package/lib/newActions.js +1 -1
  84. package/lib/next/index.d.ts +2 -2
  85. package/lib/next/index.d.ts.map +1 -1
  86. package/lib/next/index.js +3 -3
  87. package/lib/state/reducer/createReducer.d.ts.map +1 -1
  88. package/lib/state/reducer/createReducer.js +2 -6
  89. package/lib/state/reducer/fetchReducer.d.ts +1 -2
  90. package/lib/state/reducer/fetchReducer.d.ts.map +1 -1
  91. package/lib/state/reducer/fetchReducer.js +3 -14
  92. package/lib/state/reducer/invalidateReducer.d.ts +3 -4
  93. package/lib/state/reducer/invalidateReducer.d.ts.map +1 -1
  94. package/lib/state/reducer/invalidateReducer.js +1 -1
  95. package/lib/state/reducer/setReducer.d.ts +2 -38
  96. package/lib/state/reducer/setReducer.d.ts.map +1 -1
  97. package/lib/state/reducer/setReducer.js +9 -17
  98. package/lib/types.d.ts +9 -30
  99. package/lib/types.d.ts.map +1 -1
  100. package/lib/types.js +2 -6
  101. package/package.json +10 -7
  102. package/src/actionTypes.ts +1 -1
  103. package/src/controller/Controller.ts +491 -10
  104. package/src/controller/createFetch.ts +4 -19
  105. package/src/controller/createInvalidate.ts +1 -1
  106. package/src/controller/createInvalidateAll.ts +1 -1
  107. package/src/controller/createOptimistic.ts +3 -9
  108. package/src/controller/createReset.ts +1 -1
  109. package/src/controller/{createReceive.ts → createSet.ts} +9 -17
  110. package/src/controller/createSubscription.ts +3 -10
  111. package/src/index.ts +2 -16
  112. package/src/internal.ts +1 -1
  113. package/src/manager/DevtoolsManager.ts +1 -1
  114. package/src/manager/LogoutManager.ts +4 -5
  115. package/src/manager/NetworkManager.ts +31 -80
  116. package/src/manager/PollingSubscription.ts +40 -38
  117. package/src/manager/SubscriptionManager.ts +22 -54
  118. package/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap +10 -8
  119. package/src/manager/__tests__/logoutManager.ts +5 -5
  120. package/src/manager/__tests__/manager.ts +2 -4
  121. package/src/manager/__tests__/networkManager.ts +8 -42
  122. package/src/manager/__tests__/pollingSubscription.ts +259 -151
  123. package/src/manager/__tests__/subscriptionManager.ts +7 -13
  124. package/src/manager/applyManager.ts +1 -0
  125. package/src/middlewareTypes.ts +5 -10
  126. package/src/newActions.ts +33 -23
  127. package/src/next/index.ts +2 -2
  128. package/src/state/__tests__/reducer.ts +59 -297
  129. package/src/state/reducer/createReducer.ts +3 -11
  130. package/src/state/reducer/fetchReducer.ts +5 -18
  131. package/src/state/reducer/invalidateReducer.ts +2 -2
  132. package/src/state/reducer/setReducer.ts +10 -22
  133. package/src/types.ts +9 -78
  134. package/ts3.4/actionTypes.d.ts +1 -0
  135. package/ts3.4/controller/Controller.d.ts +168 -6
  136. package/ts3.4/controller/createFetch.d.ts +2 -2
  137. package/ts3.4/controller/createInvalidate.d.ts +1 -1
  138. package/ts3.4/controller/createInvalidateAll.d.ts +1 -1
  139. package/ts3.4/controller/createOptimistic.d.ts +1 -1
  140. package/ts3.4/controller/createReset.d.ts +1 -1
  141. package/ts3.4/controller/{createReceive.d.ts → createSet.d.ts} +6 -6
  142. package/ts3.4/controller/createSubscription.d.ts +3 -3
  143. package/ts3.4/index.d.ts +2 -7
  144. package/ts3.4/internal.d.ts +1 -1
  145. package/ts3.4/manager/DevtoolsManager.d.ts +1 -1
  146. package/ts3.4/manager/LogoutManager.d.ts +4 -5
  147. package/ts3.4/manager/NetworkManager.d.ts +4 -5
  148. package/ts3.4/manager/PollingSubscription.d.ts +9 -9
  149. package/ts3.4/manager/SubscriptionManager.d.ts +10 -15
  150. package/ts3.4/middlewareTypes.d.ts +5 -5
  151. package/ts3.4/newActions.d.ts +26 -18
  152. package/ts3.4/next/index.d.ts +2 -2
  153. package/ts3.4/state/reducer/fetchReducer.d.ts +1 -2
  154. package/ts3.4/state/reducer/invalidateReducer.d.ts +3 -4
  155. package/ts3.4/state/reducer/setReducer.d.ts +2 -38
  156. package/ts3.4/types.d.ts +8 -30
  157. package/legacy/compatibleActions.js +0 -2
  158. package/legacy/controller/BaseController.js +0 -289
  159. package/legacy/controller/createReceive.js +0 -36
  160. package/legacy/endpoint/index.js +0 -2
  161. package/legacy/endpoint/shapes.js +0 -2
  162. package/legacy/endpoint/types.js +0 -2
  163. package/legacy/legacyActions.js +0 -2
  164. package/legacy/next/Controller.js +0 -24
  165. package/legacy/previousActions.js +0 -2
  166. package/legacy/state/applyUpdatersToResults.js +0 -4
  167. package/legacy/state/legacy-actions/createFetch.js +0 -62
  168. package/legacy/state/legacy-actions/createReceive.js +0 -37
  169. package/legacy/state/legacy-actions/createReceiveError.js +0 -28
  170. package/legacy/state/legacy-actions/index.js +0 -4
  171. package/legacy/state/reducerInstance.js +0 -9
  172. package/lib/compatibleActions.d.ts +0 -47
  173. package/lib/compatibleActions.d.ts.map +0 -1
  174. package/lib/compatibleActions.js +0 -2
  175. package/lib/controller/BaseController.d.ts +0 -128
  176. package/lib/controller/BaseController.d.ts.map +0 -1
  177. package/lib/controller/BaseController.js +0 -289
  178. package/lib/controller/createReceive.d.ts.map +0 -1
  179. package/lib/controller/createReceive.js +0 -36
  180. package/lib/endpoint/index.d.ts +0 -3
  181. package/lib/endpoint/index.d.ts.map +0 -1
  182. package/lib/endpoint/index.js +0 -2
  183. package/lib/endpoint/shapes.d.ts +0 -25
  184. package/lib/endpoint/shapes.d.ts.map +0 -1
  185. package/lib/endpoint/shapes.js +0 -2
  186. package/lib/endpoint/types.d.ts +0 -45
  187. package/lib/endpoint/types.d.ts.map +0 -1
  188. package/lib/endpoint/types.js +0 -2
  189. package/lib/legacyActions.d.ts +0 -92
  190. package/lib/legacyActions.d.ts.map +0 -1
  191. package/lib/legacyActions.js +0 -2
  192. package/lib/next/Controller.d.ts +0 -14
  193. package/lib/next/Controller.d.ts.map +0 -1
  194. package/lib/next/Controller.js +0 -24
  195. package/lib/previousActions.d.ts +0 -91
  196. package/lib/previousActions.d.ts.map +0 -1
  197. package/lib/previousActions.js +0 -2
  198. package/lib/state/applyUpdatersToResults.d.ts +0 -13
  199. package/lib/state/applyUpdatersToResults.d.ts.map +0 -1
  200. package/lib/state/applyUpdatersToResults.js +0 -7
  201. package/lib/state/legacy-actions/createFetch.d.ts +0 -19
  202. package/lib/state/legacy-actions/createFetch.d.ts.map +0 -1
  203. package/lib/state/legacy-actions/createFetch.js +0 -62
  204. package/lib/state/legacy-actions/createReceive.d.ts +0 -14
  205. package/lib/state/legacy-actions/createReceive.d.ts.map +0 -1
  206. package/lib/state/legacy-actions/createReceive.js +0 -37
  207. package/lib/state/legacy-actions/createReceiveError.d.ts +0 -9
  208. package/lib/state/legacy-actions/createReceiveError.d.ts.map +0 -1
  209. package/lib/state/legacy-actions/createReceiveError.js +0 -28
  210. package/lib/state/legacy-actions/index.d.ts +0 -4
  211. package/lib/state/legacy-actions/index.d.ts.map +0 -1
  212. package/lib/state/legacy-actions/index.js +0 -4
  213. package/lib/state/reducerInstance.d.ts +0 -7
  214. package/lib/state/reducerInstance.d.ts.map +0 -1
  215. package/lib/state/reducerInstance.js +0 -9
  216. package/src/compatibleActions.ts +0 -96
  217. package/src/controller/BaseController.ts +0 -508
  218. package/src/endpoint/index.ts +0 -14
  219. package/src/endpoint/shapes.ts +0 -53
  220. package/src/endpoint/types.ts +0 -72
  221. package/src/legacyActions.ts +0 -163
  222. package/src/manager/__tests__/__snapshots__/pollingSubscription-endpoint.ts.snap +0 -49
  223. package/src/manager/__tests__/networkManager-legacy.ts +0 -394
  224. package/src/manager/__tests__/pollingSubscription-endpoint.ts +0 -423
  225. package/src/next/Controller.ts +0 -39
  226. package/src/previousActions.ts +0 -159
  227. package/src/state/__tests__/applyUpdatersToResults.ts +0 -40
  228. package/src/state/applyUpdatersToResults.ts +0 -29
  229. package/src/state/legacy-actions/createFetch.ts +0 -95
  230. package/src/state/legacy-actions/createReceive.ts +0 -68
  231. package/src/state/legacy-actions/createReceiveError.ts +0 -43
  232. package/src/state/legacy-actions/index.ts +0 -3
  233. package/src/state/reducerInstance.ts +0 -14
  234. package/ts3.4/compatibleActions.d.ts +0 -47
  235. package/ts3.4/controller/BaseController.d.ts +0 -170
  236. package/ts3.4/endpoint/index.d.ts +0 -3
  237. package/ts3.4/endpoint/shapes.d.ts +0 -25
  238. package/ts3.4/endpoint/types.d.ts +0 -45
  239. package/ts3.4/legacyActions.d.ts +0 -95
  240. package/ts3.4/next/Controller.d.ts +0 -14
  241. package/ts3.4/previousActions.d.ts +0 -94
  242. package/ts3.4/state/applyUpdatersToResults.d.ts +0 -13
  243. package/ts3.4/state/legacy-actions/createFetch.d.ts +0 -19
  244. package/ts3.4/state/legacy-actions/createReceive.d.ts +0 -14
  245. package/ts3.4/state/legacy-actions/createReceiveError.d.ts +0 -9
  246. package/ts3.4/state/legacy-actions/index.d.ts +0 -4
  247. package/ts3.4/state/reducerInstance.d.ts +0 -7
@@ -2,7 +2,7 @@ import { CoolerArticleResource } from '__tests__/new';
2
2
 
3
3
  import { Controller, initialState } from '../..';
4
4
  import { FETCH_TYPE, RESET_TYPE } from '../../actionTypes';
5
- import createReceive from '../../controller/createReceive';
5
+ import createSet from '../../controller/createSet';
6
6
  import LogoutManager from '../LogoutManager.js';
7
7
 
8
8
  function onError(e: any) {
@@ -44,7 +44,7 @@ describe('LogoutManager', () => {
44
44
  },
45
45
  );
46
46
  it('should ignore non-error receive', async () => {
47
- const action = createReceive(CoolerArticleResource.get, {
47
+ const action = createSet(CoolerArticleResource.get, {
48
48
  args: [{ id: 5 }],
49
49
  response: { id: 5, title: 'hi' },
50
50
  });
@@ -55,7 +55,7 @@ describe('LogoutManager', () => {
55
55
  it('should ignore non-401 receive', async () => {
56
56
  const error: any = new Error('network failed');
57
57
  error.status = 404;
58
- const action = createReceive(CoolerArticleResource.get, {
58
+ const action = createSet(CoolerArticleResource.get, {
59
59
  args: [{ id: 5 }],
60
60
  response: error,
61
61
  error: true,
@@ -68,7 +68,7 @@ describe('LogoutManager', () => {
68
68
  jest.setSystemTime(0);
69
69
  const error: any = new Error('network failed');
70
70
  error.status = 401;
71
- const action = createReceive(CoolerArticleResource.get, {
71
+ const action = createSet(CoolerArticleResource.get, {
72
72
  args: [{ id: 5 }],
73
73
  response: error,
74
74
  error: true,
@@ -90,7 +90,7 @@ describe('LogoutManager', () => {
90
90
  jest.setSystemTime(0);
91
91
  const error: any = new Error('network failed');
92
92
  error.status = 403;
93
- const action = createReceive(CoolerArticleResource.get, {
93
+ const action = createSet(CoolerArticleResource.get, {
94
94
  args: [{ id: 5 }],
95
95
  response: error,
96
96
  error: true,
@@ -1,6 +1,6 @@
1
1
  import Controller from '../../controller/Controller';
2
2
  import { Middleware } from '../../middlewareTypes';
3
- import { CombinedActionTypes } from '../../types';
3
+ import { ActionTypes } from '../../types';
4
4
  import NetworkManager from '../NetworkManager';
5
5
 
6
6
  const middleware: Middleware = new NetworkManager().getMiddleware();
@@ -9,9 +9,7 @@ it('middlewares should compose with non-rest-hooks middlewares', () => {
9
9
  type: 'BOB';
10
10
  payload: any;
11
11
  };
12
- const dispatch = jest.fn(
13
- async (action: CombinedActionTypes | AnotherAction) => {},
14
- );
12
+ const dispatch = jest.fn(async (action: ActionTypes | AnotherAction) => {});
15
13
  const ctrl = new Controller({ dispatch });
16
14
  const API: typeof ctrl & { controller: typeof ctrl } = Object.create(ctrl, {
17
15
  controller: { value: ctrl },
@@ -1,7 +1,7 @@
1
1
  import { Endpoint } from '@data-client/endpoint';
2
2
  import { Article, ArticleResource } from '__tests__/new';
3
3
 
4
- import { RECEIVE_TYPE } from '../../actionTypes';
4
+ import { SET_TYPE } from '../../actionTypes';
5
5
  import Controller from '../../controller/Controller';
6
6
  import createFetch from '../../controller/createFetch';
7
7
  import NetworkManager from '../../manager/NetworkManager';
@@ -17,7 +17,7 @@ describe('NetworkManager', () => {
17
17
  });
18
18
  let errorspy: jest.SpyInstance;
19
19
  beforeEach(() => {
20
- errorspy = jest.spyOn(global.console, 'error');
20
+ errorspy = jest.spyOn(global.console, 'error').mockImplementation(() => {});
21
21
  });
22
22
  afterEach(() => {
23
23
  errorspy.mockRestore();
@@ -26,7 +26,7 @@ describe('NetworkManager', () => {
26
26
  it('getState() should have initialState before middleware run', () => {
27
27
  class Hacked extends NetworkManager {
28
28
  getHacked() {
29
- return this.getState();
29
+ return this.controller.getState();
30
30
  }
31
31
  }
32
32
  const hacked = new Hacked();
@@ -162,13 +162,11 @@ describe('NetworkManager', () => {
162
162
  await new Promise(resolve => setTimeout(resolve, 0));
163
163
 
164
164
  const action = {
165
- type: RECEIVE_TYPE,
165
+ type: SET_TYPE,
166
166
  endpoint: fetchResolveAction.endpoint,
167
167
  payload: data,
168
168
  meta: {
169
- schema: fetchResolveAction.meta.schema,
170
169
  args: fetchResolveAction.meta.args,
171
- update: fetchResolveAction.meta.update,
172
170
  key: fetchResolveAction.meta.key,
173
171
  date: expect.any(Number),
174
172
  expiresAt: expect.any(Number),
@@ -197,13 +195,11 @@ describe('NetworkManager', () => {
197
195
  await new Promise(resolve => setTimeout(resolve, 0));
198
196
 
199
197
  const action = {
200
- type: RECEIVE_TYPE,
198
+ type: SET_TYPE,
201
199
  endpoint: fetchReceiveWithUpdatersAction.endpoint,
202
200
  payload: data,
203
201
  meta: {
204
- update: expect.any(Function),
205
202
  args: fetchReceiveWithUpdatersAction.meta.args,
206
- schema: fetchReceiveWithUpdatersAction.meta.schema,
207
203
  key: fetchReceiveWithUpdatersAction.meta.key,
208
204
  date: expect.any(Number),
209
205
  expiresAt: expect.any(Number),
@@ -232,13 +228,11 @@ describe('NetworkManager', () => {
232
228
  await new Promise(resolve => setTimeout(resolve, 0));
233
229
 
234
230
  const action = {
235
- type: RECEIVE_TYPE,
231
+ type: SET_TYPE,
236
232
  endpoint: fetchRpcWithUpdatersAction.endpoint,
237
233
  payload: data,
238
234
  meta: {
239
235
  args: fetchRpcWithUpdatersAction.meta.args,
240
- update: expect.any(Function),
241
- schema: fetchRpcWithUpdatersAction.meta.schema,
242
236
  key: fetchRpcWithUpdatersAction.meta.key,
243
237
  date: expect.any(Number),
244
238
  expiresAt: expect.any(Number),
@@ -267,13 +261,11 @@ describe('NetworkManager', () => {
267
261
  // mutations resolve before dispatch, so we must wait for next tick to see receive
268
262
  await new Promise(resolve => setTimeout(resolve, 0));
269
263
  expect(dispatch).toHaveBeenCalledWith({
270
- type: RECEIVE_TYPE,
264
+ type: SET_TYPE,
271
265
  endpoint: fetchRpcWithUpdatersAndOptimisticAction.endpoint,
272
266
  payload: data,
273
267
  meta: {
274
268
  args: fetchRpcWithUpdatersAndOptimisticAction.meta.args,
275
- update: expect.any(Function),
276
- schema: fetchRpcWithUpdatersAndOptimisticAction.meta.schema,
277
269
  key: fetchRpcWithUpdatersAndOptimisticAction.meta.key,
278
270
  date: expect.any(Number),
279
271
  expiresAt: expect.any(Number),
@@ -339,10 +331,9 @@ describe('NetworkManager', () => {
339
331
  } catch (error) {
340
332
  expect(next).not.toHaveBeenCalled();
341
333
  expect(dispatch).toHaveBeenCalledWith({
342
- type: RECEIVE_TYPE,
334
+ type: SET_TYPE,
343
335
  payload: error,
344
336
  meta: {
345
- schema: fetchRejectAction.meta.schema,
346
337
  key: fetchRejectAction.meta.key,
347
338
  date: expect.any(Number),
348
339
  expiresAt: expect.any(Number),
@@ -366,7 +357,6 @@ describe('NetworkManager', () => {
366
357
  ...fetchRejectAction,
367
358
  meta: {
368
359
  ...fetchRejectAction.meta,
369
- options: { errorExpiryLength: 1234 },
370
360
  },
371
361
  });
372
362
  } catch (error) {
@@ -390,10 +380,6 @@ describe('NetworkManager', () => {
390
380
  ...fetchRejectAction,
391
381
  meta: {
392
382
  ...fetchRejectAction.meta,
393
- options: {
394
- ...fetchRejectAction.meta.options,
395
- errorExpiryLength: undefined,
396
- },
397
383
  },
398
384
  });
399
385
  } catch (error) {
@@ -402,25 +388,5 @@ describe('NetworkManager', () => {
402
388
  expect(meta.expiresAt - meta.date).toBe(7);
403
389
  }
404
390
  });
405
-
406
- it('getLastReset() should handle Date object', async () => {
407
- const mgr = new NetworkManager();
408
- jest.spyOn(mgr, 'getState' as any).mockImplementation((): any => ({
409
- ...initialState,
410
- lastReset: new Date(0),
411
- }));
412
-
413
- expect((mgr as any).getLastReset()).toBeLessThan(Date.now());
414
- });
415
-
416
- it('getLastReset() should handle null', async () => {
417
- const mgr = new NetworkManager();
418
- jest.spyOn(mgr, 'getState' as any).mockImplementation((): any => ({
419
- ...initialState,
420
- lastReset: null,
421
- }));
422
-
423
- expect((mgr as any).getLastReset()).toBeLessThan(Date.now());
424
- });
425
391
  });
426
392
  });
@@ -1,5 +1,8 @@
1
- import { PollingArticleResource } from '__tests__/legacy-3';
1
+ import { Endpoint } from '@data-client/endpoint';
2
+ import { Article, PollingArticleResource } from '__tests__/new';
2
3
 
4
+ import Controller from '../../controller/Controller';
5
+ import { createSubscription } from '../../controller/createSubscription';
3
6
  import { initialState } from '../../state/reducer/createReducer';
4
7
  import ConnectionListener from '../ConnectionListener';
5
8
  import DefaultConnectionListener from '../DefaultConnectionListener';
@@ -55,6 +58,11 @@ class MockConnectionListener implements ConnectionListener {
55
58
  }
56
59
  }
57
60
 
61
+ const makeState = (key: string, time: number) => () => ({
62
+ ...initialState,
63
+ meta: { [key]: { date: time, expiresAt: Infinity } },
64
+ });
65
+
58
66
  function onError(e: any) {
59
67
  e.preventDefault();
60
68
  }
@@ -68,192 +76,277 @@ afterEach(() => {
68
76
  });
69
77
 
70
78
  describe('PollingSubscription', () => {
71
- const dispatch = jest.fn();
72
79
  const a = () => Promise.resolve({ id: 5, title: 'hi' });
73
80
  const fetch = jest.fn(a);
74
- let sub: PollingSubscription;
75
-
76
- beforeAll(() => {
77
- jest.useFakeTimers();
78
- sub = new PollingSubscription(
79
- {
80
- key: 'test.com',
81
- schema: PollingArticleResource,
82
- fetch,
83
- frequency: 5000,
84
- getState: () => initialState,
85
- },
86
- dispatch,
87
- );
88
- });
89
- afterAll(() => {
90
- jest.useRealTimers();
91
- });
92
-
93
- afterAll(() => {
94
- sub.cleanup();
95
- });
96
-
97
- it('should throw on undefined frequency in construction', () => {
98
- expect(
99
- () =>
100
- new PollingSubscription(
101
- {
102
- key: 'test.com',
103
- schema: PollingArticleResource,
104
- fetch,
105
- getState: () => initialState,
106
- },
107
- dispatch,
108
- ),
109
- ).toThrow();
81
+ const endpoint = new Endpoint(fetch, {
82
+ schema: Article,
83
+ key: () => 'test.com',
84
+ pollFrequency: 5000,
110
85
  });
111
86
 
112
- it('should call immediately', () => {
113
- jest.advanceTimersByTime(1);
114
- expect(dispatch.mock.calls.length).toBe(1);
115
- });
87
+ describe('existing data', () => {
88
+ it('should wait to call for fresh data', () => {
89
+ const dispatch = jest.fn();
90
+ const controller = new Controller({ dispatch });
91
+ (controller as any).getState = makeState('test.com', Date.now());
116
92
 
117
- it('should call after period', () => {
118
- dispatch.mockReset();
119
- jest.advanceTimersByTime(5000);
120
- expect(dispatch.mock.calls.length).toBe(1);
121
- dispatch.mock.calls[0].forEach((element: any) => {
122
- delete element?.meta?.createdAt;
123
- });
124
- expect(dispatch.mock.calls[0]).toMatchSnapshot();
125
- jest.advanceTimersByTime(5000);
126
- expect(dispatch.mock.calls.length).toBe(2);
127
- dispatch.mock.calls[1].forEach((element: any) => {
128
- delete element?.meta?.createdAt;
93
+ jest.useFakeTimers();
94
+ const sub2 = new PollingSubscription(
95
+ createSubscription(endpoint, { args: [] }),
96
+ controller,
97
+ );
98
+ expect(dispatch.mock.calls.length).toBe(0);
99
+ jest.advanceTimersByTime(4990);
100
+ expect(dispatch.mock.calls.length).toBe(0);
101
+ jest.advanceTimersByTime(20);
102
+ expect(dispatch.mock.calls.length).toBe(1);
103
+ jest.advanceTimersByTime(5000);
104
+ expect(dispatch.mock.calls.length).toBe(2);
105
+ jest.advanceTimersByTime(2000);
106
+ expect(dispatch.mock.calls.length).toBe(2);
107
+ sub2.cleanup();
108
+ jest.useRealTimers();
129
109
  });
130
110
 
131
- expect(dispatch.mock.calls[1]).toMatchSnapshot();
132
- });
111
+ it('should only run once with multiple simultaneous starts', () => {
112
+ const dispatch = jest.fn();
113
+ const controller = new Controller({ dispatch });
114
+ (controller as any).getState = () => initialState;
133
115
 
134
- describe('add()', () => {
135
- it('should take smaller frequency when another is added', () => {
136
- sub.add(1000);
137
- jest.advanceTimersByTime(1000 * 4);
138
- expect(dispatch.mock.calls.length).toBe(2 + 4);
116
+ jest.useFakeTimers();
117
+ const sub2 = new PollingSubscription(
118
+ createSubscription(endpoint, { args: [] }),
119
+ controller,
120
+ );
121
+ sub2.add(1000);
122
+ sub2.add(1000);
123
+ sub2.add(1000);
124
+ jest.advanceTimersByTime(1);
125
+ expect(dispatch.mock.calls.length).toBe(1);
126
+ jest.advanceTimersByTime(999);
127
+ expect(dispatch.mock.calls.length).toBe(2);
128
+ jest.advanceTimersByTime(10);
129
+ sub2.remove(1000);
130
+ sub2.remove(1000);
131
+ sub2.remove(1000);
132
+ sub2.cleanup();
133
+ jest.useRealTimers();
139
134
  });
135
+ });
140
136
 
141
- it('should not change frequency if same is added', () => {
142
- dispatch.mockClear();
143
- sub.add(1000);
144
- jest.advanceTimersByTime(1000 * 13);
145
- expect(dispatch.mock.calls.length).toBe(13);
137
+ describe('fresh data', () => {
138
+ const dispatch = jest.fn();
139
+ const controller = new Controller({ dispatch });
140
+ (controller as any).getState = makeState('test.com', 0);
141
+ let sub: PollingSubscription;
142
+
143
+ beforeAll(() => {
144
+ jest.useFakeTimers();
145
+ sub = new PollingSubscription(
146
+ createSubscription(endpoint, { args: [] }),
147
+ controller,
148
+ );
146
149
  });
147
-
148
- it('should not change frequency if larger is added', () => {
149
- dispatch.mockClear();
150
- sub.add(7000);
151
- sub.add(8000);
152
- jest.advanceTimersByTime(1000 * 13);
153
- expect(dispatch.mock.calls.length).toBe(13);
150
+ afterAll(() => {
151
+ sub.cleanup();
152
+ jest.useRealTimers();
154
153
  });
155
154
 
156
- it('should do nothing if frequency is undefined', () => {
157
- dispatch.mockClear();
158
- sub.add(undefined);
159
- jest.advanceTimersByTime(1000 * 13);
160
- expect(dispatch.mock.calls.length).toBe(13);
155
+ it('should throw on undefined frequency in construction', () => {
156
+ expect(
157
+ () =>
158
+ new PollingSubscription(
159
+ createSubscription(
160
+ new Endpoint(fetch, {
161
+ schema: Article,
162
+ key: () => 'test.com',
163
+ }),
164
+ { args: [] },
165
+ ),
166
+ controller,
167
+ ),
168
+ ).toThrow();
161
169
  });
162
- });
163
170
 
164
- describe('remove()', () => {
165
- it('should not change frequency if only partially removed', () => {
166
- dispatch.mockClear();
167
- sub.remove(1000);
168
- jest.advanceTimersByTime(1000 * 13);
169
- expect(dispatch.mock.calls.length).toBe(13);
171
+ it('should call immediately', () => {
172
+ jest.advanceTimersByTime(1);
173
+ expect(dispatch.mock.calls.length).toBe(1);
170
174
  });
171
175
 
172
- it('should not change frequency if only larger removed', () => {
173
- dispatch.mockClear();
174
- sub.remove(7000);
175
- jest.advanceTimersByTime(1000 * 13);
176
- expect(dispatch.mock.calls.length).toBe(13);
177
- });
176
+ it('should call after period', () => {
177
+ dispatch.mockReset();
178
+ jest.advanceTimersByTime(5000);
179
+ expect(dispatch.mock.calls.length).toBe(1);
180
+ dispatch.mock.calls[0].forEach((element: any) => {
181
+ delete element?.meta?.createdAt;
182
+ });
183
+ expect(dispatch.mock.calls[0]).toMatchSnapshot();
184
+ jest.advanceTimersByTime(5000);
185
+ expect(dispatch.mock.calls.length).toBe(2);
186
+ dispatch.mock.calls[1].forEach((element: any) => {
187
+ delete element?.meta?.createdAt;
188
+ });
178
189
 
179
- it('should go back to fastest if smallest frequency is removed completely', () => {
180
- sub.remove(1000);
181
- jest.advanceTimersByTime(1000);
182
- dispatch.mockClear();
183
- jest.advanceTimersByTime(5000 * 13);
184
- expect(dispatch.mock.calls.length).toBe(13);
190
+ expect(dispatch.mock.calls[1]).toMatchSnapshot();
185
191
  });
186
192
 
187
- it('should do nothing if frequency is not registered', () => {
188
- const oldError = console.error;
189
- const spy = (console.error = jest.fn());
190
-
191
- sub.remove(1000);
192
- dispatch.mockClear();
193
- jest.advanceTimersByTime(5000 * 13);
194
- expect(dispatch.mock.calls.length).toBe(13);
195
-
196
- expect(spy.mock.calls[0]).toMatchInlineSnapshot(`
197
- [
198
- "Mismatched remove: 1000 is not subscribed for test.com",
199
- ]
200
- `);
201
- console.error = oldError;
193
+ describe('add()', () => {
194
+ it('should take smaller frequency when another is added', () => {
195
+ sub.add(1000);
196
+ jest.advanceTimersByTime(1000 * 4);
197
+ expect(dispatch.mock.calls.length).toBe(2 + 4);
198
+ });
199
+
200
+ it('should not change frequency if same is added', () => {
201
+ dispatch.mockClear();
202
+ sub.add(1000);
203
+ jest.advanceTimersByTime(1000 * 13);
204
+ expect(dispatch.mock.calls.length).toBe(13);
205
+ });
206
+
207
+ it('should not change frequency if larger is added', () => {
208
+ dispatch.mockClear();
209
+ sub.add(7000);
210
+ sub.add(8000);
211
+ jest.advanceTimersByTime(1000 * 13);
212
+ expect(dispatch.mock.calls.length).toBe(13);
213
+ });
214
+
215
+ it('should do nothing if frequency is undefined', () => {
216
+ dispatch.mockClear();
217
+ sub.add(undefined);
218
+ jest.advanceTimersByTime(1000 * 13);
219
+ expect(dispatch.mock.calls.length).toBe(13);
220
+ });
202
221
  });
203
222
 
204
- it('should do nothing if frequency is undefined', () => {
205
- sub.remove(undefined);
206
- dispatch.mockClear();
207
- jest.advanceTimersByTime(5000 * 13);
208
- expect(dispatch.mock.calls.length).toBe(13);
223
+ describe('remove()', () => {
224
+ it('should not change frequency if only partially removed', () => {
225
+ dispatch.mockClear();
226
+ sub.remove(1000);
227
+ jest.advanceTimersByTime(1000 * 13);
228
+ expect(dispatch.mock.calls.length).toBe(13);
229
+ });
230
+
231
+ it('should not change frequency if only larger removed', () => {
232
+ dispatch.mockClear();
233
+ sub.remove(7000);
234
+ jest.advanceTimersByTime(1000 * 13);
235
+ expect(dispatch.mock.calls.length).toBe(13);
236
+ });
237
+
238
+ it('should go back to fastest if smallest frequency is removed completely', () => {
239
+ sub.remove(1000);
240
+ jest.advanceTimersByTime(1000);
241
+ dispatch.mockClear();
242
+ jest.advanceTimersByTime(5000 * 13);
243
+ expect(dispatch.mock.calls.length).toBe(13);
244
+ });
245
+
246
+ it('should do nothing if frequency is not registered', () => {
247
+ const oldError = console.error;
248
+ const spy = (console.error = jest.fn());
249
+
250
+ sub.remove(1000);
251
+ dispatch.mockClear();
252
+ jest.advanceTimersByTime(5000 * 13);
253
+ expect(dispatch.mock.calls.length).toBe(13);
254
+
255
+ expect(spy.mock.calls[0]).toMatchInlineSnapshot(`
256
+ [
257
+ "Mismatched remove: 1000 is not subscribed for test.com",
258
+ ]
259
+ `);
260
+ console.error = oldError;
261
+ });
262
+
263
+ it('should do nothing if frequency is undefined', () => {
264
+ sub.remove(undefined);
265
+ dispatch.mockClear();
266
+ jest.advanceTimersByTime(5000 * 13);
267
+ expect(dispatch.mock.calls.length).toBe(13);
268
+ });
269
+
270
+ it('should return false until completely empty, then return true', () => {
271
+ const controller = new Controller({ dispatch });
272
+ (controller as any).getState = makeState('test.com', 0);
273
+
274
+ const sub = new PollingSubscription(
275
+ createSubscription(endpoint, { args: [] }),
276
+ controller,
277
+ );
278
+ sub.add(5000);
279
+ sub.add(7000);
280
+ expect(sub.remove(5000)).toBe(false);
281
+ expect(sub.remove(5000)).toBe(false);
282
+ expect(sub.remove(7000)).toBe(true);
283
+ });
209
284
  });
210
285
 
211
- it('should return false until completely empty, then return true', () => {
212
- const sub = new PollingSubscription(
213
- {
214
- key: 'test.com',
215
- schema: PollingArticleResource,
216
- fetch,
217
- frequency: 5000,
218
- getState: () => initialState,
219
- },
220
- dispatch,
221
- );
222
- sub.add(5000);
223
- sub.add(7000);
224
- expect(sub.remove(5000)).toBe(false);
225
- expect(sub.remove(5000)).toBe(false);
226
- expect(sub.remove(7000)).toBe(true);
286
+ describe('cleanup()', () => {
287
+ let warnSpy: jest.SpyInstance;
288
+ afterEach(() => {
289
+ warnSpy.mockRestore();
290
+ });
291
+ beforeEach(() => (warnSpy = jest.spyOn(console, 'warn')));
292
+
293
+ it('should stop all timers', () => {
294
+ dispatch.mockClear();
295
+ sub.cleanup();
296
+ jest.advanceTimersByTime(5000 * 13);
297
+ expect(dispatch.mock.calls.length).toBe(0);
298
+ });
299
+ it('should be idempotent', () => {
300
+ sub.cleanup();
301
+ });
302
+ it('should not run even if interval not cancelled', () => {
303
+ const controller = new Controller({ dispatch });
304
+ (controller as any).getState = makeState('test.com', 0);
305
+
306
+ sub.cleanup();
307
+ sub = new PollingSubscription(
308
+ createSubscription(endpoint.extend({ key: () => 'test.com2' }), {
309
+ args: [],
310
+ }),
311
+ controller,
312
+ );
313
+ sub.add(5000);
314
+ jest.runOnlyPendingTimers();
315
+ delete (sub as any).intervalId;
316
+ jest.advanceTimersByTime(5000 * 13);
317
+
318
+ expect(dispatch.mock.calls.length).toBe(1);
319
+ expect(warnSpy.mock.calls.length).toBe(13);
320
+ expect(warnSpy.mock.calls[0]).toMatchSnapshot();
321
+ });
227
322
  });
228
323
  });
229
324
 
230
- describe('cleanup()', () => {
231
- it('should stop all timers', () => {
232
- dispatch.mockClear();
233
- sub.cleanup();
234
- jest.advanceTimersByTime(5000 * 13);
235
- expect(dispatch.mock.calls.length).toBe(0);
325
+ describe('offline support', () => {
326
+ beforeAll(() => {
327
+ jest.useFakeTimers();
236
328
  });
237
- it('should be idempotent', () => {
238
- sub.cleanup();
329
+ afterAll(() => {
330
+ jest.useRealTimers();
239
331
  });
240
- });
241
332
 
242
- describe('offline support', () => {
243
333
  function createMocks(listener: ConnectionListener) {
244
334
  const dispatch = jest.fn();
245
335
  const a = () => Promise.resolve({ id: 5, title: 'hi' });
246
336
  const fetch = jest.fn(a);
337
+ const endpoint = new Endpoint(fetch, {
338
+ schema: Article,
339
+ key: () => 'test.com',
340
+ pollFrequency: 5000,
341
+ });
342
+ const controller = new Controller({ dispatch });
343
+ (controller as any).getState = makeState('test.com', 0);
247
344
 
248
345
  const pollingSubscription = new PollingSubscription(
249
- {
250
- key: 'test.com',
251
- schema: PollingArticleResource,
252
- fetch,
253
- frequency: 5000,
254
- getState: () => initialState,
255
- },
256
- dispatch,
346
+ createSubscription(endpoint, {
347
+ args: [],
348
+ }),
349
+ controller,
257
350
  listener,
258
351
  );
259
352
  jest.advanceTimersByTime(1);
@@ -298,6 +391,21 @@ describe('PollingSubscription', () => {
298
391
  expect(listener.onlineHandlers.length).toBe(0);
299
392
  });
300
393
 
394
+ it('should not run when timeoutId is deleted after coming online', () => {
395
+ const listener = new MockConnectionListener(false);
396
+ const { dispatch, pollingSubscription } = createMocks(listener);
397
+ expect(dispatch.mock.calls.length).toBe(0);
398
+
399
+ listener.trigger('online');
400
+ delete (pollingSubscription as any).startId;
401
+ jest.advanceTimersByTime(1);
402
+ expect(dispatch.mock.calls.length).toBe(0);
403
+ jest.advanceTimersByTime(5000);
404
+ expect(dispatch.mock.calls.length).toBe(0);
405
+ expect(listener.offlineHandlers.length).toBe(1);
406
+ expect(listener.onlineHandlers.length).toBe(0);
407
+ });
408
+
301
409
  it('should stop dispatching when offline again', () => {
302
410
  const listener = new MockConnectionListener(true);
303
411
  const { dispatch } = createMocks(listener);