Search code examples
angularunit-testingjasminestorengxs

NGXS: Testing dispatched action is not working with ofActionDispatched


I'm trying to test action dispatching, but it just doesn't work in my tests... Component behaves fine, action is dispatched, but actions$.pipe does not catch the action, so it can't be checked in the test.

Code:

describe('ResponsiveService', () => {
  let store, actions$;
  const observableMediaMock = {
    subscribe : (callback: (change: MediaChange) => void) => { 
      this.callback = callback 
    },
    triggerMediaChange: (change: MediaChange) => this.callback(change)
  };
  beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [
            FlexLayoutModule,
            NgxsModule.forRoot([MediaState])
        ],
        providers: [ResponsiveService, { provide: ObservableMedia, useValue: observableMediaMock }]
    });
    store = TestBed.get(Store);
    actions$ = TestBed.get(Actions);
  });

  it('should be created', inject([ResponsiveService], (service: ResponsiveService) => {
    expect(service).toBeTruthy();
  }));

  it("should send get request", function(done) {
    inject([ResponsiveService], (service: ResponsiveService) => {
      const mediaQueryValue = 'mediaQuery',
            mqAliasValue = 'mqAlias',
            suffixValue = 'suffix';

      actions$.pipe(ofActionDispatched([MediaChanged]))
      .subscribe(({payload}) => {
        expect(payload).toBeTruthy();
        expect(payload.mediaQuery).toEqual(mediaQueryValue);
        done();
      });
      service.init();

      observableMediaMock.triggerMediaChange(new MediaChange(null, mediaQueryValue, mqAliasValue, suffixValue));
    })(); // function returned by 'inject' has to be invoked
  });
});

Thanks!


Solution

  • Update your test to the following:

    it("should send get request", async( () => {
      inject([ResponsiveService], (service: ResponsiveService) => {
      const mediaQueryValue = 'mediaQuery',
            mqAliasValue = 'mqAlias',
            suffixValue = 'suffix';
    
      actions$.pipe(ofActionDispatched(MediaChanged))
      .subscribe(({payload}) => {
        expect(payload).toBeTruthy();
        expect(payload.mediaQuery).toEqual(mediaQueryValue);
      });
      service.init();
    
      observableMediaMock.triggerMediaChange(new MediaChange(null, mediaQueryValue, mqAliasValue, suffixValue));
      })(); // function returned by 'inject' has to be invoked
    }));
    

    ofActionDispatched does not take a list as input, but rater takes a list of items eg.: ofActionDispatched(MediaChanged, SomeOtherAction).

    You should also be able to remove the done function and just wrap the test in a normal async block. Hope this helps, not sure if I opened and closed all the brackets correctly.