NGXS: How to test if an action was dispatched?

Francesco Cina picture Francesco Cina · Jun 28, 2018 · Viewed 7.8k times · Source

How to unit test whether an action was dispatched?

For example, in a LogoutService, I have this simple method:

  logout(username: string) {
    store.dispatch([new ResetStateAction(), new LogoutAction(username)]);
  }

I need to write a unit test that verifies that the two actions are dispatched:

  it('should dispatch ResetState and Logout actions', function () {
    logoutService.logout();

    // how to check the dispactched actions and their parameters?
    // expect(...)
  });

How can I check the dispatched actions?

Answer

Brampage picture Brampage · Aug 2, 2018

NGXS Pipeable Operators

Actions in NGXS are handled with Observables. NGXS provides you Pipeable Operators, for your test you could use the ofActionDispatched. Here is the list I have taken from the NGXS documentation:

  • ofAction triggers when any of the below lifecycle events happen
  • ofActionDispatched triggers when an action has been dispatched
  • ofActionSuccessful triggers when an action has been completed successfully
  • ofActionCanceled triggers when an action has been canceled
  • ofActionErrored triggers when an action has caused an error to be thrown
  • ofActionCompleted triggers when an action has been completed whether it was successful or not (returns completion summary)

Answer

1. Create variable actions$

describe('control-center.state', () => {
  let actions$: Observable<any>;

  // ...
});

2. Initialize variable actions$ with observable

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [
      NgxsModule.forRoot([AppState]),
      NgxsModule.forFeature([ControlCenterState])
    ]
  });
  store = TestBed.get(Store);
  actions$ = TestBed.get(Actions);
})

3.1 Test if 1 action has been called:

Filter your actions from the stream with the operator ofActionsDispatched().

it('should dispatch LogoutAction', (done) => {
  actions$.pipe(ofActionDispatched(LogoutAction)).subscribe((_) => {
    done();
  });

  service.logout();
});

3.2 Test if multiple actions have been called:

Use the RXJS zip operator to combine the two observables with the ofActionsDispatched() function (zip: after all observables emit, emit values as an array).

it('should dispatch ResetStateAction and LogoutAction', (done) => {
  zip(
    actions$.pipe(ofActionDispatched(ResetStateAction)),
    actions$.pipe(ofActionDispatched(LogoutAction))
  ).subscribe((_) => {
    done();
  });

  service.logout();
});

The spec will not complete until its done is called. If done is not called a timeout exception will be thrown.

From the Jasmine documentation.