Ich habe eine Komponente, die einen EventEmitter verwendet, und der EventEmitter wird verwendet, wenn jemand auf der Seite angeklickt wird. Gibt es eine Möglichkeit, den EventEmitter während eines Komponententests zu beobachten und mit TestComponentBuilder auf das Element zu klicken, das die EventEmitter.next () -Methode auslöst, und zu sehen, was gesendet wurde?
unit-testing
angular
tallkid24
quelle
quelle
Antworten:
Ihr Test könnte sein:
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'); });
wenn Ihre Komponente ist:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
quelle
<my-component (myEventEmitter)="function($event)"></my-component>
und im Test mache ich: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)Sie könnten einen Spion gebrauchen, hängt von Ihrem Stil ab. So würden Sie einen Spion leicht benutzen, um zu sehen, ob
emit
er abgefeuert wird ...it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
quelle
expect
der eigentliche Spion sein (Ergebnis einesspyOn()
Anrufs)?Sie können den Emitter abonnieren oder, falls vorhanden
@Output()
, in der übergeordneten Vorlage daran binden und in der übergeordneten Komponente überprüfen, ob die Bindung aktualisiert wurde. Sie können auch ein Klickereignis auslösen, und dann sollte das Abonnement ausgelöst werden.quelle
TestComponent
hat<my-component (someEmitter)="value=$event">
(wosomeEmitter
ist eine@Output()
), dann sollte dievalue
Eigenschaft vonTextComponent
mit dem gesendeten Ereignis aktualisiert werden.Ich musste die Länge des emittierten Arrays testen. So habe ich das zusätzlich zu anderen Antworten gemacht.
quelle
Obwohl die Antworten mit den höchsten Stimmen funktionieren, zeigen sie keine guten Testpraktiken. Daher dachte ich, ich würde Günters Antwort mit einigen praktischen Beispielen erweitern.
Stellen wir uns vor, wir haben die folgende einfache Komponente:
@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!'); } }
Die Komponente ist das zu testende System, das Teile davon ausspioniert und die Kapselung unterbricht. Winkelkomponententests sollten nur drei Dinge wissen:
fixture.nativeElement.querySelector
);@Input
s und@Output
s; undAlles, was das direkte Aufrufen von Methoden für die Instanz oder das Ausspionieren von Teilen der Komponente umfasst, ist zu eng mit der Implementierung verbunden und führt zu Reibungsverlusten beim Refactoring. Test-Doubles sollten nur für die Mitarbeiter verwendet werden. In diesem Fall sollten wir, da wir keine Mitarbeiter haben, keine Verspottungen, Spione oder andere Test-Doubles benötigen .
Eine Möglichkeit, dies zu testen, besteht darin, den Emitter direkt zu abonnieren und dann die Klickaktion aufzurufen (siehe Komponente mit Ein- und Ausgängen ):
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!'); }); });
Obwohl dies direkt mit der Komponenteninstanz interagiert, ist der Name von
@Output
Teil der öffentlichen API, sodass er nicht zu eng gekoppelt ist.Alternativ können Sie einen einfachen Testhost erstellen (siehe Komponente in einem Testhost ) und Ihre Komponente tatsächlich bereitstellen:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
Testen Sie dann die Komponente im Kontext:
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!'); }); });
Das
componentInstance
hier ist die Test - Host , so dass wir sicher sein können , wir übermäßig nicht an die Komponente gekoppelt sind wir tatsächlich zu testen.quelle