простейший возможный тест на выходную привязку не работает - PullRequest
0 голосов
/ 30 мая 2019

Я тестирую простой мертвый компонент одной кнопкой.Когда кнопка нажата, она генерирует событие (@output) и затем вызывается обратный вызов родителя (chatMessageFeedbackHandler).Ничего необычного.

Но по какой-то причине следующий тест не работает.Я просто проверяю, вызывается ли родительский chatMessageFeedbackHandler при нажатии на button#test1 ребенка.

Примечание. Если вы прокомментируете, один из следующих тестов будет работать успешно:

  1. LINE:ребенок 1.1 и ребенок 1.2
  2. LINE: родитель 1.1 и родитель 1.2

Тест:

import {async, ComponentFixture, fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
import {Component, DebugElement} from "@angular/core";
import {AppComponent} from './app.component';
import {By} from '@angular/platform-browser';

function createHostComponent(): ComponentFixture<HostComponent> {
  const fixture = TestBed.createComponent(HostComponent);
  fixture.detectChanges();
  return fixture as ComponentFixture<HostComponent>;
}

fdescribe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<HostComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [HostComponent, AppComponent],
    })
    // .compileComponents();
  }));

  beforeEach(() => {
    // fixture = TestBed.createComponent(ChatFeedbackComponent);
    fixture = createHostComponent();

  });

  fit('should emit chatMessageFeedback$ true when clicked on like button', fakeAsync(() => {
    const appComponent = fixture.debugElement.query(By.directive(AppComponent)) as DebugElement;
    // spyOn(appComponent.componentInstance,'chatFeedbackClicked');//LINE: parent 1.1
    spyOn(fixture.componentInstance,'outputHandler'); //LINE: child 1.1
    fixture.debugElement.nativeElement.querySelector('#test1').click();
    tick(500);
    flushMicrotasks();
    fixture.detectChanges();
    // expect(appComponent.componentInstance.chatFeedbackClicked).toHaveBeenCalled();//LINE: parent 1.2
    expect(fixture.componentInstance.outputHandler).toHaveBeenCalledWith(true);//LINE: child 1.2
  }));

});


@Component({selector: 'host-for-test', template: `
    <app-root (chatMessageFeedback$)="outputHandler($event)"></app-root>
  `})
class HostComponent {

  outputHandler(data) {
    alert();
  }
}

Дочерний компонент:

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

@Component({
  selector: 'app-root',
  template: `
    <button id="test1" (click)="chatFeedbackClicked(true)">Test</button>
  `,
})
export class AppComponent {
  @Output() chatMessageFeedback$ = new EventEmitter();

  chatFeedbackClicked(isFeedbackPositive: boolean) {
    this.chatMessageFeedback$.emit(isFeedbackPositive);
  }
}

1 Ответ

0 голосов
/ 30 мая 2019

Для проверки следующего родительского хост-компонента, вызывающего реальную функцию, когда дочерний элемент выдает , я думаю, что вы решаете проблему не с того конца.

В вашем случаевам нужно смоделировать компонент шаблона (дочерний компонент, компонент app-chat-feedback) и запустить событие вручную (не через весь процесс щелчка, как в случае другого модульного теста).Проверьте ниже, это должно заставить вас работать.

Это макет компонента шаблона

@Component({
    template: '',
    selector: 'app-chat-feedback'
})
export class ChatFeedbackComponentMock {


    @Output() chatMessageFeedback$: EventEmitter<any> = new EventEmitter<any>();

    // This will be the function that triggers the emit
    emitFeedback(value: any) {
        this.chatMessageFeedback$.emit(value);
    }
}

Это компонент, функциональность которого вы тестируете, в данном случае, чтоchatFeedbackClicked вызывается, когда ребенок генерирует событие.Это реальный компонент.

@Component({
    template:`
        // Your Logic here
        <app-chat-feedback (chatMessageFeedback$)="chatFeedbackClicked($event)"></app-chat-feedback>
    `
})
export class MyComponentUnderTest {
    chatFeedbackClicked() {
        // Your logic here
    }
}

Это определение теста.

describe('MyComponentUnderTest', () => {

    let fixture: ComponentFixture<MyComponentUnderTest>;
    let component: MyComponentUnderTest;

    beforeEach(() => {
        // Register both the real component under test, and the mock component of the child
        TestBed.configureTestingModule({
            declarations: [ ChatFeedbackComponentMock, MyComponentUnderTest]
        });

        // Get a handle to the component fixture, and the component instancce
        fixture = TestBed.createComponent(MyComponentUnderTest);
        component = fixture.componentInstance;
    });

    // Important that you have the fakeAsync wrapper function, since the EventEmmiter behaves asynchronously
    it('Should call chatFeedbackClicked when the chatMessageFeedback$ event is fired', fakeAsync(() => {

        // Get a handle of the instance of the child mock component (the template component that you're mocking)
        let child: ChatFeedbackComponentMock = fixture.debugElement.query(By.css('app-chat-feedback')).componentInstance;  

        // Spy on the function of the component under test, that will be asserted
        spyOn(component, 'chatFeedbackClicked');

        // Call emit feedback with some value, on the child component. This will trigger an emit call
        child.emitFeedback('value');

        // Since the calls are asynchronous, (EventEmmitter behaves like an observable), we need to simulate passing of time
        tick();

        // Assert that the function was called with the passed value
        expect(component.chatFeedbackClicked).toHaveBeenCalledWith('value');
    }));
});

Подробнее о тестировании асинхронных функций здесь и о fakeAsync функции-обертке здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...