angularjasminengxs

How trigger ngxsAfterBootstrap in jasmine unit tests?


In my angular application I use NGXS and Jasmine.

In some of my stores I use ngxsAfterBootstrap as initialization where I dispatch some actions.

I can't use ngxsOnInit because, don't know exactly why, but I can't get my up-to-date url parameters from my RouteState selectors (always undefined in ngxsOnInit, even when I subscribe to these selectors and wait a few amount of time)

But, with ngxsAfterBootstrap i get theses values.

So, in my unit tests, I want to test this initialization but I didn't find any solution to trigger ngxsAfterBootstrap method.

According to the NGXS documentation (https://www.ngxs.io/advanced/life-cycle), ngxsAfterBootstrap will be triggered via APP_BOOTSTRAP_LISTENER, so I think it's when we use the 'bootstrap' property of ngModule, which is not existing in TestBed.configureTestingModule ...

I tried to get my store instance, call manually his ngxsAfterBootstrap method with a StateContext mocked as argument, but obviously, because StateContext is mocked, it not trigger my actions when i use his dispatch ...

Did you know any "clean" solution about this ? (clean, here, is just to not modify my implementation to make the unit test working)

Thx ! (sorry for my bad English)

EDIT:

What I finally did :

productStore = TestBed.inject(ProductState);

...

const stateContextMocked = {
      getState: jasmine.createSpy(),
      setState: jasmine.createSpy(),
      patchState: jasmine.createSpy(),
      dispatch: jasmine.createSpy(),
} as StateContext<IProduct>;

 ...

productStore.ngxsAfterBootstrap(stateContextMocked);

...

expect(stateContextMocked.dispatch).toHaveBeenCalledWith(new GetProductAction(productIdMocked));

I tried to do that before, but i didn't like it because i couldn't use the "real" StateContext object which is automatically passed in argument of ngxsAfterBootstrap.

So, i couldn't the result of my dispatch.

But in fact, i can just test if my dispatch method has been called, and have another test that test the action dispatched itself.

It's even a better approach ^^


Solution

  • Let's say we want to test ngOnInit.

    1. In //Arrange step of the test, we mock all external dependencies, including public component methods (component methods are not mandatory by the way, it depends on our approach).
    2. Afterwards in //Act we trigger ngOnInit by simply calling
    component.ngOnInit();
    
    1. And finally in //Assert we expect that our spies have been called.

    Same approach is with ngxsAfterBootstrap, you should look at it as a simple class method. No need to overcomplicate things.