У меня есть компонент, который использует EventEmitter, а EventEmitter используется, когда кто-то щелкает на странице. Есть ли способ, которым я могу наблюдать за EventEmitter во время модульного теста и использовать TestComponentBuilder, чтобы щелкнуть элемент, который запускает метод EventEmitter.next (), и посмотреть, что было отправлено?
unit-testing
angular
Tallkid24
источник
источник
Ответы:
Ваш тест может быть:
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'); });
когда ваш компонент:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
источник
<my-component (myEventEmitter)="function($event)"></my-component>
а в тесте я использую: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)Вы можете использовать шпиона, в зависимости от вашего стиля. Вот как можно легко использовать шпиона, чтобы узнать
emit
, стреляют ли его ...it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
источник
expect
настоящим шпионом (результатомspyOn()
звонка)?Вы можете подписаться на эмиттер или выполнить привязку к нему, если он есть
@Output()
, в родительском шаблоне и проверить в родительском компоненте, была ли обновлена привязка. Вы также можете отправить событие щелчка, и тогда подписка должна сработать.источник
TestComponent
has<my-component (someEmitter)="value=$event">
(гдеsomeEmitter
есть@Output()
), тогдаvalue
свойствоTextComponent
должно быть обновлено отправленным событием.У меня было требование проверить длину испускаемого массива. Вот как я сделал это поверх других ответов.
источник
Хотя ответы с наибольшим количеством голосов работают, они не демонстрируют хорошие методы тестирования, поэтому я подумал, что могу расширить ответ Гюнтера некоторыми практическими примерами.
Представим, что у нас есть следующий простой компонент:
@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!'); } }
Компонент - это тестируемая система, наблюдение за ее частями нарушает инкапсуляцию. Тесты компонентов Angular должны знать только три вещи:
fixture.nativeElement.querySelector
);@Input
s и@Output
s; а такжеВсе, что связано с прямым вызовом методов в экземпляре или слежкой за частями компонента, слишком тесно связано с реализацией и добавит трение к рефакторингу - тестовые двойники должны использоваться только для соавторов. В этом случае, поскольку у нас нет соавторов, нам не нужны никакие моки, шпионы или другие тестовые двойники.
Один из способов проверить это - подписаться непосредственно на эмиттер, а затем вызвать действие щелчка (см. Компонент с входами и выходами ):
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!'); }); });
Хотя это напрямую взаимодействует с экземпляром компонента, имя
@Output
является частью общедоступного API, поэтому оно не слишком тесно связано.В качестве альтернативы вы можете создать простой тестовый хост (см. Компонент внутри тестового хоста ) и фактически смонтировать свой компонент:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
затем протестируйте компонент в контексте:
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!'); }); });
componentInstance
Вот тест хозяин , так что мы можем быть уверены в том, что мы не слишком связаны с компонентом , мы на самом деле тестирования.источник