Обновление ввода html-поля из теста Angular 2
Я хотел бы изменить значение поля ввода из Angular 2 unit test.
<input type="text" class="form-control" [(ngModel)]="abc.value" />
Я не могу просто изменить ngModel
, потому что объект abc
является закрытым:
private abc: Abc = new Abc();
В тесте Angular 2 я могу симулировать ввод пользователя в поле ввода, чтобы ngModel
был обновлен тем, что пользователь набрал из unit test?
Я могу захватить DebugElement
и nativeElement
поля ввода без проблем. (Просто установка свойства value
в nativeElement
поля ввода не работает, поскольку она не обновляет ngModel
тем, что я установил для значения).
Может быть, может быть вызван inputDebugEl.triggerEventHandler
, но я не уверен, какие аргументы ему дать, чтобы он имитировал пользователя, набрав определенную строку ввода.
Ответы
Ответ 1
Вы правы, что вы не можете просто установить ввод, вам также нужно отправить событие 'input'
. Вот функция, которую я написал ранее этим вечером для ввода текста:
function sendInput(text: string) {
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
Здесь fixture
есть ComponentFixture
, а inputElement
является релевантным HTTPInputElement
из прибора nativeElement
. Это возвращает обещание, поэтому вам, вероятно, придется его решить sendInput('whatever').then(...)
.
В контексте: https://github.com/textbook/known-for-web/blob/52c8aec4c2699c2f146a33c07786e1e32891c8b6/src/app/actor/actor.component.spec.ts#L134
Обновление
У нас были некоторые проблемы с тем, чтобы это работало в Angular 2.1, ему не понравилось создание new Event(...)
, поэтому вместо этого мы сделали:
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();
}
Ответ 2
Принятое решение не работает для меня в Angular 2.4. Значение, которое я установил, не появлялось в пользовательском интерфейсе (test) даже после того, как вызывается функция detectChanges().
Как я работал, это настроить мой тест следующим образом:
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();
}
});
В моем примере компонент TemplateComponent
имеет свойство с именем personName
, которое было свойством модели, с которым я привязываюсь в своем шаблоне:
<input id="test2" type="text" [(ngModel)]="personName" />
Ответ 3
У меня также возникли проблемы с получением ответа jonrsharpe на работу с Angular 2.4. Я обнаружил, что вызовы fixture.detectChanges()
и fixture.whenStable()
привели к тому, что компонент формы был reset. Кажется, что некоторые функции инициализации все еще находятся на рассмотрении, когда начинается тестирование. Я решил это, добавив дополнительные вызовы к этим методам перед каждым тестом. Вот фрагмент моего кода:
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...
});
}));