3

My component looks for presence of a parameter in the route in ngOnInit. If the parameter is not present, it shows error. I want to test this logic.

ngOnInit() {
    this.id = this.route.snapshot.paramMap.get("id");
    if(this.id != null) {
...    } else{
      console.log("didn't get id from the route");
      this.showDialog(...);
    }
  }

I wrote the following spec. In the spec, the parameter is not passed in the route

 beforeEach(async() => {

    fixture = TestBed.createComponent(QuestionDetailsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

fit('should show error if question details of a question can\'t be retrieved', () => {
    spyOn(component,'showDialog');
    expect(componetn.showDialog).toHaveBeenCalled();
  });

but my test case fails with reason Expected spy showDialog to have been called.

I suppose the issue is that showDialog gets called when the component gets created before the it is called.

How do I test the logic in ngOnInit? I need the component before I can test it (i.e. call it) and I want to test the logic which gets executed while the component is being created.

Alessio
  • 3,404
  • 19
  • 35
  • 48
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184

1 Answers1

2

To test the ngOnInit method, you just need to call it:

component.ngOnInit();

And the route value can be spied:

spyOn(component.route.snapshot.paramMap,"get").and.returnValue("some_id");

Also, you can change the returned value. For example:

fit("should ...", () => {
  let mock_id = null;
  spyOn(component,"showDialog");

  spyOn(component.route.snapshot.paramMap,"get").and.callFake(() => {
      return mock_id;
  });

  component.ngOnInit();
  expect(componetn.showDialog).toHaveBeenCalled();
  expect(componetn.showDialog).toHaveBeenCalledTimes(1);

  mock_id = "some_value";
  component.ngOnInit();
  expect(...).to..
  ...
  expect(componetn.showDialog).toHaveBeenCalledTimes(1);

  mock_id = "another_value";
  component.ngOnInit();
  expect(...).to..
  ...
  expect(componetn.showDialog).toHaveBeenCalledTimes(1);
});
J. Sarabia
  • 158
  • 9
  • many thanks. Your note about `spyOn(component.route.snapshot.paramMap,"get").and.returnValue("some_id")` solve the problem https://stackoverflow.com/questions/54753695/how-to-set-a-route-before-a-component-is-created-in-unit-test as well. If you write this as the answer there, I'll happily accept it. – Manu Chadha Feb 21 '19 at 06:05
  • I notice a potential issue in your solution. I had to make `route` public so that I could access it in the spec. Is there an alternative? – Manu Chadha Feb 21 '19 at 06:41
  • No, there is no need to make `route` public. I think what "bothers" is the editor. The fastest way to ignore this for me (I use VSCode) is: `spyOn(component["route"].snapshot.paramMap,"get").and.returnValue("some_id") ` – J. Sarabia Feb 21 '19 at 16:25