Mam składnik, który używa EventEmitter i EventEmitter jest używany, gdy ktoś na stronie zostanie kliknięty. Czy istnieje sposób, w jaki mogę obserwować EventEmitter podczas testu jednostkowego i użyć TestComponentBuilder, aby kliknąć element, który wyzwala metodę EventEmitter.next () i zobaczyć, co zostało wysłane?
unit-testing
angular
tallkid24
źródło
źródło
Odpowiedzi:
Twój test mógłby wyglądać następująco:
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'); });
kiedy twój komponent jest:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
źródło
<my-component (myEventEmitter)="function($event)"></my-component>
iw teście robię: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)Możesz użyć szpiega, zależy od twojego stylu. Oto, w jaki sposób możesz łatwo wykorzystać szpiega, aby sprawdzić, czy
emit
nie został zwolniony ...it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
źródło
expect
rzeczywistym szpiegiem (wynikspyOn()
rozmowy)?Możesz zasubskrybować emiter lub powiązać z nim, jeśli jest to
@Output()
, w szablonie nadrzędnym i sprawdzić komponent nadrzędny, czy powiązanie zostało zaktualizowane. Możesz również wywołać zdarzenie kliknięcia, a następnie subskrypcja powinna zostać uruchomiona.źródło
TestComponent
has<my-component (someEmitter)="value=$event">
(gdziesomeEmitter
jest@Output()
) tovalue
właściwośćTextComponent
powinna zostać zaktualizowana o wysłane zdarzenie.Miałem wymóg przetestowania długości emitowanej tablicy. Tak więc zrobiłem to na tle innych Answers.
źródło
Chociaż najwyżej ocenione odpowiedzi działają, nie są one przykładem dobrych praktyk testowania, więc pomyślałem, że poszerzę odpowiedź Güntera o kilka praktycznych przykładów.
Wyobraźmy sobie, że mamy następujący prosty element:
@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!'); } }
Składnik jest testowanym systemem, szpiegowanie jego części powoduje przerwanie hermetyzacji. Testy komponentów kątowych powinny wiedzieć tylko o trzech rzeczach:
fixture.nativeElement.querySelector
);@Input
s i@Output
S; iWszystko, co wiąże się z bezpośrednim wywoływaniem metod w instancji lub szpiegowaniem części komponentu, jest zbyt ściśle powiązane z implementacją i może powodować tarcie w refaktoryzacji - test podwójny powinien być używany tylko dla współpracowników. W tym przypadku, ponieważ nie mamy współpracowników, nie powinniśmy potrzebować żadnych fałszywych szpiegów ani innych podwójnych testów.
Jednym ze sposobów sprawdzenia tego jest zapisanie się bezpośrednio do emitera, a następnie wywołanie akcji kliknięcia (zobacz Komponent z wejściami i wyjściami ):
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!'); }); });
Chociaż to współdziała bezpośrednio z wystąpieniem składnika, nazwa
@Output
jest częścią publicznego interfejsu API, więc nie jest zbyt ściśle powiązana.Alternatywnie możesz utworzyć prostego hosta testowego (zobacz Komponent wewnątrz hosta testowego ) i faktycznie zamontować swój komponent:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
następnie przetestuj komponent w kontekście:
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
Tu jest gospodarzem testu , więc możemy być pewni, że nie jesteśmy zbyt połączeniu ze składnikiem jesteśmy faktycznie testowania.źródło