Search code examples
angularjestjsjasminengrxngrx-effects

Unit testing NgRx effect as a function


I want to unit test functional effect as described here

export const loadUsers = createEffect(
  (actions$ = inject(Actions), usersService = inject(UsersService)) => {
    return actions$.pipe(
      ofType(userActions.getUser),
      exhaustMap(() => {
        return usersService.getAll().pipe(
          map((users) => userActions.usersLoadedSuccess({ users })),
    
        );
      })
    );
  },
  { functional: true }
);

https://ngrx.io/api/effects/createEffect#functional-effects

How one would unit test this functional effect. Kindly note there is no injectable or class

I am expecting a way to test this functional effect. I tried below approach but the effect is not getting triggered at all.

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { Observable, of } from 'rxjs';
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { MockProvider } from 'ng-mocks';
import { Actions } from '@ngrx/effects';
import { userActions } from './user-store';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { UsersService } from './users.service';
import { loadUsers } from './user.effects';

describe('Offer Effects', () => {
    let actions$: Observable<unknown>;
    let store: MockStore;
    let userService: UsersService;
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [loadUsers, MockProvider(UsersService), provideMockStore(), provideMockActions(() => actions$)],
        });

        actions$ = TestBed.inject(Actions);
        store = TestBed.inject(MockStore);
        userService = TestBed.inject(UsersService);
    });

    it('should test load users effect', async () => {
        actions$ = of({
            type: userActions.getUser,
        });
        const users = { name: 'Test', surname: 'Data' };
        jest.spyOn(userService, 'getAll').mockReturnValue(of(users));
        const spy = jest.spyOn(userActions, 'usersLoadedSuccess');
        await loadUsers;
        expect(spy).toHaveBeenCalledWith({ users });
    });
});


Solution

  • If you want to use await, you're not actually calling the effect, so do something like:

    await loadUsers(actions$, userService);
    

    Otherwise use subscribe like in the 'Testing' example here: https://github.com/ngrx/platform/issues/3668

    
    it('loads users successfully', () => {
      usersEffects.loadUsers(actionsMock, usersServiceMock).subscribe((action) => {
        expect(serviceMock, 'getAll').toHaveBeenCalled();
        expect(action).toEqual(/* ... */);
      });
    });