Minto
Minto

Reputation: 57

Angular unit test ngOnInit subscription

I am starting out with unit testing in Angular 9 with Jasmine.

I am testing a simple component which implements ngOnInit:

export class HomeComponent implements OnInit {

      constructor(private router: Router
        , private authenticationService: AuthenticationService) { }

        ngOnInit(): void {
        this.authenticationService.checkIsAuthenticatedObservable()
        .subscribe(
          (isAuthenicated: boolean) => {
            if (isAuthenicated === true) {
              this.router.navigate(['/observation-feed']);
            }
          });
        }
      }

I am hitting the error with executing the ngOnInIt lifecycle hook:

TypeError: Cannot read property 'subscribe' of undefined
    at <Jasmine>
    at HomeComponent.ngOnInit (http://localhost:9876/_karma_webpack_/main.js:8140:13)

My test spec is setup like this:

describe('HomeComponent', () => {
  let component: HomeComponent;
  let fixture: ComponentFixture<HomeComponent>;
  let router: Router;
  let mockAuthenticationService;

  beforeEach(async(() => {
    mockAuthenticationService = jasmine.createSpyObj(['checkIsAuthenticatedObservable']);

    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule.withRoutes([
          // { path: 'login', component: DummyLoginLayoutComponent },
        ])
      ],
      declarations: [ HomeComponent ],
      providers: [
        { provide: AuthenticationService, useValue: mockAuthenticationService }
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HomeComponent);
    router = TestBed.get(Router);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    mockAuthenticationService.checkIsAuthenticatedObservable.and.returnValue(of(false));
    fixture.detectChanges();
    // component.ngOnInit();

    expect(component).toBeTruthy();
  });
});

I have attempted various combinations of setting up the mock object, and calling fixture.detectChanges(); and component.ngOnInit(); at different points in the intialization. None of what I have tried has worked. What's going wrong here?

Upvotes: 1

Views: 6047

Answers (1)

Maciej Kasprzak
Maciej Kasprzak

Reputation: 949

When you are calling fixture.detectChanges in the beforeEach section, Angular runs lifecycle hooks and ngOnInit is called. This is why you're getting error - you are mocking checkIsAuthenticatedObservable in the test, after the first fixture.detectChanges. Move your mock to the beforeEach section, before fixture.detectChanges and it will work correctly. Also, with Angular 9, you should use TestBed.inject instead of TestBed.get which is now deprecated.

beforeEach(() => {
    fixture = TestBed.createComponent(HomeComponent);
    router = TestBed.inject(Router);
    component = fixture.componentInstance;
    mockAuthenticationService.checkIsAuthenticatedObservable.and.returnValue(of(false));
    fixture.detectChanges();
  });

  it('should create', () => {
    fixture.detectChanges();
    expect(component).toBeTruthy();
  });

Upvotes: 8

Related Questions