J'ai un composant qui utilise un EventEmitter et l'EventEmitter est utilisé lorsque quelqu'un sur la page est cliqué. Est-il possible d'observer l'EventEmitter pendant un test unitaire et d'utiliser TestComponentBuilder pour cliquer sur l'élément qui déclenche la méthode EventEmitter.next () et voir ce qui a été envoyé?
unit-testing
angular
tallkid24
la source
la source
Réponses:
Votre test pourrait être:
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'); });
lorsque votre composant est:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
la source
<my-component (myEventEmitter)="function($event)"></my-component>
et dans le test que je fais: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)Vous pouvez utiliser un espion, cela dépend de votre style. Voici comment utiliser facilement un espion pour voir s'il
emit
est renvoyé ...it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
la source
expect
l'espion réel (résultat de l'spyOn()
appel)?Vous pouvez vous abonner à l'émetteur ou vous y lier, s'il s'agit d'un
@Output()
, dans le modèle parent et vérifier dans le composant parent si la liaison a été mise à jour. Vous pouvez également envoyer un événement de clic, puis l'abonnement devrait se déclencher.la source
TestComponent
has<my-component (someEmitter)="value=$event">
(oùsomeEmitter
est un@Output()
), alors lavalue
propriété deTextComponent
doit être mise à jour avec l'événement envoyé.J'avais besoin de tester la longueur du tableau émis. C'est ainsi que j'ai fait cela en plus d'autres réponses.
la source
Bien que les réponses aux votes les plus élevés fonctionnent, elles ne démontrent pas de bonnes pratiques de test, j'ai donc pensé développer la réponse de Günter avec quelques exemples pratiques.
Imaginons que nous ayons le composant simple suivant:
@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!'); } }
Le composant est le système testé, espionner certaines de ses parties casse l'encapsulation. Les tests de composants angulaires ne devraient connaître que trois choses:
fixture.nativeElement.querySelector
);@Input
s et@Output
s; etTout ce qui implique l'invocation directe de méthodes sur l'instance ou l'espionnage de parties du composant est trop étroitement lié à l'implémentation, et ajoutera du frottement au refactoring - les doubles de test ne devraient être utilisés que pour les collaborateurs. Dans ce cas, comme nous n'avons pas de collaborateurs, nous ne devrions pas avoir besoin de simulacres, d'espions ou d'autres doublons de test.
Une façon de tester ceci est de s'abonner directement à l'émetteur, puis d'appeler l'action de clic (voir Composant avec entrées et sorties ):
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!'); }); });
Bien que cela interagisse directement avec l'instance de composant, le nom de
@Output
fait partie de l'API publique, il n'est donc pas trop étroitement couplé.Vous pouvez également créer un hôte de test simple (voir Composant dans un hôte de test ) et monter réellement votre composant:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
puis testez le composant en contexte:
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!'); }); });
Le
componentInstance
ici est l' hôte de test , donc nous pouvons être sûrs que nous ne sommes pas trop Coupled pour la composante nous fait tester.la source