camden_kid
camden_kid

Reputation: 12813

How to unit test this effect (with {dispatch: false})?

ngrx and unit testing beginner here. I have the following effect:

@Injectable()
export class NotificationEffects {
  @Effect({dispatch: false})
  notificationShow$ = this.actions$
    .ofType(notificationAction.NOTIFICATION_SHOW)
    .do((action: notificationAction.NotificationShowAction) => {
      this.notificationService.info(action.payload.config);
    });

  constructor(private actions$: Actions, private notificationService: NotificationService) {}
}

Specifically, I would like to test that the notificationService method info has been called. How would I do that?

I have followed these examples but not found a solution:

https://netbasal.com/unit-test-your-ngrx-effects-in-angular-1bf2142dd459 https://medium.com/@adrianfaciu/testing-ngrx-effects-3682cb5d760e https://github.com/ngrx/effects/blob/master/docs/testing.md

Upvotes: 19

Views: 8187

Answers (5)

szmitas
szmitas

Reputation: 331

This should be helpful:

it('should call a notification service method info with a payload', () => {
    const action = new notificationAction.NotificationShowAction(payload);

    actions$ = hot('-a', { a: action });

    expect(effects.notificationShow$).toBeObserable(cold('-a', { a: action }))

    expect(actions$).toSatisfyOnFlush(() => {
      expect(service.info).toHaveBeenCalledWith(payload);
    });
  });

Upvotes: 1

Ravi Anand
Ravi Anand

Reputation: 5534

If someone interested without explicit subscription of effect and using only jasmine-marbles

it('should call a notification service method info with a payload', () => {
    actions$ = cold('a', { a: new notificationAction.NotificationShowAction(payload) });
    
    // `toBeObservable` will subscribe the effect and does the trick
    expect(effects.notificationShow$).toBeObservable(actions$);
    expect(service.info).toHaveBeenCalledWith(payload);
  });

Upvotes: 0

Neurotransmitter
Neurotransmitter

Reputation: 6817

The easiest (and officially suggested) way is to do it like this:

    it('should navigate to the customers detail page', () => {
      actions$ = of({ type: '[Customers Page] Customer Selected', name: 'Bob' });

      // create a spy to verify the navigation will be called
      spyOn(router, 'navigateByUrl');

      // subscribe to execute the Effect
      effects.selectCustomer$.subscribe();

      // verify the navigation has been called
      expect(router.navigateByUrl).toHaveBeenCalledWith('customers/bob');
    });

Here is the source.

Upvotes: 9

David Sajdl
David Sajdl

Reputation: 174

it('should call a notification service method info with a payload', () => {
    actions$ = cold('a', { a: new notificationAction.NotificationShowAction(payload) });
    effects.notificationShow$.subscribe(() => {
      expect(service.info).toHaveBeenCalledWith(payload);
    });
  });

It works well but the problem is when an error occur. In this case error is not reported to the test runner (to jest in my case). I need to add try catch block to get error:

   it('should call a notification service method info with a payload', () => {
        actions$ = cold('a', { a: new notificationAction.NotificationShowAction(payload) });
        effects.notificationShow$.subscribe(() => {
            try {
                expect(service.info).toHaveBeenCalledWith(payload); 
            } catch (error) {
                fail('notificationShow$: ' + error);
            }
        });
    });

Upvotes: -1

camden_kid
camden_kid

Reputation: 12813

So it's as simple as this:

describe('notificationShow$', () => {
  let effects: NotificationEffects;
  let service: any;
  let actions$: Observable<Action>;
  const payload = {test: 123};

  beforeEach( () => {
    TestBed.configureTestingModule( {
      providers: [
        NotificationEffects,
        provideMockActions( () => actions$ ),
        {
          provide: NotificationService,
          useValue: jasmine.createSpyObj('NotificationService', ['info'])
        }
      ]
    } );

    effects = TestBed.get(NotificationEffects);
    service = TestBed.get(NotificationService);
  });

  it('should call a notification service method info with a payload', () => {
    actions$ = cold('a', { a: new notificationAction.NotificationShowAction(payload) });
    effects.notificationShow$.subscribe(() => {
      expect(service.info).toHaveBeenCalledWith(payload);
    });
  });
});

Upvotes: 23

Related Questions