输出绑定不起作用的最简单的可能测试

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (6)

我用一个按钮测试一个死的简单组件。单击按钮时,它会发出一个(@output)事件,然后调用父的callback(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);
  }
}
提问于
用户回答回答于

要测试以下父主机组件,调用实际功能,当子项发出时,我认为您正在从错误的一端解决问题。

在您的情况下,您需要模拟,模板组件(子,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包装函数的信息

扫码关注云+社区

领取腾讯云代金券