[min]
テンプレートフォームとディレクティブを使用したかった[max]
ので、それらを作成しましたが、機能します。しかし、テストは私を混乱させます: 検証は非同期的に実行されませんが、値やものを変更した後、これを実行する必要があります:
component.makeSomeChangeThatInvalidatesMyInput();
// control.invalid = false, expected
fixture.detectChanges();
// control.invalid is still false, not expected
// but if I go do this
fixture.whenStable().then(() => {
// control.invalid is STILL false, not expected
fixture.detectChanges();
// control.invalid now true
// expect(... .errors ... ) now passes
})
whenStable()
別のdetectChanges()
サイクルは言うまでもなく、なぜそれが必要なのかわかりません。ここで何が欠けていますか?この検証を実行するには、なぜ変更検出の 2 サイクルが必要なのですか?
テストを実行するかどうかは関係ありasync
ません。
これが私のテストです:
@Component({
selector: 'test-cmp',
template: `<form>
<input [max]="maxValue" [(ngModel)]="numValue" name="numValue" #val="ngModel">
<span class="error" *ngIf="val.invalid">Errors there.</span>
</form>`
})
class TestMaxDirectiveComponent {
maxValue: number;
numValue: number;
}
fdescribe('ValidateMaxDirective', () => {
let fixture: ComponentFixture<TestMaxDirectiveComponent>;
let component: TestMaxDirectiveComponent;
beforeEach(async(() => TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [TestMaxDirectiveComponent, ValidateMaxDirective],
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(TestMaxDirectiveComponent);
component = fixture.componentInstance;
return fixture.detectChanges();
})
));
fit('should have errors even when value is greater than maxValue', async(() => {
component.numValue = 42;
component.maxValue = 2;
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('.error')).toBeTruthy();
});
}));
});
そして、ここにディレクティブ自体があります(少し簡略化されています):
const VALIDATE_MAX_PROVIDER = {
provide: NG_VALIDATORS, useExisting: forwardRef(() => ValidateMaxDirective), multi: true,
};
@Directive({
selector: '[max][ngModel]',
providers: [VALIDATE_MAX_PROVIDER],
})
export class ValidateMaxDirective implements Validator {
private _max: number | string;
@Input() get max(): number | string {
return this._max;
}
set max(value: number | string) {
this._max = value;
}
validate(control: AbstractControl): ValidationErrors | null {
if (isEmptyInputValue(control.value) || isEmptyInputValue(this._max)) {
return null; // don't validate empty values to allow optional controls
}
const value = parseFloat(control.value);
return !isNaN(value) && value > this._max ? {'max': {'max': this._max, 'actual': control.value}} : null;
}
}
バージョン 1.6.8 と最新の angular 5.2ng new app
を使用して、これを真新しいものでテストしました。@angular/cli