Eu tenho um componente que usa um EventEmitter e o EventEmitter é usado quando alguém na página é clicado. Existe alguma maneira de observar o EventEmitter durante um teste de unidade e usar TestComponentBuilder para clicar no elemento que aciona o método EventEmitter.next () e ver o que foi enviado?
unit-testing
angular
tallkid24
fonte
fonte
Respostas:
Seu teste pode ser:
it('should emit on click', () => { const fixture = TestBed.createComponent(MyComponent); // spy on event emitter const component = fixture.componentInstance; spyOn(component.myEventEmitter, 'emit'); // trigger the click const nativeElement = fixture.nativeElement; const button = nativeElement.querySelector('button'); button.dispatchEvent(new Event('click')); fixture.detectChanges(); expect(component.myEventEmitter.emit).toHaveBeenCalledWith('hello'); });
quando seu componente é:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
fonte
<my-component (myEventEmitter)="function($event)"></my-component>
e no teste eu faço: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)Você pode usar um espião, depende do seu estilo. Veja como você usaria um espião facilmente para ver se
emit
está sendo disparado ...it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
fonte
expect
o espião real (resultado daspyOn()
ligação)?Você pode assinar o emissor ou vincular-se a ele, se for um
@Output()
, no modelo pai e verificar no componente pai se a vinculação foi atualizada. Você também pode enviar um evento de clique e a assinatura deve ser disparada.fonte
TestComponent
has<my-component (someEmitter)="value=$event">
(ondesomeEmitter
é um@Output()
) então avalue
propriedade deTextComponent
deve ser atualizada com o evento enviado.Tive a necessidade de testar o comprimento da matriz emitida. Então foi assim que fiz isso em cima de outras respostas.
fonte
Embora as respostas com maior votação funcionem, elas não estão demonstrando boas práticas de teste, então pensei em expandir a resposta de Günter com alguns exemplos práticos.
Vamos imaginar que temos o seguinte componente simples:
@Component({ selector: 'my-demo', template: ` <button (click)="buttonClicked()">Click Me!</button> ` }) export class DemoComponent { @Output() clicked = new EventEmitter<string>(); constructor() { } buttonClicked(): void { this.clicked.emit('clicked!'); } }
O componente é o sistema em teste, espionando partes dele quebras de encapsulamento. Os testes de componentes angulares devem saber apenas sobre três coisas:
fixture.nativeElement.querySelector
);@Input
s e@Output
s; eQualquer coisa que envolva invocar métodos diretamente na instância ou espionar partes do componente está muito intimamente ligada à implementação e adicionará atrito à refatoração - duplas de teste devem ser usadas apenas para os colaboradores. Neste caso, como não temos colaboradores, devemos não precisa de nenhum simulações, espiões ou outras duplas de teste.
Uma maneira de testar isso é inscrevendo-se diretamente no emissor e, em seguida, invocando a ação de clique (consulte Componente com entradas e saídas ):
describe('DemoComponent', () => { let component: DemoComponent; let fixture: ComponentFixture<DemoComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ DemoComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(DemoComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should emit when clicked', () => { let emitted: string; component.clicked.subscribe((event: string) => { emitted = event; }); fixture.nativeElement.querySelector('button').click(); expect(emitted).toBe('clicked!'); }); });
Embora isso interaja diretamente com a instância do componente, o nome do
@Output
faz parte da API pública, portanto, não é muito acoplado.Como alternativa, você pode criar um host de teste simples (consulte Componente dentro de um host de teste ) e realmente montar seu componente:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
em seguida, teste o componente no contexto:
describe('DemoComponent', () => { let component: TestHostComponent; let fixture: ComponentFixture<TestHostComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ TestHostComponent, DemoComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(TestHostComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should emit when clicked', () => { fixture.nativeElement.querySelector('button').click(); expect(component.lastClick).toBe('clicked!'); }); });
A
componentInstance
aqui é o anfitrião de teste , para que possamos ter a certeza de que não estamos excessivamente acoplado ao componente estamos testando realmente.fonte