Je voudrais changer la valeur d'un champ de saisie à l'intérieur d'un Angular 2 unités de test.
<input type="text" class="form-control" [(ngModel)]="abc.value" />
Je ne peux pas simplement changer le ngModel
car l'objet abc
est privé:
private abc: Abc = new Abc();
Dans Angular 2 tests, puis-je simuler la saisie de l'utilisateur dans le champ de saisie de sorte que le ngModel
soit mis à jour avec ce que l'utilisateur a saisi à partir d'un test unitaire?
Je peux saisir le DebugElement
et le nativeElement
du champ de saisie sans problème. (Le fait de définir une propriété value
sur le nativeElement
du champ de saisie ne semble pas fonctionner car il ne met pas à jour le ngModel
avec ce que j'ai défini pour la valeur).
Peut être inputDebugEl.triggerEventHandler
_ peut être appelé, mais je ne suis pas sûr des arguments à donner, cela simulera donc l'utilisateur ayant saisi une chaîne d'entrée particulière.
Vous avez raison de dire que vous ne pouvez pas simplement définir l'entrée, vous devez également envoyer l'événement 'input'
. Voici une fonction que j'ai écrite plus tôt ce soir pour saisir du texte:
function sendInput(text: string) {
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
Ici fixture
est le ComponentFixture
et inputElement
est le HTTPInputElement
correspondant à partir du nativeElement
du projecteur. Cela retourne une promesse et vous devrez probablement la résoudre sendInput('whatever').then(...)
.
Dans le contexte: https: //github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134
Mise à jour :
Nous avons eu quelques problèmes pour que cela fonctionne dans Angular 2.1, cela ne lui a pas plu de créer une new Event(...)
] _, alors nous avons plutôt:
import { dispatchEvent } from '@angular/platform-browser/testing/browser-util';
...
function sendInput(text: string) {
inputElement.value = text;
dispatchEvent(fixture.nativeElement, 'input');
fixture.detectChanges();
return fixture.whenStable();
}
La solution acceptée ne fonctionnait pas vraiment pour moi dans Angular 2.4. La valeur que j'avais définie n'apparaissait pas dans l'interface utilisateur (de test), même après l'appel de detectChanges ().
Pour que cela fonctionne, j'ai configuré mon test de la manière suivante:
describe('TemplateComponent', function () {
let comp: TemplateComponent;
let fixture: ComponentFixture<TemplateComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ TemplateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TemplateComponent);
comp = fixture.componentInstance;
});
it('should allow us to set a bound input field', fakeAsync(() => {
setInputValue('#test2', 'Tommy');
expect(comp.personName).toEqual('Tommy');
}));
// must be called from within fakeAsync due to use of tick()
function setInputValue(selector: string, value: string) {
fixture.detectChanges();
tick();
let input = fixture.debugElement.query(By.css(selector)).nativeElement;
input.value = value;
input.dispatchEvent(new Event('input'));
tick();
}
});
Mon composant TemplateComponent
a une propriété nommée personName
dans cet exemple, qui correspond à la propriété de modèle que je lie dans mon modèle:
<input id="test2" type="text" [(ngModel)]="personName" />
J'ai également eu du mal à obtenir la réponse de jonrsharpe avec Angular 2.4. J'ai constaté que les appels à fixture.detectChanges()
et fixture.whenStable()
provoquaient la réinitialisation du composant de formulaire. Il semble qu’une fonction d’initialisation soit toujours en attente au début du test, ce que j’ai résolu en ajoutant des appels supplémentaires à ces méthodes avant chaque test. Voici un extrait de mon code:
beforeEach(() => {
TestBed.configureTestingModule({
// ...etc...
});
fixture = TestBed.createComponent(LoginComponent);
comp = fixture.componentInstance;
usernameBox = fixture.debugElement.query(By.css('input[name="username"]'));
passwordBox = fixture.debugElement.query(By.css('input[type="password"]'));
loginButton = fixture.debugElement.query(By.css('.btn-primary'));
formElement = fixture.debugElement.query(By.css('form'));
});
beforeEach(async(() => {
// The magic sauce!!
// Because this is in an async wrapper it will automatically wait
// for the call to whenStable() to complete
fixture.detectChanges();
fixture.whenStable();
}));
function sendInput(inputElement: any, text: string) {
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
it('should log in correctly', async(() => {
sendInput(usernameBox.nativeElement, 'User1')
.then(() => {
return sendInput(passwordBox.nativeElement, 'Password1')
}).then(() => {
formElement.triggerEventHandler('submit', null);
fixture.detectChanges();
let spinner = fixture.debugElement.query(By.css('img'));
expect(Helper.isHidden(spinner)).toBeFalsy('Spinner should be visible');
// ...etc...
});
}));