Angular Test Jest - TypeError: Cannot read property 'queryParams' of undefined

2.7k views Asked by At

I've seen the same error in other posts but they didn't work for me.

I have an Angular component, where I need to read a queryParam from the url, for example in http://localhost:4200/sample-page?page=3 I want to stores the number 3 into a component local variable.

/**
 * Set page by url parameter
 */
export const setPaginationMarkByUrlParam = (activatedRoute): number => {
  // Get page param from Url to set pagination page
  const pageParam = activatedRoute.snapshot.queryParams;
  return pageParam.page ? Number(pageParam.page) : 1;
};

This function is in another file and I put as parameter the activeRoute, which comes from the ngOnInit of the component in which I want to get the queryParam.

ngOnInit() {
    this.page = setPaginationMarkByUrlParam(this.activatedRoute);
}

This code works perfectly, but when the Jenkins pipeline runs the npx jest tests, I get the following message: TypeError: Cannot read property 'queryParams' of undefined

My Spec.ts:

beforeEach(() => {
      TestBed.configureTestingModule({
        ...,
        providers: [
          {
            provide: ActivatedRoute,
            useValue: {
              data: {
                subscribe: (fn: (value: Data) => void) =>
                  fn({
                    pagingParams: {
                      predicate: 'id',
                      reverse: false,
                      page: 0
                    }
                  })
              }
            }
          }
        ]...

it('Should call load all on init', () => {
      // GIVEN
      const headers = new HttpHeaders().append('link', 'link;link');
      spyOn(service, 'query').and.returnValue(
        of(
          new HttpResponse({
            body: [new DataSource(123)],
            headers
          })
        )
      );

      // WHEN
      comp.ngOnInit();

      // THEN
      expect(service.query).toHaveBeenCalled();
      expect(comp.dataSources[0]).toEqual(jasmine.objectContaining({ id: 123 }));
    });

The test fails in comp.ngOnInit(); function.

I don't have any kind of private variables, the activeRoute that comes as a parameter, I tried it with public and private.

Looking at both StackOverflow and GitHub Issues I have not been able to fix this problem.

Thank you very much!

2

There are 2 answers

0
Randy Casburn On

While you are mocking data, you are not mocking snapshot on ActivatedRoute. You have three choices to accomplish this:

  1. First, you should consider using an ActivatedRouteStub as described in the docs. This then makes is as easy as: activatedRoute.setParamMap({page: 3}); to set any queryParameter you want to set. This option requires more test code

  2. Next option: this would mock the queryParameter of page on the ActivatedRoute with an Observable:

  provide: ActivatedRoute, useValue: {
    snapshot: of(queryParams: { page: 3 }),
  }
  1. If, for a reason not disclosed in your question, you do not need an Observable from your ActivatedRoute, this would be the alternate code:
  provide: ActivatedRoute, useValue: {
    snapshot: { queryParams: { page: 3 } }
  }

Finally, the code you provided doesn't have a call to inject for the ActivatedRoute provider nor does it show the test component creation. So at a minimum ensure you are doing that as well:

Either:

fixture = TestBed.createComponent(...);

Or:

activatedRoute = TestBed.inject(ActivatedRoute);

If none of these suggestions solve your problem, put a a minimal StackBlitz that demonstrates the problem and we'll get it working.

0
S.Voulgaris On

Generally for configuring/mocking different RouteOptions when you have ActivatedRoute with Jest you should use:

  1. createRoutingFactory from @ngneat/spectator/jest
  2. and pass one or more of the RouteOptions properties like (params, queryParams, parent etc.) directly on its constructor

For example:

const createComponent = createRoutingFactory({
component: Component,
imports: [RouterTestingModule],
parent: {
  snapshot: {
    queryParamMap: convertToParamMap({
      //...
    }),
    paramMap: convertToParamMap({
     //...
    })
  } 
 }
});