3

I am little new to writing unit tests for Angular and not able to figure out how I can write unit tests for a component with a @Input directive.

Here is my

== file.component.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-bugs-table',
  templateUrl: './bugs-table.component.html',
  styleUrls: ['./bugs-table.component.scss']
})
export class BugsTableComponent implements OnInit {
//   priorityData: any = [];
  @Input() bugsDataService;
  @Input() gridItemComponent;
  constructor(
  ) {  }

  ngOnInit() {

  }
    ngAfterViewInit() {
this.bugsDataService.subscribe(response => {
  this.bugsData = response;
})

} }

Here is my file.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule, } from '@angular/forms';
import { HttpModule, BrowserXhr } from "@angular/http";

fdescribe('BugsTableComponent', () => {
  let component: BugsTableComponent;
  let fixture: ComponentFixture<BugsTableComponent>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BugsTableComponent ],
      imports: []
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(BugsTableComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit('should create', () => {
    expect(component).toBeTruthy();
  });
});

But it fails with error:

× should create HeadlessChrome 69.0.3497 (Windows 10.0.0) TypeError: Cannot read property 'subscribe' of undefined

I know this is because bugsDataService (which is a observable) is undefined. Can any please help fixing this. Please let me know if you need more info.

3
  • First of all why do you input a service? The service should be injected. Secondly, have you tried setting component.bugsDataService ? Commented Sep 28, 2018 at 19:09
  • actually this is an Observable data. (yes, kind of service)... but this is how it is. component.bugsDataService : can you show an exmaple please. Commented Sep 28, 2018 at 19:11
  • Did you ever get this solved? I suspect your beforeEach functions were not executing. Commented Feb 4, 2022 at 16:34

2 Answers 2

4

the following works:

Include this import:

import { of } from 'rxjs';

Change the beforeEach block for the file to:

beforeEach(() => {
  fixture = TestBed.createComponent(BugsTableComponent);
  component = fixture.componentInstance;

  // needed because ngAfterViewInit gets called and if there isn't an observable to subscribe to it will fail
  component.bugsDataService = of(null);

  fixture.detectChanges();
});

Write a test:

it('Should assign the input value to bugsdata', () => {
  // Arrange
  component.bugsData = {}; // to make sure it's empty at the start
  const resultFromService = {hello: 'world'};
  component.bugsDataService = of(resultFromService); // this creates an observable from resultFromService

  // Act
  component.ngAfterViewInit();

  // Assert
  expect(component.bugsData).toEqual(resultFromService);
});

Some notes:

  • I've noticed is that your component has a ngAfterViewInit but the class does not implement it. If you're not using ngOnInit then replace it in the class declaration with ngAfterViewInit and update the imports.
  • If you don't want to do the change I suggested in the beforeEach block you can move the subscribe line from ngAfterViewInit to a separate method that is called by ngAfterViewInit. However, you'll then need to spy on it so it doesn't actually get called.
Sign up to request clarification or add additional context in comments.

Comments

0
beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BugsTableComponent ],
      imports: [],
      providers: [BugsDataService] // inject service here 
    })
    .compileComponents();
  }));

This should fix the bug but

If you want to Simulate the actual behaviour of the service better way would be to create a mock service which extends BugsDataService and use it in the unit test cases to provide Mock Data

example

@Injectable()
export class BugsDataMockService extends BugsDataService {

overridenMethod() {
return Observable.of( { data : yourmockresponse });
}


And in your Spec file (Unit test)
beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BugsTableComponent ],
      imports: [],
      providers: [ { provide: BugsDataService, useClass: BugsMockDataService } ] // Use Mock Service instead of original one 
    })
    .compileComponents();
  }));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.