From 2b9647c50c616fc169ef99d8efe4e87d451114dc Mon Sep 17 00:00:00 2001 From: Gabriel Guerrero Date: Sun, 8 Dec 2024 23:28:15 +0000 Subject: [PATCH] fix(signals): withCalls mapPipe not working correctly Due to a bug when using mapPipe: exhaustMap or switchMap was always behaving like a concatMap, this pr fixes the issue and adds tests fix #148 --- .../src/lib/with-calls/with-calls.spec.ts | 106 +++++++++++++++++- .../signals/src/lib/with-calls/with-calls.ts | 4 +- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.spec.ts b/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.spec.ts index 87d0a1e..9770b4d 100644 --- a/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.spec.ts +++ b/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.spec.ts @@ -1,5 +1,5 @@ import { computed, signal } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; +import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { patchState, signalStore, @@ -7,7 +7,7 @@ import { withMethods, withState, } from '@ngrx/signals'; -import { BehaviorSubject, of, Subject, tap, throwError } from 'rxjs'; +import { BehaviorSubject, delay, of, Subject, tap, throwError } from 'rxjs'; import { typedCallConfig, withCalls } from '../index'; @@ -750,4 +750,106 @@ describe('withCalls', () => { }); }); }); + + describe('withCalls with mapPipe', () => { + it('when withCall has mapPipe = switchMap should only process last call', fakeAsync(() => { + let aux = 0; + const call = jest.fn().mockImplementation(() => { + console.log('call'); + aux++; + return of('' + aux).pipe(delay(100)); + }); + const Store = signalStore( + { providedIn: 'root' }, + withCalls(() => ({ + testCall: typedCallConfig({ + call: call, + mapPipe: 'switchMap', + }), + })), + ); + const store = TestBed.inject(Store); + expect(store.isTestCallLoading()).toBeFalsy(); + + store.testCall(); + store.testCall(); + store.testCall(); + + expect(store.isTestCallLoading()).toBeTruthy(); + tick(150); + expect(store.isTestCallLoaded()).toBeTruthy(); + expect(store.testCallResult()).toBe('3'); + + expect(call).toHaveBeenCalledTimes(3); + })); + + it('when withCall has mapPipe= exhaustMap should only process first call', fakeAsync(() => { + let aux = 0; + const call = jest.fn().mockImplementation(() => { + console.log('call'); + aux++; + return of('' + aux).pipe(delay(100)); + }); + const Store = signalStore( + { providedIn: 'root' }, + withCalls(() => ({ + testCall: typedCallConfig({ + call: call, + mapPipe: 'exhaustMap', + }), + })), + ); + const store = TestBed.inject(Store); + expect(store.isTestCallLoading()).toBeFalsy(); + + store.testCall(); + store.testCall(); + store.testCall(); + + expect(store.isTestCallLoading()).toBeTruthy(); + tick(150); + expect(store.isTestCallLoaded()).toBeTruthy(); + expect(store.testCallResult()).toBe('1'); + + expect(call).toHaveBeenCalledTimes(1); + })); + + it('when withCall has mapPipe = concatMap should process all calls in sequence', fakeAsync(() => { + let aux = 0; + const call = jest.fn().mockImplementation(() => { + console.log('call'); + aux++; + return of('' + aux).pipe(delay(100)); + }); + const Store = signalStore( + { providedIn: 'root' }, + withCalls(() => ({ + testCall: typedCallConfig({ + call: call, + mapPipe: 'concatMap', + }), + })), + ); + const store = TestBed.inject(Store); + expect(store.isTestCallLoading()).toBeFalsy(); + + store.testCall(); + store.testCall(); + store.testCall(); + + expect(store.isTestCallLoading()).toBeTruthy(); + tick(110); + expect(store.testCallResult()).toBe('1'); + expect(store.isTestCallLoading()).toBeTruthy(); + expect(call).toHaveBeenCalledTimes(2); + tick(110); + expect(store.testCallResult()).toBe('2'); + expect(store.isTestCallLoading()).toBeTruthy(); + expect(call).toHaveBeenCalledTimes(3); + tick(110); + expect(store.testCallResult()).toBe('3'); + expect(store.isTestCallLoaded()).toBeTruthy(); + expect(call).toHaveBeenCalledTimes(3); + })); + }); }); diff --git a/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.ts b/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.ts index 05576b8..d076fef 100644 --- a/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.ts +++ b/libs/ngrx-traits/signals/src/lib/with-calls/with-calls.ts @@ -238,9 +238,9 @@ export function withCalls< acc[callNameKey] = rxMethod( pipe( - concatMap((params) => { + mapPipe((params) => { const skip = skipWhenFn?.(params) ?? false; - const process$ = mapPipe((params) => { + const process$ = concatMap((params) => { setLoading(); return runInInjectionContext(environmentInjector, () => { return callFn(params).pipe(