@angular-architects/ngrx-toolkit 19.2.3 → 19.4.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 (123) hide show
  1. package/eslint.config.cjs +43 -0
  2. package/jest.config.ts +22 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +4 -21
  5. package/project.json +37 -0
  6. package/redux-connector/docs/README.md +131 -0
  7. package/redux-connector/index.ts +6 -0
  8. package/redux-connector/ng-package.json +5 -0
  9. package/redux-connector/src/lib/create-redux.ts +102 -0
  10. package/redux-connector/src/lib/model.ts +89 -0
  11. package/redux-connector/src/lib/rxjs-interop/redux-method.ts +66 -0
  12. package/redux-connector/src/lib/signal-redux-store.ts +59 -0
  13. package/redux-connector/src/lib/util.ts +22 -0
  14. package/{index.d.ts → src/index.ts} +36 -4
  15. package/src/lib/assertions/assertions.ts +9 -0
  16. package/{lib/devtools/features/with-disabled-name-indicies.d.ts → src/lib/devtools/features/with-disabled-name-indicies.ts} +5 -1
  17. package/{lib/devtools/features/with-glitch-tracking.d.ts → src/lib/devtools/features/with-glitch-tracking.ts} +6 -1
  18. package/{lib/devtools/features/with-mapper.d.ts → src/lib/devtools/features/with-mapper.ts} +7 -1
  19. package/src/lib/devtools/internal/current-action-names.ts +1 -0
  20. package/src/lib/devtools/internal/default-tracker.ts +60 -0
  21. package/src/lib/devtools/internal/devtools-feature.ts +37 -0
  22. package/src/lib/devtools/internal/devtools-syncer.service.ts +202 -0
  23. package/src/lib/devtools/internal/glitch-tracker.service.ts +61 -0
  24. package/src/lib/devtools/internal/models.ts +29 -0
  25. package/{lib/devtools/provide-devtools-config.d.ts → src/lib/devtools/provide-devtools-config.ts} +16 -4
  26. package/src/lib/devtools/rename-devtools-name.ts +21 -0
  27. package/src/lib/devtools/tests/action-name.spec.ts +48 -0
  28. package/src/lib/devtools/tests/basic.spec.ts +111 -0
  29. package/src/lib/devtools/tests/connecting.spec.ts +37 -0
  30. package/src/lib/devtools/tests/helpers.spec.ts +43 -0
  31. package/src/lib/devtools/tests/naming.spec.ts +216 -0
  32. package/src/lib/devtools/tests/provide-devtools-config.spec.ts +25 -0
  33. package/src/lib/devtools/tests/types.spec.ts +19 -0
  34. package/src/lib/devtools/tests/update-state.spec.ts +29 -0
  35. package/src/lib/devtools/tests/with-devtools.spec.ts +5 -0
  36. package/src/lib/devtools/tests/with-glitch-tracking.spec.ts +272 -0
  37. package/src/lib/devtools/tests/with-mapper.spec.ts +69 -0
  38. package/src/lib/devtools/update-state.ts +38 -0
  39. package/{lib/devtools/with-dev-tools-stub.d.ts → src/lib/devtools/with-dev-tools-stub.ts} +2 -1
  40. package/src/lib/devtools/with-devtools.ts +81 -0
  41. package/src/lib/flattening-operator.ts +42 -0
  42. package/src/lib/immutable-state/deep-freeze.ts +43 -0
  43. package/src/lib/immutable-state/is-dev-mode.ts +6 -0
  44. package/src/lib/immutable-state/tests/with-immutable-state.spec.ts +260 -0
  45. package/src/lib/immutable-state/with-immutable-state.ts +115 -0
  46. package/src/lib/mutation/http-mutation.spec.ts +473 -0
  47. package/src/lib/mutation/http-mutation.ts +172 -0
  48. package/src/lib/mutation/mutation.ts +26 -0
  49. package/src/lib/mutation/rx-mutation.spec.ts +594 -0
  50. package/src/lib/mutation/rx-mutation.ts +208 -0
  51. package/src/lib/shared/prettify.ts +3 -0
  52. package/{lib/shared/signal-store-models.d.ts → src/lib/shared/signal-store-models.ts} +8 -4
  53. package/src/lib/shared/throw-if-null.ts +7 -0
  54. package/src/lib/storage-sync/features/with-indexed-db.ts +81 -0
  55. package/src/lib/storage-sync/features/with-local-storage.ts +58 -0
  56. package/src/lib/storage-sync/internal/indexeddb.service.ts +124 -0
  57. package/src/lib/storage-sync/internal/local-storage.service.ts +19 -0
  58. package/src/lib/storage-sync/internal/models.ts +62 -0
  59. package/src/lib/storage-sync/internal/session-storage.service.ts +18 -0
  60. package/src/lib/storage-sync/tests/indexeddb.service.spec.ts +99 -0
  61. package/src/lib/storage-sync/tests/with-storage-async.spec.ts +308 -0
  62. package/src/lib/storage-sync/tests/with-storage-sync.spec.ts +268 -0
  63. package/src/lib/storage-sync/with-storage-sync.ts +233 -0
  64. package/src/lib/with-call-state.spec.ts +42 -0
  65. package/src/lib/with-call-state.ts +195 -0
  66. package/src/lib/with-conditional.spec.ts +125 -0
  67. package/{lib/with-conditional.d.ts → src/lib/with-conditional.ts} +31 -7
  68. package/src/lib/with-data-service.spec.ts +564 -0
  69. package/src/lib/with-data-service.ts +433 -0
  70. package/src/lib/with-feature-factory.spec.ts +69 -0
  71. package/{lib/with-feature-factory.d.ts → src/lib/with-feature-factory.ts} +32 -4
  72. package/src/lib/with-mutations.spec.ts +537 -0
  73. package/src/lib/with-mutations.ts +146 -0
  74. package/src/lib/with-pagination.spec.ts +90 -0
  75. package/src/lib/with-pagination.ts +353 -0
  76. package/src/lib/with-redux.spec.ts +258 -0
  77. package/src/lib/with-redux.ts +387 -0
  78. package/src/lib/with-reset.spec.ts +112 -0
  79. package/src/lib/with-reset.ts +62 -0
  80. package/src/lib/with-undo-redo.spec.ts +287 -0
  81. package/src/lib/with-undo-redo.ts +199 -0
  82. package/src/test-setup.ts +8 -0
  83. package/tsconfig.json +29 -0
  84. package/tsconfig.lib.json +17 -0
  85. package/tsconfig.lib.prod.json +9 -0
  86. package/tsconfig.spec.json +17 -0
  87. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +0 -119
  88. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +0 -1
  89. package/fesm2022/angular-architects-ngrx-toolkit.mjs +0 -1787
  90. package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +0 -1
  91. package/lib/assertions/assertions.d.ts +0 -2
  92. package/lib/devtools/internal/current-action-names.d.ts +0 -1
  93. package/lib/devtools/internal/default-tracker.d.ts +0 -13
  94. package/lib/devtools/internal/devtools-feature.d.ts +0 -24
  95. package/lib/devtools/internal/devtools-syncer.service.d.ts +0 -35
  96. package/lib/devtools/internal/glitch-tracker.service.d.ts +0 -18
  97. package/lib/devtools/internal/models.d.ts +0 -24
  98. package/lib/devtools/rename-devtools-name.d.ts +0 -7
  99. package/lib/devtools/update-state.d.ts +0 -15
  100. package/lib/devtools/with-devtools.d.ts +0 -24
  101. package/lib/immutable-state/deep-freeze.d.ts +0 -11
  102. package/lib/immutable-state/is-dev-mode.d.ts +0 -1
  103. package/lib/immutable-state/with-immutable-state.d.ts +0 -60
  104. package/lib/shared/throw-if-null.d.ts +0 -1
  105. package/lib/storage-sync/features/with-indexed-db.d.ts +0 -2
  106. package/lib/storage-sync/features/with-local-storage.d.ts +0 -3
  107. package/lib/storage-sync/internal/indexeddb.service.d.ts +0 -29
  108. package/lib/storage-sync/internal/local-storage.service.d.ts +0 -8
  109. package/lib/storage-sync/internal/models.d.ts +0 -45
  110. package/lib/storage-sync/internal/session-storage.service.d.ts +0 -8
  111. package/lib/storage-sync/with-storage-sync.d.ts +0 -45
  112. package/lib/with-call-state.d.ts +0 -58
  113. package/lib/with-data-service.d.ts +0 -109
  114. package/lib/with-pagination.d.ts +0 -98
  115. package/lib/with-redux.d.ts +0 -147
  116. package/lib/with-reset.d.ts +0 -29
  117. package/lib/with-undo-redo.d.ts +0 -31
  118. package/redux-connector/index.d.ts +0 -2
  119. package/redux-connector/src/lib/create-redux.d.ts +0 -13
  120. package/redux-connector/src/lib/model.d.ts +0 -40
  121. package/redux-connector/src/lib/rxjs-interop/redux-method.d.ts +0 -14
  122. package/redux-connector/src/lib/signal-redux-store.d.ts +0 -11
  123. package/redux-connector/src/lib/util.d.ts +0 -5
