Bruno.Beraud.PW
Bruno.Beraud.PW

Reputation: 63

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 ^^

Upvotes: 1

Views: 386

Answers (2)

Vilmantas Baranauskas
Vilmantas Baranauskas

Reputation: 6726

Adding following to the beforeEach() block worked fine for me with jest and ngxs v3.8:

TestBed.inject(APP_BOOTSTRAP_LISTENER).forEach((l) => l(fixture.componentRef));

Disclaimer: That was a pure luck, without really understanding how everything is wired behind the scenes.

Upvotes: 0

Victor Muresanu
Victor Muresanu

Reputation: 166

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.

Upvotes: 0

Related Questions