如何从单元测试中获取/设置FormGroup中的Ionic 2离子输入FormControl值? [英] How to get/set an Ionic 2 ion-input FormControl value within a FormGroup from a Unit Test?
问题描述
我想编写一个通过在输入字段中设置值然后检查关联的实例成员来与Angular 2/Ionic 2离子输入字段进行交互的单元测试.
I would like to write a unit test that interacts with an Angular 2/Ionic 2 ion-input field by setting values in the input field and then examining the associated instance members.
具体来说,我想:
- 在组件实例中设置默认值.
- 验证该值是否已在相关的DOM元素中设置.
- 将值输入到相关的DOM元素(输入字段)
- 验证它是否反映在组件实例中.
我可以在普通的HTML输入字段中使用它,但是我确实了解离子输入字段的使用.
I have this working for a normal HTML input field however there is something about the use of an ion-input field that I do understand.
我的单元测试和测试组件:
My unit test and test component:
/**
* Form Tests
*/
import {Component} from '@angular/core';
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import {
AbstractControl,
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule
} from '@angular/forms';
import {dispatchEvent} from '@angular/platform-browser/testing/browser_util';
// Ionic imports
import {
App,
MenuController,
NavController,
Platform,
Config,
Keyboard,
Form,
IonicModule
} from 'ionic-angular';
describe( 'Ionic Form Tests',
() => {
// -----------------------------------
/**
* instance and element in a FormControl should match, right?
*/
it( 'nativeElement and instance should match with input and ion-input in a FormGroup',
fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [
IonicFormTestComponent
],
providers: [
App,
Platform,
Form,
{ provide: Config, useClass: ConfigMock },
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
],
});
let fixture: any = TestBed.createComponent( IonicFormTestComponent );
fixture.whenStable().then(() => {
fixture.detectChanges();
tick();
let instance = fixture.componentInstance;
// first check that the initial plain input value and element match
let plainInputEl = fixture.debugElement.query( By.css( '[formControlName="plainInputControl"]' ) ).nativeElement;
expect( instance.plainInputControl.value ).toEqual( 'plain input control value' );
expect( plainInputEl.value ).toEqual( 'plain input control value' );
// now check to see if the model updates when we update the DOM element
plainInputEl.value = 'updated Plain Input Control Value';
dispatchEvent( plainInputEl, 'input' );
fixture.detectChanges();
tick();
// this works
expect( instance.plainInputControl.value ).toEqual( 'updated Plain Input Control Value' );
// -------------------------------------------------------------
// repeat with ion-input
let ionicInputEl = fixture.debugElement.query( By.css( '[formControlName="ionicInputControl"]' ) ).nativeElement;
expect( instance.ionicInputControl.value ).toEqual( 'ionic input control value' );
// this fails with ionicInputEl.value 'undefined'
// (how to correctly get the value of the ion-input element?)
expect( ionicInputEl.value ).toEqual( 'ionic input control value' );
ionicInputEl.value = 'updated Ionic Input Control Value';
dispatchEvent( ionicInputEl, 'input' );
fixture.detectChanges()
tick();
console.log( "Ionic input element value is:", ionicInputEl.value );
// this fails, instance.ionicInputControl.value not changed.
expect( instance.ionicInputControl.value ).toEqual( 'updated Ionic Input Control Value' );
});
}) // end of fakeAsync()
); // end of it()
}
); // end of describe()
// -------------------------------------------------
/**
* ionic test component with form Group
*/
@Component({
selector: 'ionic-form-test-component',
template: `
<form [formGroup]="testFormGroup">
<input type="text" value="" formControlName="plainInputControl" />
<ion-input type="text" value="" formControlName="ionicInputControl"></ion-input>
</form>
`
})
export class IonicFormTestComponent {
testFormGroup: FormGroup;
plainInputControl: AbstractControl;
ionicInputControl: AbstractControl;
constructor() {
this.testFormGroup = new FormGroup({
'plainInputControl': new FormControl( '' ),
'ionicInputControl': new FormControl( '' )
});
this.plainInputControl = this.testFormGroup.controls[ 'plainInputControl' ];
this.plainInputControl.setValue( 'plain input control value' );
this.ionicInputControl = this.testFormGroup.controls[ 'ionicInputControl' ];
this.ionicInputControl.setValue( 'ionic input control value' );
}
}
// --------------------------------------------------
export class ConfigMock {
public get(): any {
return '';
}
public getBoolean(): boolean {
return true;
}
public getNumber(): number {
return 1;
}
}
// END
如何在单元测试中以编程方式获取/设置离子输入场的值,从而使上述方法起作用?
How do I get/set the value of an ion-input field programmatically within a unit test so that the above works?
很明显,我缺少了一些东西. Ionic 2文档在此主题上没有任何提示.
Clearly I'm missing something. The Ionic 2 documentation is woefully silent on this subject. The Angular 2 documentation on FormControl seems to imply that it automatically supports two way binding (the successful unit test above seems to support that assertion.)
推荐答案
经过反复尝试,事实证明,为了使Ionic 2识别离子输入场的值已更改,第一个子项的值必须设置离子输入元素(即输入字段),然后必须在该元素上触发输入"事件.
After much trial and error, it turns out that in order to get Ionic 2 to recognize the ion-input field value has changed, the value of the first child element of ion-input, which is an input field, has to be set and then an 'input' event has to be triggered on that element.
// change the value of the element
ionicInputEl.children[0].value = "ELEMENT UPDATE";
dispatchEvent( ionicInputEl.children[0], 'input' );
fixture.detectChanges();
tick();
// check to see that the instance value updated to match.
expect( instance.ionicInputControl.value ).toEqual( 'ELEMENT UPDATE');
Reaching into the internal structure of the ion-input field is ugly so I've filed an issue about it: https://github.com/driftyco/ionic/issues/9622
这篇关于如何从单元测试中获取/设置FormGroup中的Ionic 2离子输入FormControl值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!