@@ -0,0 +1,594 @@
1
+ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
2
+ import { delay, Observable, of, Subject, switchMap, throwError } from 'rxjs';
3
+ import { concatOp, exhaustOp, mergeOp, switchOp } from '../flattening-operator';
4
+ import { rxMutation } from './rx-mutation';
5
+
6
+ type Param =
7
+ | number
8
+ | {
9
+ value: number | Observable<number>;
10
+ delay?: number;
11
+ fail?: boolean;
12
+ };
13
+
14
+ type NormalizedParam = {
15
+ value: number | Observable<number>;
16
+ delay: number;
17
+ fail: boolean;
18
+ };
19
+
20
+ async function asyncTick(): Promise<void> {
21
+ return new Promise((resolve) => {
22
+ setTimeout(() => {
23
+ resolve();
24
+ }, 0);
25
+ });
26
+ }
27
+
28
+ function calcDouble(value: number, delayInMsec = 1000): Observable<number> {
29
+ return of(value * 2).pipe(delay(delayInMsec));
30
+ }
31
+
32
+ function fail(_value: number, delayInMsec = 1000): Observable<number> {
33
+ return of(null).pipe(
34
+ delay(delayInMsec),
35
+ switchMap(() => throwError(() => ({ error: 'Test-Error' }))),
36
+ );
37
+ }
38
+
39
+ function createTestSetup(flatteningOperator = concatOp) {
40
+ function normalizeParam(param: Param): NormalizedParam {
41
+ if (typeof param === 'number') {
42
+ return {
43
+ value: param,
44
+ delay: 1000,
45
+ fail: false,
46
+ };
47
+ }
48
+
49
+ return {
50
+ value: param.value,
51
+ delay: param.delay ?? 1000,
52
+ fail: param.fail ?? false,
53
+ };
54
+ }
55
+
56
+ type SuccessParam = { result: number; param: Param };
57
+ type ErrorParam = { error: unknown; param: Param };
58
+
59
+ let onSuccessCalls = 0;
60
+ let onErrorCalls = 0;
61
+ let counter = 3;
62
+
63
+ let lastOnSuccessParam: SuccessParam | undefined = undefined;
64
+ let lastOnErrorParam: ErrorParam | undefined = undefined;
65
+
66
+ return TestBed.runInInjectionContext(() => {
67
+ const increment = rxMutation({
68
+ operation: (param: Param) => {
69
+ const normalized = normalizeParam(param);
70
+
71
+ if (normalized.value instanceof Observable) {
72
+ return normalized.value.pipe(
73
+ switchMap((value) => {
74
+ if (normalized.fail) {
75
+ return fail(value, normalized.delay);
76
+ }
77
+ return calcDouble(value, normalized.delay);
78
+ }),
79
+ );
80
+ }
81
+
82
+ if (normalized.fail) {
83
+ return fail(normalized.value, normalized.delay);
84
+ }
85
+ return calcDouble(normalized.value, normalized.delay);
86
+ },
87
+ operator: flatteningOperator,
88
+ onSuccess: (result, param) => {
89
+ lastOnSuccessParam = { result, param: param };
90
+ onSuccessCalls++;
91
+ counter = counter + result;
92
+ },
93
+ onError: (error, param) => {
94
+ lastOnErrorParam = { error, param: param };
95
+ onErrorCalls++;
96
+ },
97
+ });
98
+
99
+ return {
100
+ increment,
101
+ getCounter: () => counter,
102
+ onSuccessCalls: () => onSuccessCalls,
103
+ onErrorCalls: () => onErrorCalls,
104
+ lastOnSuccessParam: () => lastOnSuccessParam,
105
+ lastOnErrorParam: () => lastOnErrorParam,
106
+ };
107
+ });
108
+ }
109
+
110
+ describe('rxMutation', () => {
111
+ it('should update the state', fakeAsync(() => {
112
+ const testSetup = createTestSetup();
113
+ const increment = testSetup.increment;
114
+
115
+ expect(increment.status()).toEqual('idle');
116
+ expect(increment.isPending()).toEqual(false);
117
+
118
+ increment(2);
119
+ expect(increment.status()).toEqual('pending');
120
+ expect(increment.isPending()).toEqual(true);
121
+
122
+ tick(2000);
123
+ expect(increment.status()).toEqual('success');
124
+ expect(increment.isPending()).toEqual(false);
125
+ expect(increment.isSuccess()).toEqual(true);
126
+ expect(increment.error()).toEqual(undefined);
127
+
128
+ expect(testSetup.getCounter()).toEqual(7);
129
+ }));
130
+
131
+ it('sets error', fakeAsync(() => {
132
+ const testSetup = createTestSetup();
133
+ const increment = testSetup.increment;
134
+
135
+ increment({ value: 2, fail: true });
136
+
137
+ tick(2000);
138
+ expect(increment.status()).toEqual('error');
139
+ expect(increment.isPending()).toEqual(false);
140
+ expect(increment.isSuccess()).toEqual(false);
141
+ expect(increment.error()).toEqual({
142
+ error: 'Test-Error',
143
+ });
144
+
145
+ expect(testSetup.getCounter()).toEqual(3);
146
+ }));
147
+
148
+ it('starts two concurrent operations using concatMap: the first one fails and the second one succeeds', fakeAsync(() => {
149
+ const testSetup = createTestSetup(concatOp);
150
+ const increment = testSetup.increment;
151
+
152
+ increment({ value: 1, delay: 100, fail: true });
153
+ increment({ value: 2, delay: 200, fail: false });
154
+
155
+ tick(100);
156
+
157
+ expect(increment.status()).toEqual('pending');
158
+ expect(increment.isPending()).toEqual(true);
159
+ expect(increment.error()).toEqual({
160
+ error: 'Test-Error',
161
+ });
162
+
163
+ tick(200);
164
+
165
+ expect(increment.status()).toEqual('success');
166
+ expect(increment.isPending()).toEqual(false);
167
+ expect(increment.error()).toEqual(undefined);
168
+
169
+ expect(testSetup.getCounter()).toEqual(7);
170
+ }));
171
+
172
+ it('starts two concurrent operations using mergeMap: the first one fails and the second one succeeds', fakeAsync(() => {
173
+ const testSetup = createTestSetup(mergeOp);
174
+ const increment = testSetup.increment;
175
+
176
+ increment({ value: 1, delay: 100, fail: true });
177
+ increment({ value: 2, delay: 200, fail: false });
178
+
179
+ tick(100);
180
+
181
+ expect(increment.status()).toEqual('pending');
182
+ expect(increment.isPending()).toEqual(true);
183
+ expect(increment.isSuccess()).toEqual(false);
184
+
185
+ expect(increment.error()).toEqual({
186
+ error: 'Test-Error',
187
+ });
188
+
189
+ tick(100);
190
+
191
+ expect(increment.status()).toEqual('success');
192
+ expect(increment.isPending()).toEqual(false);
193
+ expect(increment.isSuccess()).toEqual(true);
194
+
195
+ expect(increment.error()).toEqual(undefined);
196
+
197
+ expect(testSetup.getCounter()).toEqual(7);
198
+ }));
199
+
200
+ it('deals with race conditions using switchMap', fakeAsync(() => {
201
+ const testSetup = createTestSetup(switchOp);
202
+ const increment = testSetup.increment;
203
+
204
+ increment(1);
205
+
206
+ tick(500);
207
+ expect(increment.status()).toEqual('pending');
208
+ expect(increment.isPending()).toEqual(true);
209
+
210
+ increment(2);
211
+ tick(1000);
212
+
213
+ expect(increment.status()).toEqual('success');
214
+ expect(increment.isPending()).toEqual(false);
215
+ expect(increment.error()).toEqual(undefined);
216
+ expect(increment.isSuccess()).toEqual(true);
217
+
218
+ expect(testSetup.getCounter()).toEqual(7);
219
+ expect(testSetup.onSuccessCalls()).toEqual(1);
220
+ expect(testSetup.onErrorCalls()).toEqual(0);
221
+
222
+ expect(testSetup.lastOnSuccessParam()).toEqual({
223
+ param: 2,
224
+ result: 4,
225
+ });
226
+ }));
227
+
228
+ it('deals with race conditions using mergeMap', fakeAsync(() => {
229
+ const testSetup = createTestSetup(mergeOp);
230
+ const increment = testSetup.increment;
231
+
232
+ increment(1);
233
+ tick(500);
234
+ increment(2);
235
+ tick(500);
236
+
237
+ expect(increment.status()).toEqual('pending');
238
+ expect(increment.isPending()).toEqual(true);
239
+ expect(increment.isSuccess()).toEqual(false);
240
+
241
+ // expect(testSetup.getCounter()).toEqual(7);
242
+ expect(testSetup.onSuccessCalls()).toEqual(1);
243
+ expect(testSetup.onErrorCalls()).toEqual(0);
244
+ expect(testSetup.lastOnSuccessParam()).toEqual({
245
+ param: 1,
246
+ result: 2,
247
+ });
248
+
249
+ tick(500);
250
+
251
+ expect(increment.status()).toEqual('success');
252
+ expect(increment.isPending()).toEqual(false);
253
+ expect(increment.error()).toEqual(undefined);
254
+ expect(increment.isSuccess()).toEqual(true);
255
+
256
+ expect(testSetup.getCounter()).toEqual(9);
257
+ expect(testSetup.onSuccessCalls()).toEqual(2);
258
+ expect(testSetup.onErrorCalls()).toEqual(0);
259
+ expect(testSetup.lastOnSuccessParam()).toEqual({
260
+ param: 2,
261
+ result: 4,
262
+ });
263
+ }));
264
+
265
+ it('deals with race conditions using mergeMap where the 2nd task starts after and finishes before the 1st one', fakeAsync(() => {
266
+ const testSetup = createTestSetup(mergeOp);
267
+ const increment = testSetup.increment;
268
+
269
+ increment({ value: 1, delay: 1000 });
270
+ tick(500);
271
+
272
+ expect(increment.status()).toEqual('pending');
273
+ expect(increment.isPending()).toEqual(true);
274
+ expect(increment.isSuccess()).toEqual(false);
275
+
276
+ increment({ value: 2, delay: 100 });
277
+ tick(500);
278
+
279
+ expect(increment.status()).toEqual('success');
280
+ expect(increment.isPending()).toEqual(false);
281
+ expect(increment.error()).toEqual(undefined);
282
+ expect(increment.isSuccess()).toEqual(true);
283
+
284
+ expect(testSetup.getCounter()).toEqual(9);
285
+ expect(testSetup.onSuccessCalls()).toEqual(2);
286
+ expect(testSetup.onErrorCalls()).toEqual(0);
287
+ expect(testSetup.lastOnSuccessParam()).toEqual({
288
+ param: { value: 1, delay: 1000 },
289
+ result: 2,
290
+ });
291
+ }));
292
+
293
+ it('deals with race conditions using concatMap', fakeAsync(() => {
294
+ const testSetup = createTestSetup(concatOp);
295
+ const increment = testSetup.increment;
296
+
297
+ increment({ value: 1, delay: 1000 });
298
+ tick(500);
299
+ increment({ value: 2, delay: 100 });
300
+ tick(500);
301
+
302
+ expect(increment.status()).toEqual('pending');
303
+ expect(increment.isPending()).toEqual(true);
304
+ expect(increment.isSuccess()).toEqual(false);
305
+
306
+ expect(testSetup.getCounter()).toEqual(5);
307
+ expect(testSetup.onSuccessCalls()).toEqual(1);
308
+ expect(testSetup.onErrorCalls()).toEqual(0);
309
+ expect(testSetup.lastOnSuccessParam()).toEqual({
310
+ param: { value: 1, delay: 1000 },
311
+ result: 2,
312
+ });
313
+
314
+ tick(500);
315
+
316
+ expect(increment.status()).toEqual('success');
317
+ expect(increment.isPending()).toEqual(false);
318
+ expect(increment.error()).toEqual(undefined);
319
+ expect(increment.isSuccess()).toEqual(true);
320
+
321
+ expect(testSetup.getCounter()).toEqual(9);
322
+ expect(testSetup.onSuccessCalls()).toEqual(2);
323
+ expect(testSetup.onErrorCalls()).toEqual(0);
324
+ expect(testSetup.lastOnSuccessParam()).toEqual({
325
+ param: { value: 2, delay: 100 },
326
+ result: 4,
327
+ });
328
+ }));
329
+
330
+ it('deals with race conditions using exhaustMap', fakeAsync(() => {
331
+ const testSetup = createTestSetup(exhaustOp);
332
+ const increment = testSetup.increment;
333
+
334
+ increment({ value: 1, delay: 1000 });
335
+ tick(500);
336
+
337
+ expect(increment.status()).toEqual('pending');
338
+ expect(increment.isPending()).toEqual(true);
339
+ expect(increment.isSuccess()).toEqual(false);
340
+
341
+ increment({ value: 2, delay: 100 });
342
+ tick(500);
343
+
344
+ expect(increment.status()).toEqual('success');
345
+ expect(increment.isPending()).toEqual(false);
346
+ expect(increment.error()).toEqual(undefined);
347
+ expect(increment.isSuccess()).toEqual(true);
348
+
349
+ expect(testSetup.getCounter()).toEqual(5);
350
+ expect(testSetup.onSuccessCalls()).toEqual(1);
351
+ expect(testSetup.onErrorCalls()).toEqual(0);
352
+ expect(testSetup.lastOnSuccessParam()).toEqual({
353
+ param: { value: 1, delay: 1000 },
354
+ result: 2,
355
+ });
356
+
357
+ tick(500);
358
+
359
+ expect(increment.status()).toEqual('success');
360
+ expect(increment.isPending()).toEqual(false);
361
+ expect(increment.error()).toEqual(undefined);
362
+ expect(increment.isSuccess()).toEqual(true);
363
+
364
+ expect(testSetup.getCounter()).toEqual(5);
365
+ expect(testSetup.onSuccessCalls()).toEqual(1);
366
+ expect(testSetup.onErrorCalls()).toEqual(0);
367
+ expect(testSetup.lastOnSuccessParam()).toEqual({
368
+ param: { value: 1, delay: 1000 },
369
+ result: 2,
370
+ });
371
+ }));
372
+
373
+ it('informs about failed operation via the returned promise', async () => {
374
+ const testSetup = createTestSetup(switchOp);
375
+ const increment = testSetup.increment;
376
+
377
+ const p1 = increment({ value: 1, delay: 1, fail: false });
378
+ const p2 = increment({ value: 2, delay: 2, fail: true });
379
+
380
+ expect(increment.status()).toEqual('pending');
381
+ expect(increment.isPending()).toEqual(true);
382
+ expect(increment.isSuccess()).toEqual(false);
383
+
384
+ await asyncTick();
385
+
386
+ const result1 = await p1;
387
+ const result2 = await p2;
388
+
389
+ expect(result1.status).toEqual('aborted');
390
+ expect(result2).toEqual({
391
+ status: 'error',
392
+ error: {
393
+ error: 'Test-Error',
394
+ },
395
+ });
396
+
397
+ expect(increment.isPending()).toEqual(false);
398
+ expect(increment.status()).toEqual('error');
399
+ expect(increment.isSuccess()).toEqual(false);
400
+
401
+ expect(increment.error()).toEqual({
402
+ error: 'Test-Error',
403
+ });
404
+ });
405
+
406
+ it('informs about successful operation via the returned promise', async () => {
407
+ const testSetup = createTestSetup();
408
+ const increment = testSetup.increment;
409
+
410
+ const resultPromise = increment({ value: 2, delay: 2, fail: false });
411
+
412
+ expect(increment.status()).toEqual('pending');
413
+ expect(increment.isPending()).toEqual(true);
414
+ expect(increment.isSuccess()).toEqual(false);
415
+
416
+ await asyncTick();
417
+
418
+ const result = await resultPromise;
419
+
420
+ expect(result).toEqual({
421
+ status: 'success',
422
+ value: 4,
423
+ });
424
+
425
+ expect(increment.isPending()).toEqual(false);
426
+ expect(increment.isSuccess()).toEqual(true);
427
+
428
+ expect(increment.status()).toEqual('success');
429
+ expect(increment.error()).toBeUndefined();
430
+ });
431
+
432
+ it('informs about aborted operation when using switchMap', async () => {
433
+ const testSetup = createTestSetup(switchOp);
434
+ const increment = testSetup.increment;
435
+
436
+ const p1 = increment({ value: 1, delay: 1, fail: false });
437
+ const p2 = increment({ value: 2, delay: 2, fail: false });
438
+
439
+ expect(increment.status()).toEqual('pending');
440
+ expect(increment.isPending()).toEqual(true);
441
+ expect(increment.isSuccess()).toEqual(false);
442
+
443
+ await asyncTick();
444
+
445
+ const result1 = await p1;
446
+ const result2 = await p2;
447
+
448
+ expect(result1.status).toEqual('aborted');
449
+ expect(result2).toEqual({
450
+ status: 'success',
451
+ value: 4,
452
+ });
453
+
454
+ expect(increment.isPending()).toEqual(false);
455
+ expect(increment.status()).toEqual('success');
456
+ expect(increment.isSuccess()).toEqual(true);
457
+
458
+ expect(increment.value()).toEqual(4);
459
+ expect(increment.hasValue()).toEqual(true);
460
+ expect(increment.error()).toBeUndefined();
461
+ });
462
+
463
+ it('informs about aborted operation when using exhaustMap', async () => {
464
+ const testSetup = createTestSetup(exhaustOp);
465
+ const increment = testSetup.increment;
466
+
467
+ const p1 = increment({ value: 1, delay: 1, fail: false });
468
+ const p2 = increment({ value: 2, delay: 1, fail: false });
469
+
470
+ expect(increment.status()).toEqual('pending');
471
+ expect(increment.isPending()).toEqual(true);
472
+ expect(increment.isSuccess()).toEqual(false);
473
+
474
+ await asyncTick();
475
+
476
+ const result1 = await p1;
477
+ const result2 = await p2;
478
+
479
+ expect(result1).toEqual({
480
+ status: 'success',
481
+ value: 2,
482
+ });
483
+
484
+ expect(result2.status).toEqual('aborted');
485
+
486
+ expect(increment.isPending()).toEqual(false);
487
+ expect(increment.status()).toEqual('success');
488
+ expect(increment.isSuccess()).toEqual(true);
489
+ expect(increment.error()).toBeUndefined();
490
+ });
491
+
492
+ it('calls success handler per value in the stream and returns the final value via the promise', async () => {
493
+ const testSetup = createTestSetup(switchOp);
494
+ const increment = testSetup.increment;
495
+
496
+ const input$ = new Subject<number>();
497
+ const resultPromise = increment({
498
+ value: input$,
499
+ delay: 1,
500
+ fail: false,
501
+ });
502
+
503
+ expect(increment.status()).toEqual('pending');
504
+ expect(increment.isPending()).toEqual(true);
505
+ expect(increment.isSuccess()).toEqual(false);
506
+
507
+ input$.next(1);
508
+ input$.next(2);
509
+ input$.next(3);
510
+ input$.complete();
511
+
512
+ await asyncTick();
513
+
514
+ const result = await resultPromise;
515
+
516
+ expect(result).toEqual({
517
+ status: 'success',
518
+ value: 6,
519
+ });
520
+
521
+ expect(testSetup.getCounter()).toEqual(9);
522
+ expect(testSetup.lastOnSuccessParam()).toMatchObject({
523
+ result: 6,
524
+ });
525
+
526
+ expect(increment.isPending()).toEqual(false);
527
+ expect(increment.status()).toEqual('success');
528
+ expect(increment.isSuccess()).toEqual(true);
529
+
530
+ expect(increment.error()).toBeUndefined();
531
+ });
532
+
533
+ it('informs about failed operation via the returned promise', async () => {
534
+ const testSetup = createTestSetup(switchOp);
535
+ const increment = testSetup.increment;
536
+
537
+ const p1 = increment({ value: 1, delay: 1, fail: false });
538
+ const p2 = increment({ value: 2, delay: 2, fail: true });
539
+
540
+ expect(increment.status()).toEqual('pending');
541
+ expect(increment.isPending()).toEqual(true);
542
+ expect(increment.isSuccess()).toEqual(false);
543
+
544
+ await asyncTick();
545
+
546
+ const result1 = await p1;
547
+ const result2 = await p2;
548
+
549
+ expect(result1.status).toEqual('aborted');
550
+ expect(result2).toEqual({
551
+ status: 'error',
552
+ error: {
553
+ error: 'Test-Error',
554
+ },
555
+ });
556
+
557
+ expect(increment.isPending()).toEqual(false);
558
+ expect(increment.hasValue()).toEqual(false);
559
+ expect(increment.status()).toEqual('error');
560
+ expect(increment.isSuccess()).toEqual(false);
561
+ expect(increment.error()).toEqual({
562
+ error: 'Test-Error',
563
+ });
564
+ });
565
+
566
+ it('can be called using an operation function', async () => {
567
+ const increment = TestBed.runInInjectionContext(() =>
568
+ rxMutation((value: number) => {
569
+ return calcDouble(value).pipe(delay(1));
570
+ }),
571
+ );
572
+
573
+ const resultPromise = increment(2);
574
+
575
+ expect(increment.status()).toEqual('pending');
576
+ expect(increment.isPending()).toEqual(true);
577
+ expect(increment.isSuccess()).toEqual(false);
578
+
579
+ await asyncTick();
580
+
581
+ const result = await resultPromise;
582
+
583
+ expect(result).toEqual({
584
+ status: 'success',
585
+ value: 4,
586
+ });
587
+
588
+ expect(increment.isPending()).toEqual(false);
589
+ expect(increment.isSuccess()).toEqual(true);
590
+
591
+ expect(increment.status()).toEqual('success');
592
+ expect(increment.error()).toBeUndefined();
593
+ });
594
+ });