Skip to content

Commit

Permalink
fix(signals): withCalls mapPipe not working correctly
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Gabriel Guerrero committed Dec 8, 2024
1 parent 5fd0d1c commit d800304
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 4 deletions.
106 changes: 104 additions & 2 deletions libs/ngrx-traits/signals/src/lib/with-calls/with-calls.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { computed, signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import {
patchState,
signalStore,
withComputed,
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';

Expand Down Expand Up @@ -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);
}));
});
});
4 changes: 2 additions & 2 deletions libs/ngrx-traits/signals/src/lib/with-calls/with-calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ export function withCalls<

acc[callNameKey] = rxMethod<unknown[]>(
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(
Expand Down

0 comments on commit d800304

Please sign in to comment.