How to test child component @output

Viewed 4856

I would like to test a child component @output in angular2. I want to use this mock child component @output to activate a parent component function and test it.

Mock the component and test all the async method.

<wizard-quick-search-page *ngIf="initSearchPanel" [createUserAttributes]="createUserAttributes" [existingUserAttributes]="existingUserAttributes" (edit)="showEditUserPanel($event)"
  (create)="showCreateUserPanel($event)">
</wizard-quick-search-page>
@Component({
  selector: 'wizard-quick-search-page',
  template: '<button class="quick-search-page-submit" (click)="onClick()">Create</button>'
})
class MockQuickSearchPageComponent {
  @Output() public create: EventEmitter<any> = new EventEmitter<any>();
  public onClick(): void {
    console.log('call create');
    this.create.emit(true);
  }
}

fdescribe('AddUserComponent', () => {
  let component: AddUserComponent;
  let fixture: ComponentFixture<AddUserComponent>;
  let mockQuickSearchComponent: MockQuickSearchPageComponent;
  let mockQuickSearchComponentFixture: ComponentFixture<MockQuickSearchPageComponent>;
  let createButton: DebugElement;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: Language, useClass: MockLanguage }
      ],
      declarations: [
        AddUserComponent,
        MockQuickSearchPageComponent
      ],
      schemas: [NO_ERRORS_SCHEMA]
    })
      .compileComponents();
  }));

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

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

  describe('quickSearchComponent', () => {
    beforeEach(() => {
      mockQuickSearchComponentFixture = TestBed.createComponent(MockQuickSearchPageComponent);
      mockQuickSearchComponent = mockQuickSearchComponentFixture.componentInstance;
      mockQuickSearchComponentFixture.detectChanges();

      createButton = mockQuickSearchComponentFixture.debugElement.query(By.css('button.quick-search-page-submit'));
    });

    it('should create', () => {
      expect(mockQuickSearchComponent).toBeTruthy();
    });

    it('should open create a new user panel', fakeAsync(() => {
      spyOn(component, 'showCreateUserPanel');
      createButton.triggerEventHandler('click', null);
      tick();
      mockQuickSearchComponentFixture.detectChanges();
      expect(component.showCreateUserPanel).toHaveBeenCalled();
    }));
  });
});

Parent component function component.showCreateUserPanel not been called

1 Answers

If you want to test how parent and child communicate to each other then you shouldn't create isolated instance of MockQuickSearchPageComponent but rather use the instance which is initialized within parent component.

Current test

AddUserComponent  MockQuickSearchPageComponent

In your implementation they know nothing about each other.

TestBed.createComponent(MockQuickSearchPageComponent); creates a new component tree with MockQuickSearchPageComponent as a root component

How it should be done

 AddUserComponent  
       ||
       \/
MockQuickSearchPageComponent

Now MockQuickSearchPageComponent is a child of AddUserComponent and can listen for any events emmited from that child component.

It could be done by using fixture.debugElement.query(By.directive(MockQuickSearchPageComponent):

describe('quickSearchComponent', () => {
  beforeEach(() => {
    fixture.componentInstance.initSearchPanel = true;
    fixture.detectChanges();

    const childDirQueryResult = 
             fixture.debugElement.query(By.directive(MockQuickSearchPageComponent));

    mockQuickSearchComponent = childDirQueryResult.componentInstance;

    createButton = childDirQueryResult.query(By.css('button.quick-search-page-submit'));
  });

  it('should create', () => {
    expect(mockQuickSearchComponent).toBeTruthy();
  });

  it('should open create a new user panel', () => {
    spyOn(component, 'showCreateUserPanel');
    createButton.triggerEventHandler('click', null);

    expect(component.showCreateUserPanel).toHaveBeenCalled();
  });
});

Plunker Example

Related