@data-client/core 0.1.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.
Files changed (308) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +71 -0
  3. package/dist/index.js +1643 -0
  4. package/dist/index.umd.min.js +1 -0
  5. package/dist/next.js +461 -0
  6. package/dist/package.json +1 -0
  7. package/legacy/actionTypes.js +12 -0
  8. package/legacy/compatibleActions.js +2 -0
  9. package/legacy/controller/BaseController.js +289 -0
  10. package/legacy/controller/Controller.js +20 -0
  11. package/legacy/controller/createFetch.js +42 -0
  12. package/legacy/controller/createInvalidate.js +12 -0
  13. package/legacy/controller/createInvalidateAll.js +8 -0
  14. package/legacy/controller/createOptimistic.js +33 -0
  15. package/legacy/controller/createReceive.js +36 -0
  16. package/legacy/controller/createReset.js +8 -0
  17. package/legacy/controller/createSubscription.js +30 -0
  18. package/legacy/controller/types.js +2 -0
  19. package/legacy/endpoint/index.js +2 -0
  20. package/legacy/endpoint/shapes.js +2 -0
  21. package/legacy/endpoint/types.js +2 -0
  22. package/legacy/fsa.js +2 -0
  23. package/legacy/index.js +22 -0
  24. package/legacy/internal.js +4 -0
  25. package/legacy/legacyActions.js +2 -0
  26. package/legacy/manager/ConnectionListener.js +2 -0
  27. package/legacy/manager/DefaultConnectionListener.js +40 -0
  28. package/legacy/manager/DevtoolsManager.js +73 -0
  29. package/legacy/manager/LogoutManager.js +34 -0
  30. package/legacy/manager/NetworkManager.js +291 -0
  31. package/legacy/manager/PollingSubscription.js +159 -0
  32. package/legacy/manager/SubscriptionManager.js +117 -0
  33. package/legacy/manager/applyManager.js +23 -0
  34. package/legacy/manager/devtoolsTypes.js +2 -0
  35. package/legacy/manager/index.js +6 -0
  36. package/legacy/middlewareTypes.js +2 -0
  37. package/legacy/newActions.js +2 -0
  38. package/legacy/next/Controller.js +24 -0
  39. package/legacy/next/index.js +3 -0
  40. package/legacy/previousActions.js +2 -0
  41. package/legacy/state/RIC.js +3 -0
  42. package/legacy/state/applyUpdatersToResults.js +4 -0
  43. package/legacy/state/legacy-actions/createFetch.js +62 -0
  44. package/legacy/state/legacy-actions/createReceive.js +37 -0
  45. package/legacy/state/legacy-actions/createReceiveError.js +28 -0
  46. package/legacy/state/legacy-actions/index.js +4 -0
  47. package/legacy/state/reducer/createReducer.js +54 -0
  48. package/legacy/state/reducer/fetchReducer.js +32 -0
  49. package/legacy/state/reducer/invalidateReducer.js +28 -0
  50. package/legacy/state/reducer/setReducer.js +113 -0
  51. package/legacy/state/reducerInstance.js +9 -0
  52. package/legacy/state/selectMeta.js +4 -0
  53. package/legacy/types.js +8 -0
  54. package/lib/actionTypes.d.ts +11 -0
  55. package/lib/actionTypes.d.ts.map +1 -0
  56. package/lib/actionTypes.js +12 -0
  57. package/lib/compatibleActions.d.ts +47 -0
  58. package/lib/compatibleActions.d.ts.map +1 -0
  59. package/lib/compatibleActions.js +2 -0
  60. package/lib/controller/BaseController.d.ts +128 -0
  61. package/lib/controller/BaseController.d.ts.map +1 -0
  62. package/lib/controller/BaseController.js +289 -0
  63. package/lib/controller/Controller.d.ts +14 -0
  64. package/lib/controller/Controller.d.ts.map +1 -0
  65. package/lib/controller/Controller.js +20 -0
  66. package/lib/controller/createFetch.d.ts +12 -0
  67. package/lib/controller/createFetch.d.ts.map +1 -0
  68. package/lib/controller/createFetch.js +42 -0
  69. package/lib/controller/createInvalidate.d.ts +6 -0
  70. package/lib/controller/createInvalidate.d.ts.map +1 -0
  71. package/lib/controller/createInvalidate.js +12 -0
  72. package/lib/controller/createInvalidateAll.d.ts +3 -0
  73. package/lib/controller/createInvalidateAll.d.ts.map +1 -0
  74. package/lib/controller/createInvalidateAll.js +8 -0
  75. package/lib/controller/createOptimistic.d.ts +10 -0
  76. package/lib/controller/createOptimistic.d.ts.map +1 -0
  77. package/lib/controller/createOptimistic.js +33 -0
  78. package/lib/controller/createReceive.d.ts +20 -0
  79. package/lib/controller/createReceive.d.ts.map +1 -0
  80. package/lib/controller/createReceive.js +36 -0
  81. package/lib/controller/createReset.d.ts +3 -0
  82. package/lib/controller/createReset.d.ts.map +1 -0
  83. package/lib/controller/createReset.js +8 -0
  84. package/lib/controller/createSubscription.d.ts +9 -0
  85. package/lib/controller/createSubscription.d.ts.map +1 -0
  86. package/lib/controller/createSubscription.js +30 -0
  87. package/lib/controller/types.d.ts +6 -0
  88. package/lib/controller/types.d.ts.map +1 -0
  89. package/lib/controller/types.js +2 -0
  90. package/lib/endpoint/index.d.ts +3 -0
  91. package/lib/endpoint/index.d.ts.map +1 -0
  92. package/lib/endpoint/index.js +2 -0
  93. package/lib/endpoint/shapes.d.ts +25 -0
  94. package/lib/endpoint/shapes.d.ts.map +1 -0
  95. package/lib/endpoint/shapes.js +2 -0
  96. package/lib/endpoint/types.d.ts +45 -0
  97. package/lib/endpoint/types.d.ts.map +1 -0
  98. package/lib/endpoint/types.js +2 -0
  99. package/lib/fsa.d.ts +41 -0
  100. package/lib/fsa.d.ts.map +1 -0
  101. package/lib/fsa.js +2 -0
  102. package/lib/index.d.ts +19 -0
  103. package/lib/index.d.ts.map +1 -0
  104. package/lib/index.js +22 -0
  105. package/lib/internal.d.ts +4 -0
  106. package/lib/internal.d.ts.map +1 -0
  107. package/lib/internal.js +4 -0
  108. package/lib/legacyActions.d.ts +92 -0
  109. package/lib/legacyActions.d.ts.map +1 -0
  110. package/lib/legacyActions.js +2 -0
  111. package/lib/manager/ConnectionListener.d.ts +8 -0
  112. package/lib/manager/ConnectionListener.d.ts.map +1 -0
  113. package/lib/manager/ConnectionListener.js +2 -0
  114. package/lib/manager/DefaultConnectionListener.d.ts +20 -0
  115. package/lib/manager/DefaultConnectionListener.d.ts.map +1 -0
  116. package/lib/manager/DefaultConnectionListener.js +40 -0
  117. package/lib/manager/DevtoolsManager.d.ts +24 -0
  118. package/lib/manager/DevtoolsManager.d.ts.map +1 -0
  119. package/lib/manager/DevtoolsManager.js +74 -0
  120. package/lib/manager/LogoutManager.d.ts +25 -0
  121. package/lib/manager/LogoutManager.d.ts.map +1 -0
  122. package/lib/manager/LogoutManager.js +34 -0
  123. package/lib/manager/NetworkManager.d.ts +82 -0
  124. package/lib/manager/NetworkManager.d.ts.map +1 -0
  125. package/lib/manager/NetworkManager.js +295 -0
  126. package/lib/manager/PollingSubscription.d.ts +45 -0
  127. package/lib/manager/PollingSubscription.d.ts.map +1 -0
  128. package/lib/manager/PollingSubscription.js +159 -0
  129. package/lib/manager/SubscriptionManager.d.ts +55 -0
  130. package/lib/manager/SubscriptionManager.d.ts.map +1 -0
  131. package/lib/manager/SubscriptionManager.js +117 -0
  132. package/lib/manager/applyManager.d.ts +10 -0
  133. package/lib/manager/applyManager.d.ts.map +1 -0
  134. package/lib/manager/applyManager.js +23 -0
  135. package/lib/manager/devtoolsTypes.d.ts +205 -0
  136. package/lib/manager/devtoolsTypes.d.ts.map +1 -0
  137. package/lib/manager/devtoolsTypes.js +2 -0
  138. package/lib/manager/index.d.ts +8 -0
  139. package/lib/manager/index.d.ts.map +1 -0
  140. package/lib/manager/index.js +6 -0
  141. package/lib/middlewareTypes.d.ts +18 -0
  142. package/lib/middlewareTypes.d.ts.map +1 -0
  143. package/lib/middlewareTypes.js +2 -0
  144. package/lib/newActions.d.ts +85 -0
  145. package/lib/newActions.d.ts.map +1 -0
  146. package/lib/newActions.js +2 -0
  147. package/lib/next/Controller.d.ts +14 -0
  148. package/lib/next/Controller.d.ts.map +1 -0
  149. package/lib/next/Controller.js +24 -0
  150. package/lib/next/index.d.ts +3 -0
  151. package/lib/next/index.d.ts.map +1 -0
  152. package/lib/next/index.js +3 -0
  153. package/lib/previousActions.d.ts +91 -0
  154. package/lib/previousActions.d.ts.map +1 -0
  155. package/lib/previousActions.js +2 -0
  156. package/lib/state/RIC.d.ts +2 -0
  157. package/lib/state/RIC.js +3 -0
  158. package/lib/state/applyUpdatersToResults.d.ts +13 -0
  159. package/lib/state/applyUpdatersToResults.d.ts.map +1 -0
  160. package/lib/state/applyUpdatersToResults.js +7 -0
  161. package/lib/state/legacy-actions/createFetch.d.ts +19 -0
  162. package/lib/state/legacy-actions/createFetch.d.ts.map +1 -0
  163. package/lib/state/legacy-actions/createFetch.js +62 -0
  164. package/lib/state/legacy-actions/createReceive.d.ts +14 -0
  165. package/lib/state/legacy-actions/createReceive.d.ts.map +1 -0
  166. package/lib/state/legacy-actions/createReceive.js +37 -0
  167. package/lib/state/legacy-actions/createReceiveError.d.ts +9 -0
  168. package/lib/state/legacy-actions/createReceiveError.d.ts.map +1 -0
  169. package/lib/state/legacy-actions/createReceiveError.js +28 -0
  170. package/lib/state/legacy-actions/index.d.ts +4 -0
  171. package/lib/state/legacy-actions/index.d.ts.map +1 -0
  172. package/lib/state/legacy-actions/index.js +4 -0
  173. package/lib/state/reducer/createReducer.d.ts +7 -0
  174. package/lib/state/reducer/createReducer.d.ts.map +1 -0
  175. package/lib/state/reducer/createReducer.js +55 -0
  176. package/lib/state/reducer/fetchReducer.d.ts +4 -0
  177. package/lib/state/reducer/fetchReducer.d.ts.map +1 -0
  178. package/lib/state/reducer/fetchReducer.js +34 -0
  179. package/lib/state/reducer/invalidateReducer.d.ts +37 -0
  180. package/lib/state/reducer/invalidateReducer.d.ts.map +1 -0
  181. package/lib/state/reducer/invalidateReducer.js +34 -0
  182. package/lib/state/reducer/setReducer.d.ts +40 -0
  183. package/lib/state/reducer/setReducer.d.ts.map +1 -0
  184. package/lib/state/reducer/setReducer.js +119 -0
  185. package/lib/state/reducerInstance.d.ts +7 -0
  186. package/lib/state/reducerInstance.d.ts.map +1 -0
  187. package/lib/state/reducerInstance.js +9 -0
  188. package/lib/state/selectMeta.d.ts +3 -0
  189. package/lib/state/selectMeta.d.ts.map +1 -0
  190. package/lib/state/selectMeta.js +4 -0
  191. package/lib/types.d.ts +71 -0
  192. package/lib/types.d.ts.map +1 -0
  193. package/lib/types.js +8 -0
  194. package/node.mjs +1 -0
  195. package/package.json +127 -0
  196. package/src/actionTypes.ts +11 -0
  197. package/src/compatibleActions.ts +96 -0
  198. package/src/controller/BaseController.ts +508 -0
  199. package/src/controller/Controller.ts +32 -0
  200. package/src/controller/__tests__/Controller.ts +29 -0
  201. package/src/controller/__tests__/__snapshots__/getResponse.ts.snap +35 -0
  202. package/src/controller/__tests__/getResponse.ts +182 -0
  203. package/src/controller/createFetch.ts +54 -0
  204. package/src/controller/createInvalidate.ts +16 -0
  205. package/src/controller/createInvalidateAll.ts +11 -0
  206. package/src/controller/createOptimistic.ts +47 -0
  207. package/src/controller/createReceive.ts +85 -0
  208. package/src/controller/createReset.ts +9 -0
  209. package/src/controller/createSubscription.ts +39 -0
  210. package/src/controller/types.ts +22 -0
  211. package/src/endpoint/index.ts +14 -0
  212. package/src/endpoint/shapes.ts +53 -0
  213. package/src/endpoint/types.ts +72 -0
  214. package/src/fsa.ts +99 -0
  215. package/src/index.ts +61 -0
  216. package/src/internal.ts +3 -0
  217. package/src/legacyActions.ts +163 -0
  218. package/src/manager/ConnectionListener.ts +7 -0
  219. package/src/manager/DefaultConnectionListener.ts +54 -0
  220. package/src/manager/DevtoolsManager.ts +99 -0
  221. package/src/manager/LogoutManager.ts +57 -0
  222. package/src/manager/NetworkManager.ts +346 -0
  223. package/src/manager/PollingSubscription.ts +190 -0
  224. package/src/manager/SubscriptionManager.ts +156 -0
  225. package/src/manager/__tests__/__snapshots__/pollingSubscription-endpoint.ts.snap +49 -0
  226. package/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap +43 -0
  227. package/src/manager/__tests__/logoutManager.ts +112 -0
  228. package/src/manager/__tests__/manager.ts +44 -0
  229. package/src/manager/__tests__/networkManager-legacy.ts +394 -0
  230. package/src/manager/__tests__/networkManager.ts +426 -0
  231. package/src/manager/__tests__/pollingSubscription-endpoint.ts +423 -0
  232. package/src/manager/__tests__/pollingSubscription.ts +313 -0
  233. package/src/manager/__tests__/subscriptionManager.ts +208 -0
  234. package/src/manager/applyManager.ts +33 -0
  235. package/src/manager/devtoolsTypes.ts +210 -0
  236. package/src/manager/index.ts +7 -0
  237. package/src/middlewareTypes.ts +49 -0
  238. package/src/newActions.ts +140 -0
  239. package/src/next/Controller.ts +39 -0
  240. package/src/next/index.ts +2 -0
  241. package/src/package.json +1 -0
  242. package/src/previousActions.ts +159 -0
  243. package/src/state/RIC.d.ts +2 -0
  244. package/src/state/RIC.js +5 -0
  245. package/src/state/__tests__/RIC.web.ts +16 -0
  246. package/src/state/__tests__/__snapshots__/reducer.ts.snap +56 -0
  247. package/src/state/__tests__/applyUpdatersToResults.ts +40 -0
  248. package/src/state/__tests__/reducer.ts +868 -0
  249. package/src/state/applyUpdatersToResults.ts +29 -0
  250. package/src/state/legacy-actions/createFetch.ts +95 -0
  251. package/src/state/legacy-actions/createReceive.ts +68 -0
  252. package/src/state/legacy-actions/createReceiveError.ts +43 -0
  253. package/src/state/legacy-actions/index.ts +3 -0
  254. package/src/state/reducer/createReducer.ts +80 -0
  255. package/src/state/reducer/fetchReducer.ts +48 -0
  256. package/src/state/reducer/invalidateReducer.ts +39 -0
  257. package/src/state/reducer/setReducer.ts +157 -0
  258. package/src/state/reducerInstance.ts +14 -0
  259. package/src/state/selectMeta.ts +8 -0
  260. package/src/types.ts +125 -0
  261. package/ts3.4/actionTypes.d.ts +11 -0
  262. package/ts3.4/compatibleActions.d.ts +47 -0
  263. package/ts3.4/controller/BaseController.d.ts +170 -0
  264. package/ts3.4/controller/Controller.d.ts +14 -0
  265. package/ts3.4/controller/createFetch.d.ts +14 -0
  266. package/ts3.4/controller/createInvalidate.d.ts +8 -0
  267. package/ts3.4/controller/createInvalidateAll.d.ts +3 -0
  268. package/ts3.4/controller/createOptimistic.d.ts +12 -0
  269. package/ts3.4/controller/createReceive.d.ts +24 -0
  270. package/ts3.4/controller/createReset.d.ts +3 -0
  271. package/ts3.4/controller/createSubscription.d.ts +13 -0
  272. package/ts3.4/controller/types.d.ts +6 -0
  273. package/ts3.4/endpoint/index.d.ts +3 -0
  274. package/ts3.4/endpoint/shapes.d.ts +25 -0
  275. package/ts3.4/endpoint/types.d.ts +45 -0
  276. package/ts3.4/fsa.d.ts +41 -0
  277. package/ts3.4/index.d.ts +22 -0
  278. package/ts3.4/internal.d.ts +4 -0
  279. package/ts3.4/legacyActions.d.ts +95 -0
  280. package/ts3.4/manager/ConnectionListener.d.ts +8 -0
  281. package/ts3.4/manager/DefaultConnectionListener.d.ts +20 -0
  282. package/ts3.4/manager/DevtoolsManager.d.ts +24 -0
  283. package/ts3.4/manager/LogoutManager.d.ts +25 -0
  284. package/ts3.4/manager/NetworkManager.d.ts +82 -0
  285. package/ts3.4/manager/PollingSubscription.d.ts +45 -0
  286. package/ts3.4/manager/SubscriptionManager.d.ts +55 -0
  287. package/ts3.4/manager/applyManager.d.ts +10 -0
  288. package/ts3.4/manager/devtoolsTypes.d.ts +205 -0
  289. package/ts3.4/manager/index.d.ts +8 -0
  290. package/ts3.4/middlewareTypes.d.ts +18 -0
  291. package/ts3.4/newActions.d.ts +88 -0
  292. package/ts3.4/next/Controller.d.ts +14 -0
  293. package/ts3.4/next/index.d.ts +3 -0
  294. package/ts3.4/previousActions.d.ts +94 -0
  295. package/ts3.4/state/RIC.d.ts +2 -0
  296. package/ts3.4/state/applyUpdatersToResults.d.ts +13 -0
  297. package/ts3.4/state/legacy-actions/createFetch.d.ts +19 -0
  298. package/ts3.4/state/legacy-actions/createReceive.d.ts +14 -0
  299. package/ts3.4/state/legacy-actions/createReceiveError.d.ts +9 -0
  300. package/ts3.4/state/legacy-actions/index.d.ts +4 -0
  301. package/ts3.4/state/reducer/createReducer.d.ts +7 -0
  302. package/ts3.4/state/reducer/fetchReducer.d.ts +4 -0
  303. package/ts3.4/state/reducer/invalidateReducer.d.ts +37 -0
  304. package/ts3.4/state/reducer/setReducer.d.ts +40 -0
  305. package/ts3.4/state/reducerInstance.d.ts +7 -0
  306. package/ts3.4/state/selectMeta.d.ts +3 -0
  307. package/ts3.4/types.d.ts +73 -0
  308. package/typescript.svg +8 -0
@@ -0,0 +1,49 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`PollingSubscription fresh data cleanup() should not run even if interval not cancelled 1`] = `
4
+ [
5
+ "Poll intervalId for test.com2 still running, but intervalId deleted",
6
+ ]
7
+ `;
8
+
9
+ exports[`PollingSubscription fresh data should call after period 1`] = `
10
+ [
11
+ {
12
+ "endpoint": [Function],
13
+ "meta": {
14
+ "args": [],
15
+ "key": "test.com",
16
+ "options": [Function],
17
+ "promise": Promise {},
18
+ "reject": [Function],
19
+ "resolve": [Function],
20
+ "schema": [Function],
21
+ "throttle": true,
22
+ "type": "read",
23
+ },
24
+ "payload": [Function],
25
+ "type": "rest-hooks/fetch",
26
+ },
27
+ ]
28
+ `;
29
+
30
+ exports[`PollingSubscription fresh data should call after period 2`] = `
31
+ [
32
+ {
33
+ "endpoint": [Function],
34
+ "meta": {
35
+ "args": [],
36
+ "key": "test.com",
37
+ "options": [Function],
38
+ "promise": Promise {},
39
+ "reject": [Function],
40
+ "resolve": [Function],
41
+ "schema": [Function],
42
+ "throttle": true,
43
+ "type": "read",
44
+ },
45
+ "payload": [Function],
46
+ "type": "rest-hooks/fetch",
47
+ },
48
+ ]
49
+ `;
@@ -0,0 +1,43 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`PollingSubscription should call after period 1`] = `
4
+ [
5
+ {
6
+ "endpoint": [Function],
7
+ "meta": {
8
+ "args": [],
9
+ "key": "test.com",
10
+ "options": [Function],
11
+ "promise": Promise {},
12
+ "reject": [Function],
13
+ "resolve": [Function],
14
+ "schema": [Function],
15
+ "throttle": true,
16
+ "type": "read",
17
+ },
18
+ "payload": [Function],
19
+ "type": "rest-hooks/fetch",
20
+ },
21
+ ]
22
+ `;
23
+
24
+ exports[`PollingSubscription should call after period 2`] = `
25
+ [
26
+ {
27
+ "endpoint": [Function],
28
+ "meta": {
29
+ "args": [],
30
+ "key": "test.com",
31
+ "options": [Function],
32
+ "promise": Promise {},
33
+ "reject": [Function],
34
+ "resolve": [Function],
35
+ "schema": [Function],
36
+ "throttle": true,
37
+ "type": "read",
38
+ },
39
+ "payload": [Function],
40
+ "type": "rest-hooks/fetch",
41
+ },
42
+ ]
43
+ `;
@@ -0,0 +1,112 @@
1
+ import { CoolerArticleResource } from '__tests__/new';
2
+
3
+ import { Controller, initialState } from '../..';
4
+ import { FETCH_TYPE, RESET_TYPE } from '../../actionTypes';
5
+ import createReceive from '../../controller/createReceive';
6
+ import LogoutManager from '../LogoutManager.js';
7
+
8
+ function onError(e: any) {
9
+ e.preventDefault();
10
+ }
11
+ beforeEach(() => {
12
+ if (typeof addEventListener === 'function')
13
+ addEventListener('error', onError);
14
+ });
15
+ afterEach(() => {
16
+ if (typeof removeEventListener === 'function')
17
+ removeEventListener('error', onError);
18
+ });
19
+
20
+ describe('LogoutManager', () => {
21
+ const manager = new LogoutManager();
22
+ const getState = () => initialState;
23
+
24
+ describe('getMiddleware()', () => {
25
+ it('should return the same value every call', () => {
26
+ const a = manager.getMiddleware();
27
+ expect(a).toBe(manager.getMiddleware());
28
+ expect(a).toBe(manager.getMiddleware());
29
+ });
30
+ });
31
+
32
+ describe('middleware', () => {
33
+ afterEach(() => {
34
+ jest.useRealTimers();
35
+ });
36
+ const middleware = manager.getMiddleware();
37
+ const next = jest.fn();
38
+ const dispatch = jest.fn(action => Promise.resolve());
39
+ const controller = new Controller({ dispatch, getState });
40
+ const API: Controller & { controller: Controller } = Object.create(
41
+ controller,
42
+ {
43
+ controller: { value: controller },
44
+ },
45
+ );
46
+ it('should ignore non-error receive', async () => {
47
+ const action = createReceive(CoolerArticleResource.get, {
48
+ args: [{ id: 5 }],
49
+ response: { id: 5, title: 'hi' },
50
+ });
51
+ await middleware(API)(next)(action);
52
+
53
+ expect(dispatch.mock.calls.length).toBe(0);
54
+ });
55
+ it('should ignore non-401 receive', async () => {
56
+ const error: any = new Error('network failed');
57
+ error.status = 404;
58
+ const action = createReceive(CoolerArticleResource.get, {
59
+ args: [{ id: 5 }],
60
+ response: error,
61
+ error: true,
62
+ });
63
+ await middleware(API)(next)(action);
64
+
65
+ expect(dispatch.mock.calls.length).toBe(0);
66
+ });
67
+ it('should dispatch reset on 401', async () => {
68
+ jest.setSystemTime(0);
69
+ const error: any = new Error('network failed');
70
+ error.status = 401;
71
+ const action = createReceive(CoolerArticleResource.get, {
72
+ args: [{ id: 5 }],
73
+ response: error,
74
+ error: true,
75
+ });
76
+ await middleware(API)(next)(action);
77
+
78
+ expect(dispatch.mock.calls.length).toBe(1);
79
+ expect(dispatch.mock.calls[0][0]?.type).toBe(RESET_TYPE);
80
+ });
81
+
82
+ it('should call custom handleLogout', async () => {
83
+ const handleLogout = jest.fn((controller: Controller) => {});
84
+ const localMiddleware = new LogoutManager({
85
+ shouldLogout(error) {
86
+ return error.status === 403;
87
+ },
88
+ handleLogout,
89
+ }).getMiddleware();
90
+ jest.setSystemTime(0);
91
+ const error: any = new Error('network failed');
92
+ error.status = 403;
93
+ const action = createReceive(CoolerArticleResource.get, {
94
+ args: [{ id: 5 }],
95
+ response: error,
96
+ error: true,
97
+ });
98
+ await localMiddleware(API)(next)(action);
99
+
100
+ expect(handleLogout.mock.calls.length).toBe(1);
101
+ });
102
+
103
+ it('should let other actions pass through', async () => {
104
+ const action = { type: FETCH_TYPE };
105
+ next.mockReset();
106
+
107
+ await middleware(API)(next)(action as any);
108
+
109
+ expect(next.mock.calls.length).toBe(1);
110
+ });
111
+ });
112
+ });
@@ -0,0 +1,44 @@
1
+ import Controller from '../../controller/Controller';
2
+ import { Middleware } from '../../middlewareTypes';
3
+ import { CombinedActionTypes } from '../../types';
4
+ import NetworkManager from '../NetworkManager';
5
+
6
+ const middleware: Middleware = new NetworkManager().getMiddleware();
7
+ it('middlewares should compose with non-rest-hooks middlewares', () => {
8
+ type AnotherAction = {
9
+ type: 'BOB';
10
+ payload: any;
11
+ };
12
+ const dispatch = jest.fn(
13
+ async (action: CombinedActionTypes | AnotherAction) => {},
14
+ );
15
+ const ctrl = new Controller({ dispatch });
16
+ const API: typeof ctrl & { controller: typeof ctrl } = Object.create(ctrl, {
17
+ controller: { value: ctrl },
18
+ });
19
+ type A = (typeof API)['dispatch'];
20
+ let counter = 0;
21
+ const nonRHMiddleware =
22
+ <
23
+ C extends {
24
+ dispatch: (action: AnotherAction) => Promise<void>;
25
+ },
26
+ >(
27
+ controller: C,
28
+ ) =>
29
+ (next: C['dispatch']): C['dispatch'] =>
30
+ async (action: AnotherAction) => {
31
+ next(action);
32
+ counter++;
33
+ };
34
+
35
+ const [a, b] = [middleware(API), nonRHMiddleware(API)];
36
+ const dispA = a(b(dispatch));
37
+ const dispB = b(a(dispatch));
38
+ expect(dispatch.mock.calls.length).toBe(0);
39
+ dispA({ type: 'BOB' as const, payload: 5 });
40
+ expect(dispatch.mock.calls.length).toBe(1);
41
+ dispB({ type: 'BOB' as const, payload: 5 });
42
+ expect(dispatch.mock.calls.length).toBe(2);
43
+ expect(counter).toBe(2);
44
+ });
@@ -0,0 +1,394 @@
1
+ import { ArticleResource } from '__tests__/legacy-3';
2
+
3
+ import { RECEIVE_TYPE } from '../../actionTypes';
4
+ import Controller from '../../controller/Controller';
5
+ import { FetchAction } from '../../legacyActions';
6
+ import { createFetch } from '../../state/legacy-actions';
7
+ import { initialState } from '../../state/reducer/createReducer';
8
+ import { Middleware } from '../../types';
9
+ import NetworkManager from '../NetworkManager';
10
+
11
+ describe('NetworkManager', () => {
12
+ const manager = new NetworkManager();
13
+ const getState = () => initialState;
14
+
15
+ afterAll(() => {
16
+ manager.cleanup();
17
+ });
18
+ let errorspy: jest.SpyInstance;
19
+ beforeEach(() => {
20
+ errorspy = jest.spyOn(global.console, 'error');
21
+ });
22
+ afterEach(() => {
23
+ errorspy.mockRestore();
24
+ });
25
+
26
+ it('getState() should have initialState before middleware run', () => {
27
+ class Hacked extends NetworkManager {
28
+ getHacked() {
29
+ return this.getState();
30
+ }
31
+ }
32
+ const hacked = new Hacked();
33
+ expect(hacked.getHacked()).toEqual(initialState);
34
+ });
35
+
36
+ describe('getMiddleware()', () => {
37
+ it('should return the same value every call', () => {
38
+ const a = manager.getMiddleware();
39
+ expect(a).toBe(manager.getMiddleware());
40
+ expect(a).toBe(manager.getMiddleware());
41
+ });
42
+ it('should return the different value for a different instance', () => {
43
+ const a = manager.getMiddleware();
44
+ const manager2 = new NetworkManager();
45
+ const a2 = manager2.getMiddleware();
46
+ expect(a).not.toBe(a2);
47
+ expect(a2).toBe(manager2.getMiddleware());
48
+ manager2.cleanup();
49
+ });
50
+ });
51
+
52
+ describe('middleware', () => {
53
+ const detailShape = ArticleResource.detailShape();
54
+ detailShape.fetch = () => Promise.resolve({ id: 5, title: 'hi' });
55
+ const fetchResolveAction = createFetch(detailShape, {
56
+ params: { id: 5 },
57
+ throttle: false,
58
+ });
59
+
60
+ const updaters = {
61
+ [ArticleResource.listShape().getFetchKey({})]:
62
+ () => (result: string[], oldResults: string[] | undefined) =>
63
+ [...(oldResults || []), result] as any,
64
+ };
65
+ const fetchReceiveWithUpdatersAction: FetchAction = {
66
+ ...fetchResolveAction,
67
+ meta: {
68
+ ...fetchResolveAction.meta,
69
+ updaters,
70
+ },
71
+ };
72
+
73
+ const updateShape = ArticleResource.updateShape();
74
+ updateShape.fetch = (params, body) => Promise.resolve(body);
75
+ const fetchRpcWithUpdatersAction = createFetch(updateShape, {
76
+ params: { id: 5 },
77
+ body: { id: 5, title: 'hi' },
78
+ throttle: false,
79
+ updateParams: [
80
+ [
81
+ ArticleResource.listShape(),
82
+ {},
83
+ () => (result: string[], oldResults: string[] | undefined) =>
84
+ [...(oldResults || []), result],
85
+ ],
86
+ ],
87
+ });
88
+ const partialUpdateShape = ArticleResource.partialUpdateShape();
89
+ partialUpdateShape.fetch = (params, body) => Promise.resolve(body);
90
+ const fetchRpcWithUpdatersAndOptimisticAction = createFetch(
91
+ partialUpdateShape,
92
+ {
93
+ params: { id: 5 },
94
+ body: { id: 5, title: 'hi' },
95
+ throttle: false,
96
+ updateParams: [
97
+ [
98
+ ArticleResource.listShape(),
99
+ {},
100
+ () => (result: string[], oldResults: string[] | undefined) =>
101
+ [...(oldResults || []), result],
102
+ ],
103
+ ],
104
+ },
105
+ );
106
+
107
+ const errorUpdateShape = ArticleResource.updateShape();
108
+ errorUpdateShape.fetch = () => Promise.reject(new Error('Failed'));
109
+ const fetchRejectAction = createFetch(errorUpdateShape, {
110
+ params: { id: 5 },
111
+ body: { id: 5, title: 'hi' },
112
+ throttle: false,
113
+ });
114
+ (fetchRejectAction.meta.promise as any).catch(e => {});
115
+
116
+ let NM: NetworkManager;
117
+ let middleware: Middleware;
118
+ beforeEach(() => {
119
+ NM = new NetworkManager(42, 7);
120
+ middleware = NM.getMiddleware();
121
+ });
122
+ afterEach(() => {
123
+ NM.cleanup();
124
+ });
125
+
126
+ it('should handle fetch actions and dispatch on success', async () => {
127
+ const next = jest.fn();
128
+ const dispatch = jest.fn();
129
+ const controller = new Controller({ dispatch, getState });
130
+ const API: Controller & { controller: Controller } = Object.create(
131
+ controller,
132
+ {
133
+ controller: { value: controller },
134
+ },
135
+ );
136
+
137
+ middleware(API)(next)(fetchResolveAction);
138
+
139
+ const data = await fetchResolveAction.payload();
140
+
141
+ const action = {
142
+ type: RECEIVE_TYPE,
143
+ payload: data,
144
+ meta: {
145
+ schema: fetchResolveAction.meta.schema,
146
+ args: fetchResolveAction.meta.args,
147
+ update: fetchResolveAction.meta.update,
148
+ key: fetchResolveAction.meta.key,
149
+ date: expect.any(Number),
150
+ expiresAt: expect.any(Number),
151
+ fetchedAt: expect.any(Number),
152
+ },
153
+ };
154
+ expect(dispatch).toHaveBeenCalledWith(action);
155
+ expect(next).not.toHaveBeenCalledWith(action);
156
+ });
157
+ it('should handle fetch receive action and dispatch on success with updaters', async () => {
158
+ const next = jest.fn();
159
+ const dispatch = jest.fn();
160
+ const controller = new Controller({ dispatch, getState });
161
+ const API: Controller & { controller: Controller } = Object.create(
162
+ controller,
163
+ {
164
+ controller: { value: controller },
165
+ },
166
+ );
167
+ middleware(API)(next)(fetchReceiveWithUpdatersAction);
168
+
169
+ const data = await fetchReceiveWithUpdatersAction.payload();
170
+
171
+ const action = {
172
+ type: RECEIVE_TYPE,
173
+ payload: data,
174
+ meta: {
175
+ updaters: {
176
+ [ArticleResource.listShape().getFetchKey({})]: expect.any(Function),
177
+ },
178
+ args: fetchReceiveWithUpdatersAction.meta.args,
179
+ update: fetchReceiveWithUpdatersAction.meta.update,
180
+ schema: fetchReceiveWithUpdatersAction.meta.schema,
181
+ key: fetchReceiveWithUpdatersAction.meta.key,
182
+ date: expect.any(Number),
183
+ expiresAt: expect.any(Number),
184
+ fetchedAt: expect.any(Number),
185
+ },
186
+ };
187
+ expect(dispatch).toHaveBeenCalledWith(action);
188
+ expect(next).not.toHaveBeenCalledWith(action);
189
+ });
190
+ it('should handle fetch rpc action and dispatch on success with updaters', async () => {
191
+ const next = jest.fn();
192
+ const dispatch = jest.fn();
193
+ const controller = new Controller({ dispatch, getState });
194
+ const API: Controller & { controller: Controller } = Object.create(
195
+ controller,
196
+ {
197
+ controller: { value: controller },
198
+ },
199
+ );
200
+ middleware(API)(next)(fetchRpcWithUpdatersAction);
201
+
202
+ const data = await fetchRpcWithUpdatersAction.payload();
203
+
204
+ const action = {
205
+ type: RECEIVE_TYPE,
206
+ payload: data,
207
+ meta: {
208
+ updaters: undefined,
209
+ args: fetchRpcWithUpdatersAction.meta.args,
210
+ update: expect.any(Function),
211
+ schema: fetchRpcWithUpdatersAction.meta.schema,
212
+ key: fetchRpcWithUpdatersAction.meta.key,
213
+ date: expect.any(Number),
214
+ expiresAt: expect.any(Number),
215
+ fetchedAt: expect.any(Number),
216
+ },
217
+ };
218
+ expect(dispatch).toHaveBeenCalledWith(action);
219
+ expect(next).not.toHaveBeenCalledWith(action);
220
+ });
221
+ it('should handle fetch rpc action with optimistic response and dispatch on success with updaters', async () => {
222
+ const next = jest.fn();
223
+ const dispatch = jest.fn();
224
+ const controller = new Controller({ dispatch, getState });
225
+ const API: Controller & { controller: Controller } = Object.create(
226
+ controller,
227
+ {
228
+ controller: { value: controller },
229
+ },
230
+ );
231
+ middleware(API)(next)(fetchRpcWithUpdatersAndOptimisticAction);
232
+
233
+ const data = await fetchRpcWithUpdatersAndOptimisticAction.payload();
234
+
235
+ expect(next).toHaveBeenCalled();
236
+ expect(dispatch).toHaveBeenCalledWith({
237
+ type: RECEIVE_TYPE,
238
+ payload: data,
239
+ meta: {
240
+ updaters: undefined,
241
+ args: fetchRpcWithUpdatersAndOptimisticAction.meta.args,
242
+ update: expect.any(Function),
243
+ schema: fetchRpcWithUpdatersAndOptimisticAction.meta.schema,
244
+ key: fetchRpcWithUpdatersAndOptimisticAction.meta.key,
245
+ date: expect.any(Number),
246
+ expiresAt: expect.any(Number),
247
+ fetchedAt: expect.any(Number),
248
+ },
249
+ });
250
+ });
251
+ it('should use dataExpireLength from action if specified', async () => {
252
+ const dispatch = jest.fn();
253
+ const controller = new Controller({ dispatch, getState });
254
+ const API: Controller & { controller: Controller } = Object.create(
255
+ controller,
256
+ {
257
+ controller: { value: controller },
258
+ },
259
+ );
260
+ middleware(API)(() => Promise.resolve())({
261
+ ...fetchResolveAction,
262
+ meta: {
263
+ ...fetchResolveAction.meta,
264
+ options: { dataExpiryLength: 314 },
265
+ },
266
+ });
267
+
268
+ await fetchResolveAction.payload();
269
+
270
+ expect(dispatch).toHaveBeenCalled();
271
+ const { meta } = dispatch.mock.calls[0][0];
272
+ expect(meta.expiresAt - meta.date).toBe(314);
273
+ });
274
+ it('should use dataExpireLength from NetworkManager if not specified in action', async () => {
275
+ const dispatch = jest.fn();
276
+ const controller = new Controller({ dispatch, getState });
277
+ const API: Controller & { controller: Controller } = Object.create(
278
+ controller,
279
+ {
280
+ controller: { value: controller },
281
+ },
282
+ );
283
+ middleware(API)(() => Promise.resolve())({
284
+ ...fetchResolveAction,
285
+ meta: {
286
+ ...fetchResolveAction.meta,
287
+ options: { dataExpiryLength: undefined },
288
+ },
289
+ });
290
+
291
+ await fetchResolveAction.payload();
292
+
293
+ expect(dispatch).toHaveBeenCalled();
294
+ const { meta } = dispatch.mock.calls[0][0];
295
+ expect(meta.expiresAt - meta.date).toBe(42);
296
+ });
297
+ it('should handle fetch actions and dispatch on error', async () => {
298
+ const next = jest.fn();
299
+ const dispatch = jest.fn();
300
+ const controller = new Controller({ dispatch, getState });
301
+ const API: Controller & { controller: Controller } = Object.create(
302
+ controller,
303
+ {
304
+ controller: { value: controller },
305
+ },
306
+ );
307
+ try {
308
+ await middleware(API)(next)(fetchRejectAction);
309
+ } catch (error) {
310
+ expect(next).not.toHaveBeenCalled();
311
+ expect(dispatch).toHaveBeenCalledWith({
312
+ type: RECEIVE_TYPE,
313
+ payload: error,
314
+ meta: {
315
+ schema: fetchRejectAction.meta.schema,
316
+ key: fetchRejectAction.meta.key,
317
+ date: expect.any(Number),
318
+ expiresAt: expect.any(Number),
319
+ },
320
+ error: true,
321
+ });
322
+ }
323
+ });
324
+ it('should use errorExpireLength from action if specified', async () => {
325
+ const dispatch = jest.fn();
326
+ const controller = new Controller({ dispatch, getState });
327
+ const API: Controller & { controller: Controller } = Object.create(
328
+ controller,
329
+ {
330
+ controller: { value: controller },
331
+ },
332
+ );
333
+ try {
334
+ await middleware(API)(() => Promise.resolve())({
335
+ ...fetchRejectAction,
336
+ meta: {
337
+ ...fetchRejectAction.meta,
338
+ options: { errorExpiryLength: 1234 },
339
+ },
340
+ });
341
+ } catch (error) {
342
+ expect(dispatch).toHaveBeenCalled();
343
+ const { meta } = dispatch.mock.calls[0][0];
344
+ expect(meta.expiresAt - meta.date).toBe(1234);
345
+ }
346
+ });
347
+ it('should use errorExpireLength from NetworkManager if not specified in action', async () => {
348
+ const dispatch = jest.fn();
349
+ const controller = new Controller({ dispatch, getState });
350
+ const API: Controller & { controller: Controller } = Object.create(
351
+ controller,
352
+ {
353
+ controller: { value: controller },
354
+ },
355
+ );
356
+ try {
357
+ await middleware(API)(() => Promise.resolve())({
358
+ ...fetchRejectAction,
359
+ meta: {
360
+ ...fetchRejectAction.meta,
361
+ options: {
362
+ ...fetchRejectAction.meta.options,
363
+ errorExpiryLength: undefined,
364
+ },
365
+ },
366
+ });
367
+ } catch (error) {
368
+ expect(dispatch).toHaveBeenCalled();
369
+ const { meta } = dispatch.mock.calls[0][0];
370
+ expect(meta.expiresAt - meta.date).toBe(7);
371
+ }
372
+ });
373
+
374
+ it('getLastReset() should handle Date object', async () => {
375
+ const mgr = new NetworkManager();
376
+ jest.spyOn(mgr, 'getState' as any).mockImplementation((): any => ({
377
+ ...initialState,
378
+ lastReset: new Date(0),
379
+ }));
380
+
381
+ expect((mgr as any).getLastReset()).toBeLessThan(Date.now());
382
+ });
383
+
384
+ it('getLastReset() should handle null', async () => {
385
+ const mgr = new NetworkManager();
386
+ jest.spyOn(mgr, 'getState' as any).mockImplementation((): any => ({
387
+ ...initialState,
388
+ lastReset: null,
389
+ }));
390
+
391
+ expect((mgr as any).getLastReset()).toBeLessThan(Date.now());
392
+ });
393
+ });
394
+ });