test(forms): refactor integration tests to improve speed (#13500)

This commit is contained in:
Marc Laval 2016-12-16 02:07:26 +01:00 committed by Chuck Jazdzewski
parent 0fe3cd9a4c
commit 55dfa1b69d
3 changed files with 146 additions and 191 deletions

View File

@ -987,4 +987,4 @@ function stringifyType(type: any): string {
} else {
return stringify(type);
}
}
}

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, EventEmitter, Input, Output, forwardRef} from '@angular/core';
import {TestBed, fakeAsync, tick} from '@angular/core/testing';
import {Component, Directive, EventEmitter, Input, Output, Type, forwardRef} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {AbstractControl, ControlValueAccessor, FormArray, FormControl, FormGroup, FormGroupDirective, FormsModule, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule, Validator, Validators} from '@angular/forms';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -16,38 +16,15 @@ import {dispatchEvent} from '@angular/platform-browser/testing/browser_util';
export function main() {
describe('reactive forms integration tests', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule],
declarations: [
FormControlComp,
FormGroupComp,
FormArrayComp,
FormArrayNestedGroup,
FormControlNameSelect,
FormControlNumberInput,
FormControlRangeInput,
FormControlRadioButtons,
WrappedValue,
WrappedValueForm,
MyInput,
MyInputForm,
FormGroupNgModel,
FormControlNgModel,
LoginIsEmptyValidator,
LoginIsEmptyWrapper,
ValidationBindingsForm,
UniqLoginValidator,
UniqLoginWrapper,
NestedFormGroupComp,
FormControlCheckboxRequiredValidator,
]
});
});
function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> {
TestBed.configureTestingModule(
{declarations: [component, ...directives], imports: [FormsModule, ReactiveFormsModule]});
return TestBed.createComponent(component);
}
describe('basic functionality', () => {
it('should work with single controls', () => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('old value');
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -64,7 +41,7 @@ export function main() {
});
it('should work with formGroups (model -> view)', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')});
fixture.detectChanges();
@ -73,7 +50,7 @@ export function main() {
});
it('should add novalidate by default to form', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')});
fixture.detectChanges();
@ -82,7 +59,7 @@ export function main() {
});
it('work with formGroups (view -> model)', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('oldValue')});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -99,7 +76,7 @@ export function main() {
describe('rebound form groups', () => {
it('should update DOM elements initially', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('oldValue')});
fixture.detectChanges();
@ -111,7 +88,7 @@ export function main() {
});
it('should update model when UI changes', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('oldValue')});
fixture.detectChanges();
@ -132,7 +109,7 @@ export function main() {
});
it('should work with radio buttons when reusing control', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const food = new FormControl('chicken');
fixture.componentInstance.form =
new FormGroup({'food': food, 'drink': new FormControl('')});
@ -150,7 +127,7 @@ export function main() {
});
it('should update nested form group model when UI changes', () => {
const fixture = TestBed.createComponent(NestedFormGroupComp);
const fixture = initTest(NestedFormGroupComp);
fixture.componentInstance.form = new FormGroup(
{'signin': new FormGroup({'login': new FormControl(), 'password': new FormControl()})});
fixture.detectChanges();
@ -178,7 +155,7 @@ export function main() {
});
it('should pick up dir validators from form controls', () => {
const fixture = TestBed.createComponent(LoginIsEmptyWrapper);
const fixture = initTest(LoginIsEmptyWrapper, LoginIsEmptyValidator);
const form = new FormGroup({
'login': new FormControl(''),
'min': new FormControl(''),
@ -202,7 +179,7 @@ export function main() {
});
it('should pick up dir validators from nested form groups', () => {
const fixture = TestBed.createComponent(NestedFormGroupComp);
const fixture = initTest(NestedFormGroupComp, LoginIsEmptyValidator);
const form = new FormGroup({
'signin':
new FormGroup({'login': new FormControl(''), 'password': new FormControl('')})
@ -222,7 +199,7 @@ export function main() {
});
it('should strip named controls that are not found', () => {
const fixture = TestBed.createComponent(NestedFormGroupComp);
const fixture = initTest(NestedFormGroupComp, LoginIsEmptyValidator);
const form = new FormGroup({
'signin':
new FormGroup({'login': new FormControl(''), 'password': new FormControl('')})
@ -248,7 +225,7 @@ export function main() {
});
it('should strip array controls that are not found', () => {
const fixture = TestBed.createComponent(FormArrayComp);
const fixture = initTest(FormArrayComp);
const cityArray = new FormArray([new FormControl('SF'), new FormControl('NY')]);
const form = new FormGroup({cities: cityArray});
fixture.componentInstance.form = form;
@ -277,7 +254,7 @@ export function main() {
it('should attach dir to control when leaf control changes', () => {
const form = new FormGroup({'login': new FormControl('oldValue')});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -300,7 +277,7 @@ export function main() {
});
it('should attach dirs to all child controls when group control changes', () => {
const fixture = TestBed.createComponent(NestedFormGroupComp);
const fixture = initTest(NestedFormGroupComp, LoginIsEmptyValidator);
const form = new FormGroup({
signin: new FormGroup(
{login: new FormControl('oldLogin'), password: new FormControl('oldPassword')})
@ -332,7 +309,7 @@ export function main() {
});
it('should attach dirs to all present child controls when array control changes', () => {
const fixture = TestBed.createComponent(FormArrayComp);
const fixture = initTest(FormArrayComp);
const cityArray = new FormArray([new FormControl('SF'), new FormControl('NY')]);
const form = new FormGroup({cities: cityArray});
fixture.componentInstance.form = form;
@ -363,7 +340,7 @@ export function main() {
describe('form arrays', () => {
it('should support form arrays', () => {
const fixture = TestBed.createComponent(FormArrayComp);
const fixture = initTest(FormArrayComp);
const cityArray = new FormArray([new FormControl('SF'), new FormControl('NY')]);
const form = new FormGroup({cities: cityArray});
fixture.componentInstance.form = form;
@ -386,7 +363,7 @@ export function main() {
});
it('should support pushing new controls to form arrays', () => {
const fixture = TestBed.createComponent(FormArrayComp);
const fixture = initTest(FormArrayComp);
const cityArray = new FormArray([new FormControl('SF'), new FormControl('NY')]);
const form = new FormGroup({cities: cityArray});
fixture.componentInstance.form = form;
@ -402,7 +379,7 @@ export function main() {
});
it('should support form groups nested in form arrays', () => {
const fixture = TestBed.createComponent(FormArrayNestedGroup);
const fixture = initTest(FormArrayNestedGroup);
const cityArray = new FormArray([
new FormGroup({town: new FormControl('SF'), state: new FormControl('CA')}),
new FormGroup({town: new FormControl('NY'), state: new FormControl('NY')})
@ -434,7 +411,7 @@ export function main() {
describe('programmatic changes', () => {
it('should update the value in the DOM when setValue() is called', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('oldValue');
const form = new FormGroup({'login': login});
fixture.componentInstance.form = form;
@ -450,7 +427,7 @@ export function main() {
describe('disabled controls', () => {
it('should add disabled attribute to an individual control when instantiated as disabled',
() => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl({value: 'some value', disabled: true});
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -464,7 +441,7 @@ export function main() {
});
it('should add disabled attribute to formControlName when instantiated as disabled', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const control = new FormControl({value: 'some value', disabled: true});
fixture.componentInstance.form = new FormGroup({login: control});
fixture.componentInstance.control = control;
@ -480,7 +457,7 @@ export function main() {
it('should add disabled attribute to an individual control when disable() is called',
() => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('some value');
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -498,7 +475,7 @@ export function main() {
it('should add disabled attribute to child controls when disable() is called on group',
() => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('login')});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -516,7 +493,7 @@ export function main() {
it('should not add disabled attribute to custom controls when disable() is called', () => {
const fixture = TestBed.createComponent(MyInputForm);
const fixture = initTest(MyInputForm, MyInput);
const control = new FormControl('some value');
fixture.componentInstance.form = new FormGroup({login: control});
fixture.detectChanges();
@ -535,7 +512,7 @@ export function main() {
describe('user input', () => {
it('should mark controls as touched after interacting with the DOM control', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('oldValue');
const form = new FormGroup({'login': login});
fixture.componentInstance.form = form;
@ -553,7 +530,7 @@ export function main() {
describe('submit and reset events', () => {
it('should emit ngSubmit event with the original submit event on submit', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')});
fixture.componentInstance.event = null;
fixture.detectChanges();
@ -566,7 +543,7 @@ export function main() {
});
it('should mark formGroup as submitted on submit event', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')});
fixture.detectChanges();
@ -581,7 +558,7 @@ export function main() {
});
it('should set value in UI when form resets to that value programmatically', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('some value');
const form = new FormGroup({'login': login});
fixture.componentInstance.form = form;
@ -595,7 +572,7 @@ export function main() {
});
it('should clear value in UI when form resets programmatically', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('some value');
const form = new FormGroup({'login': login});
fixture.componentInstance.form = form;
@ -613,7 +590,7 @@ export function main() {
describe('value changes and status changes', () => {
it('should mark controls as dirty before emitting a value change event', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('oldValue');
fixture.componentInstance.form = new FormGroup({'login': login});
fixture.detectChanges();
@ -628,7 +605,7 @@ export function main() {
it('should mark control as pristine before emitting a value change event when resetting ',
() => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const login = new FormControl('oldValue');
const form = new FormGroup({'login': login});
fixture.componentInstance.form = form;
@ -649,7 +626,7 @@ export function main() {
describe('setting status classes', () => {
it('should work with single fields', () => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('', Validators.required);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -670,7 +647,7 @@ export function main() {
});
it('should work with single fields and async validators', fakeAsync(() => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('', null, uniqLoginAsyncValidator('good'));
fixture.debugElement.componentInstance.control = control;
fixture.detectChanges();
@ -691,7 +668,7 @@ export function main() {
}));
it('should work with single fields that combines async and sync validators', fakeAsync(() => {
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control =
new FormControl('', Validators.required, uniqLoginAsyncValidator('good'));
fixture.debugElement.componentInstance.control = control;
@ -724,7 +701,7 @@ export function main() {
}));
it('should work with single fields in parent forms', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('', Validators.required)});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -745,7 +722,7 @@ export function main() {
});
it('should work with formGroup', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('', Validators.required)});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -774,7 +751,7 @@ export function main() {
it('should support <input> without type', () => {
TestBed.overrideComponent(
FormControlComp, {set: {template: `<input [formControl]="control">`}});
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('old');
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -791,7 +768,7 @@ export function main() {
});
it('should support <input type=text>', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('old')});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -808,7 +785,7 @@ export function main() {
});
it('should ignore the change event for <input type=text>', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('oldValue')});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -823,7 +800,7 @@ export function main() {
it('should support <textarea>', () => {
TestBed.overrideComponent(
FormControlComp, {set: {template: `<textarea [formControl]="control"></textarea>`}});
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl('old');
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -842,7 +819,7 @@ export function main() {
it('should support <type=checkbox>', () => {
TestBed.overrideComponent(
FormControlComp, {set: {template: `<input type="checkbox" [formControl]="control">`}});
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
const control = new FormControl(true);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -859,7 +836,7 @@ export function main() {
});
it('should support <select>', () => {
const fixture = TestBed.createComponent(FormControlNameSelect);
const fixture = initTest(FormControlNameSelect);
fixture.detectChanges();
// model -> view
@ -879,7 +856,7 @@ export function main() {
describe('should support <type=number>', () => {
it('with basic use case', () => {
const fixture = TestBed.createComponent(FormControlNumberInput);
const fixture = initTest(FormControlNumberInput);
const control = new FormControl(10);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -896,7 +873,7 @@ export function main() {
});
it('when value is cleared in the UI', () => {
const fixture = TestBed.createComponent(FormControlNumberInput);
const fixture = initTest(FormControlNumberInput);
const control = new FormControl(10, Validators.required);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -916,7 +893,7 @@ export function main() {
});
it('when value is cleared programmatically', () => {
const fixture = TestBed.createComponent(FormControlNumberInput);
const fixture = initTest(FormControlNumberInput);
const control = new FormControl(10);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -931,7 +908,7 @@ export function main() {
describe('should support <type=radio>', () => {
it('should support basic functionality', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form =
new FormGroup({'food': new FormControl('fish'), 'drink': new FormControl('sprite')});
fixture.componentInstance.form = form;
@ -958,7 +935,7 @@ export function main() {
});
it('should support an initial undefined value', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form = new FormGroup({'food': new FormControl(), 'drink': new FormControl()});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -969,7 +946,7 @@ export function main() {
});
it('should reset properly', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form =
new FormGroup({'food': new FormControl('fish'), 'drink': new FormControl('sprite')});
fixture.componentInstance.form = form;
@ -984,7 +961,7 @@ export function main() {
});
it('should set value to null and undefined properly', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form = new FormGroup(
{'food': new FormControl('chicken'), 'drink': new FormControl('sprite')});
fixture.componentInstance.form = form;
@ -1005,7 +982,7 @@ export function main() {
});
it('should use formControlName to group radio buttons when name is absent', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const foodCtrl = new FormControl('fish');
const drinkCtrl = new FormControl('sprite');
fixture.componentInstance.form = new FormGroup({'food': foodCtrl, 'drink': drinkCtrl});
@ -1037,7 +1014,7 @@ export function main() {
});
it('should support removing controls from <type=radio>', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const showRadio = new FormControl('yes');
const form =
new FormGroup({'food': new FormControl('fish'), 'drink': new FormControl('sprite')});
@ -1071,7 +1048,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form = new FormGroup({
food: new FormControl('fish'),
nested: new FormGroup({food: new FormControl('fish')})
@ -1100,7 +1077,7 @@ export function main() {
});
it('should disable all radio buttons when disable() is called', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form =
new FormGroup({food: new FormControl('fish'), drink: new FormControl('cola')});
fixture.componentInstance.form = form;
@ -1132,7 +1109,7 @@ export function main() {
});
it('should disable all radio buttons when initially disabled', () => {
const fixture = TestBed.createComponent(FormControlRadioButtons);
const fixture = initTest(FormControlRadioButtons);
const form = new FormGroup({
food: new FormControl({value: 'fish', disabled: true}),
drink: new FormControl('cola')
@ -1151,7 +1128,7 @@ export function main() {
describe('should support <type=range>', () => {
it('with basic use case', () => {
const fixture = TestBed.createComponent(FormControlRangeInput);
const fixture = initTest(FormControlRangeInput);
const control = new FormControl(10);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -1168,7 +1145,7 @@ export function main() {
});
it('when value is cleared in the UI', () => {
const fixture = TestBed.createComponent(FormControlNumberInput);
const fixture = initTest(FormControlNumberInput);
const control = new FormControl(10, Validators.required);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -1188,7 +1165,7 @@ export function main() {
});
it('when value is cleared programmatically', () => {
const fixture = TestBed.createComponent(FormControlNumberInput);
const fixture = initTest(FormControlNumberInput);
const control = new FormControl(10);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -1202,7 +1179,7 @@ export function main() {
describe('custom value accessors', () => {
it('should support basic functionality', () => {
const fixture = TestBed.createComponent(WrappedValueForm);
const fixture = initTest(WrappedValueForm, WrappedValue);
const form = new FormGroup({'login': new FormControl('aa')});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -1225,7 +1202,7 @@ export function main() {
it('should support non builtin input elements that fire a change event without a \'target\' property',
() => {
const fixture = TestBed.createComponent(MyInputForm);
const fixture = initTest(MyInputForm, MyInput);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('aa')});
fixture.detectChanges();
@ -1240,7 +1217,7 @@ export function main() {
});
it('should support custom accessors without setDisabledState - formControlName', () => {
const fixture = TestBed.createComponent(WrappedValueForm);
const fixture = initTest(WrappedValueForm, WrappedValue);
fixture.componentInstance.form = new FormGroup({
'login': new FormControl({value: 'aa', disabled: true}),
});
@ -1254,7 +1231,7 @@ export function main() {
TestBed.overrideComponent(
FormControlComp,
{set: {template: `<input type="text" [formControl]="control" wrapped-value>`}});
const fixture = TestBed.createComponent(FormControlComp);
const fixture = initTest(FormControlComp);
fixture.componentInstance.control = new FormControl({value: 'aa', disabled: true});
fixture.detectChanges();
expect(fixture.componentInstance.control.status).toEqual('DISABLED');
@ -1267,7 +1244,7 @@ export function main() {
describe('ngModel interactions', () => {
it('should support ngModel for complex forms', fakeAsync(() => {
const fixture = TestBed.createComponent(FormGroupNgModel);
const fixture = initTest(FormGroupNgModel);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('')});
fixture.componentInstance.login = 'oldValue';
fixture.detectChanges();
@ -1284,7 +1261,7 @@ export function main() {
}));
it('should support ngModel for single fields', fakeAsync(() => {
const fixture = TestBed.createComponent(FormControlNgModel);
const fixture = initTest(FormControlNgModel);
fixture.componentInstance.control = new FormControl('');
fixture.componentInstance.login = 'oldValue';
fixture.detectChanges();
@ -1301,7 +1278,7 @@ export function main() {
}));
it('should not update the view when the value initially came from the view', fakeAsync(() => {
const fixture = TestBed.createComponent(FormControlNgModel);
const fixture = initTest(FormControlNgModel);
fixture.componentInstance.control = new FormControl('');
fixture.detectChanges();
tick();
@ -1322,7 +1299,7 @@ export function main() {
describe('validations', () => {
it('required validator should validate checkbox', () => {
const fixture = TestBed.createComponent(FormControlCheckboxRequiredValidator);
const fixture = initTest(FormControlCheckboxRequiredValidator);
const control = new FormControl(false, Validators.requiredTrue);
fixture.componentInstance.control = control;
fixture.detectChanges();
@ -1340,7 +1317,7 @@ export function main() {
});
it('should use sync validators defined in html', () => {
const fixture = TestBed.createComponent(LoginIsEmptyWrapper);
const fixture = initTest(LoginIsEmptyWrapper, LoginIsEmptyValidator);
const form = new FormGroup({
'login': new FormControl(''),
'min': new FormControl(''),
@ -1385,7 +1362,7 @@ export function main() {
});
it('should use sync validators using bindings', () => {
const fixture = TestBed.createComponent(ValidationBindingsForm);
const fixture = initTest(ValidationBindingsForm);
const form = new FormGroup({
'login': new FormControl(''),
'min': new FormControl(''),
@ -1433,7 +1410,7 @@ export function main() {
});
it('changes on bound properties should change the validation state of the form', () => {
const fixture = TestBed.createComponent(ValidationBindingsForm);
const fixture = initTest(ValidationBindingsForm);
const form = new FormGroup({
'login': new FormControl(''),
'min': new FormControl(''),
@ -1508,7 +1485,7 @@ export function main() {
});
it('should support rebound controls with rebound validators', () => {
const fixture = TestBed.createComponent(ValidationBindingsForm);
const fixture = initTest(ValidationBindingsForm);
const form = new FormGroup({
'login': new FormControl(''),
'min': new FormControl(''),
@ -1545,7 +1522,7 @@ export function main() {
});
it('should use async validators defined in the html', fakeAsync(() => {
const fixture = TestBed.createComponent(UniqLoginWrapper);
const fixture = initTest(UniqLoginWrapper, UniqLoginValidator);
const form = new FormGroup({'login': new FormControl('')});
tick();
fixture.componentInstance.form = form;
@ -1565,7 +1542,7 @@ export function main() {
}));
it('should use sync validators defined in the model', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const form = new FormGroup({'login': new FormControl('aa', Validators.required)});
fixture.componentInstance.form = form;
fixture.detectChanges();
@ -1579,7 +1556,7 @@ export function main() {
});
it('should use async validators defined in the model', fakeAsync(() => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const control =
new FormControl('', Validators.required, uniqLoginAsyncValidator('expected'));
const form = new FormGroup({'login': control});
@ -1610,7 +1587,7 @@ export function main() {
describe('errors', () => {
it('should throw if a form isn\'t passed into formGroup', () => {
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(new RegExp(`formGroup expects a FormGroup instance`));
@ -1624,7 +1601,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1641,7 +1618,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1660,7 +1637,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1677,7 +1654,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1696,7 +1673,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1712,7 +1689,7 @@ export function main() {
</div>`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
expect(() => fixture.detectChanges())
.toThrowError(
@ -1729,7 +1706,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.myGroup = new FormGroup({});
expect(() => fixture.detectChanges())
@ -1747,7 +1724,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.myGroup = new FormGroup({});
expect(() => fixture.detectChanges()).not.toThrowError();
@ -1765,7 +1742,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
const myGroup = new FormGroup({person: new FormGroup({})});
fixture.componentInstance.myGroup = new FormGroup({person: new FormGroup({})});
@ -1786,7 +1763,7 @@ export function main() {
`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.myGroup = new FormGroup({});
expect(() => fixture.detectChanges())
@ -1803,7 +1780,7 @@ export function main() {
</form>`
}
});
const fixture = TestBed.createComponent(FormGroupComp);
const fixture = initTest(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'food': new FormControl('fish')});
expect(() => fixture.detectChanges())

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, Input, forwardRef} from '@angular/core';
import {Component, Directive, Input, Type, forwardRef} from '@angular/core';
import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing';
import {AbstractControl, ControlValueAccessor, FormsModule, NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, NgForm, Validator} from '@angular/forms';
import {By} from '@angular/platform-browser/src/dom/debug/by';
@ -16,37 +16,15 @@ import {dispatchEvent} from '@angular/platform-browser/testing/browser_util';
export function main() {
describe('template-driven forms integration tests', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
StandaloneNgModel,
NgModelForm,
NgModelGroupForm,
NgModelValidBinding,
NgModelNgIfForm,
NgModelRadioForm,
NgModelRangeForm,
NgModelSelectForm,
NgNoFormComp,
InvalidNgModelNoName,
NgModelOptionsStandalone,
NgModelCustomComp,
NgModelCustomWrapper,
NgModelValidationBindings,
NgModelMultipleValidators,
NgAsyncValidator,
NgModelAsyncValidation,
NgModelSelectMultipleForm,
NgModelSelectWithNullForm,
NgModelCheckboxRequiredValidator,
],
imports: [FormsModule]
});
});
function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> {
TestBed.configureTestingModule(
{declarations: [component, ...directives], imports: [FormsModule]});
return TestBed.createComponent(component);
}
describe('basic functionality', () => {
it('should support ngModel for standalone fields', fakeAsync(() => {
const fixture = TestBed.createComponent(StandaloneNgModel);
const fixture = initTest(StandaloneNgModel);
fixture.componentInstance.name = 'oldValue';
fixture.detectChanges();
@ -65,7 +43,7 @@ export function main() {
}));
it('should support ngModel registration with a parent form', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.componentInstance.name = 'Nancy';
fixture.detectChanges();
@ -77,7 +55,7 @@ export function main() {
}));
it('should add novalidate by default to form element', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.detectChanges();
tick();
@ -87,7 +65,7 @@ export function main() {
}));
it('should support ngModelGroup', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelGroupForm);
const fixture = initTest(NgModelGroupForm);
fixture.componentInstance.first = 'Nancy';
fixture.componentInstance.last = 'Drew';
fixture.componentInstance.email = 'some email';
@ -110,7 +88,7 @@ export function main() {
}));
it('should add controls and control groups to form control model', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelGroupForm);
const fixture = initTest(NgModelGroupForm);
fixture.componentInstance.first = 'Nancy';
fixture.componentInstance.last = 'Drew';
fixture.componentInstance.email = 'some email';
@ -125,7 +103,7 @@ export function main() {
}));
it('should remove controls and control groups from form control model', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelNgIfForm);
const fixture = initTest(NgModelNgIfForm);
fixture.componentInstance.emailShowing = true;
fixture.componentInstance.first = 'Nancy';
fixture.componentInstance.email = 'some email';
@ -158,7 +136,7 @@ export function main() {
}));
it('should set status classes with ngModel', async(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.componentInstance.name = 'aa';
fixture.detectChanges();
fixture.whenStable().then(() => {
@ -181,7 +159,7 @@ export function main() {
it('should set status classes with ngModel and async validators', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelAsyncValidation);
const fixture = initTest(NgModelAsyncValidation, NgAsyncValidator);
fixture.whenStable().then(() => {
fixture.detectChanges();
@ -203,7 +181,7 @@ export function main() {
}));
it('should set status classes with ngModelGroup and ngForm', async(() => {
const fixture = TestBed.createComponent(NgModelGroupForm);
const fixture = initTest(NgModelGroupForm);
fixture.componentInstance.first = '';
fixture.detectChanges();
@ -238,13 +216,13 @@ export function main() {
}));
it('should not create a template-driven form when ngNoForm is used', () => {
const fixture = TestBed.createComponent(NgNoFormComp);
const fixture = initTest(NgNoFormComp);
fixture.detectChanges();
expect(fixture.debugElement.children[0].providerTokens.length).toEqual(0);
});
it('should not add novalidate when ngNoForm is used', () => {
const fixture = TestBed.createComponent(NgNoFormComp);
const fixture = initTest(NgNoFormComp);
fixture.detectChanges();
const form = fixture.debugElement.query(By.css('form'));
expect(form.nativeElement.hasAttribute('novalidate')).toBeFalsy();
@ -253,19 +231,19 @@ export function main() {
describe('name and ngModelOptions', () => {
it('should throw if ngModel has a parent form but no name attr or standalone label', () => {
const fixture = TestBed.createComponent(InvalidNgModelNoName);
const fixture = initTest(InvalidNgModelNoName);
expect(() => fixture.detectChanges())
.toThrowError(new RegExp(`name attribute must be set`));
});
it('should not throw if ngModel has a parent form, no name attr, and a standalone label',
() => {
const fixture = TestBed.createComponent(NgModelOptionsStandalone);
const fixture = initTest(NgModelOptionsStandalone);
expect(() => fixture.detectChanges()).not.toThrow();
});
it('should not register standalone ngModels with parent form', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelOptionsStandalone);
const fixture = initTest(NgModelOptionsStandalone);
fixture.componentInstance.one = 'some data';
fixture.componentInstance.two = 'should not show';
fixture.detectChanges();
@ -280,7 +258,7 @@ export function main() {
}));
it('should override name attribute with ngModelOptions name if provided', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.componentInstance.options = {name: 'override'};
fixture.componentInstance.name = 'some data';
fixture.detectChanges();
@ -293,7 +271,7 @@ export function main() {
describe('submit and reset events', () => {
it('should emit ngSubmit event with the original submit event on submit', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.componentInstance.event = null;
const form = fixture.debugElement.query(By.css('form'));
@ -304,7 +282,7 @@ export function main() {
}));
it('should mark NgForm as submitted on submit event', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
tick();
const form = fixture.debugElement.children[0].injector.get(NgForm);
@ -318,7 +296,7 @@ export function main() {
}));
it('should reset the form to empty when reset event is fired', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.componentInstance.name = 'should be cleared';
fixture.detectChanges();
tick();
@ -341,7 +319,7 @@ export function main() {
}));
it('should reset the form submit state when reset button is clicked', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
const form = fixture.debugElement.children[0].injector.get(NgForm);
const formEl = fixture.debugElement.query(By.css('form'));
@ -359,7 +337,7 @@ export function main() {
describe('valueChange and statusChange events', () => {
it('should emit valueChanges and statusChanges on init', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
const form = fixture.debugElement.children[0].injector.get(NgForm);
fixture.componentInstance.name = 'aa';
fixture.detectChanges();
@ -380,7 +358,7 @@ export function main() {
}));
it('should mark controls dirty before emitting the value change event', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
const form = fixture.debugElement.children[0].injector.get(NgForm).form;
fixture.detectChanges();
@ -397,7 +375,7 @@ export function main() {
it('should mark controls pristine before emitting the value change event when resetting ',
fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.detectChanges();
tick();
@ -419,7 +397,7 @@ export function main() {
describe('disabled controls', () => {
it('should not consider disabled controls in value or validation', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelGroupForm);
const fixture = initTest(NgModelGroupForm);
fixture.componentInstance.isDisabled = false;
fixture.componentInstance.first = '';
fixture.componentInstance.last = 'Drew';
@ -443,7 +421,7 @@ export function main() {
it('should add disabled attribute in the UI if disable() is called programmatically',
fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelGroupForm);
const fixture = initTest(NgModelGroupForm);
fixture.componentInstance.isDisabled = false;
fixture.componentInstance.first = 'Nancy';
fixture.detectChanges();
@ -459,7 +437,7 @@ export function main() {
}));
it('should disable a custom control if disabled attr is added', async(() => {
const fixture = TestBed.createComponent(NgModelCustomWrapper);
const fixture = initTest(NgModelCustomWrapper, NgModelCustomComp);
fixture.componentInstance.name = 'Nancy';
fixture.componentInstance.isDisabled = true;
fixture.detectChanges();
@ -485,7 +463,7 @@ export function main() {
`,
}
});
const fixture = TestBed.createComponent(NgModelForm);
const fixture = initTest(NgModelForm);
fixture.detectChanges();
tick();
const form = fixture.debugElement.children[0].injector.get(NgForm);
@ -501,7 +479,7 @@ export function main() {
}));
it('should disable radio controls properly with programmatic call', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.componentInstance.food = 'fish';
fixture.detectChanges();
tick();
@ -537,7 +515,7 @@ export function main() {
describe('range control', () => {
it('should support <type=range>', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRangeForm);
const fixture = initTest(NgModelRangeForm);
// model -> view
fixture.componentInstance.val = 4;
fixture.detectChanges();
@ -557,7 +535,7 @@ export function main() {
describe('radio controls', () => {
it('should support <type=radio>', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.componentInstance.food = 'fish';
fixture.detectChanges();
tick();
@ -576,7 +554,7 @@ export function main() {
}));
it('should support multiple named <type=radio> groups', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.componentInstance.food = 'fish';
fixture.componentInstance.drink = 'sprite';
fixture.detectChanges();
@ -599,7 +577,7 @@ export function main() {
}));
it('should support initial undefined value', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.detectChanges();
tick();
@ -611,7 +589,7 @@ export function main() {
}));
it('should support resetting properly', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.componentInstance.food = 'chicken';
fixture.detectChanges();
tick();
@ -627,7 +605,7 @@ export function main() {
}));
it('should support setting value to null and undefined', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelRadioForm);
const fixture = initTest(NgModelRadioForm);
fixture.componentInstance.food = 'chicken';
fixture.detectChanges();
tick();
@ -655,7 +633,7 @@ export function main() {
describe('select controls', () => {
it('with option values that are objects', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const fixture = initTest(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
@ -679,7 +657,7 @@ export function main() {
}));
it('when new options are added', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const fixture = initTest(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}];
comp.selectedCity = comp.cities[1];
@ -698,7 +676,7 @@ export function main() {
}));
it('when options are removed', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const fixture = initTest(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}];
comp.selectedCity = comp.cities[1];
@ -716,7 +694,7 @@ export function main() {
}));
it('when option values have same content, but different identities', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const fixture = initTest(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'NYC'}];
comp.selectedCity = comp.cities[0];
@ -733,7 +711,7 @@ export function main() {
}));
it('should work with null option', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectWithNullForm);
const fixture = initTest(NgModelSelectWithNullForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}];
comp.selectedCity = null;
@ -760,7 +738,7 @@ export function main() {
let comp: NgModelSelectMultipleForm;
beforeEach(() => {
fixture = TestBed.createComponent(NgModelSelectMultipleForm);
fixture = initTest(NgModelSelectMultipleForm);
comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
});
@ -821,7 +799,7 @@ export function main() {
describe('custom value accessors', () => {
it('should support standard writing to view and model', async(() => {
const fixture = TestBed.createComponent(NgModelCustomWrapper);
const fixture = initTest(NgModelCustomWrapper, NgModelCustomComp);
fixture.componentInstance.name = 'Nancy';
fixture.detectChanges();
fixture.whenStable().then(() => {
@ -846,7 +824,7 @@ export function main() {
describe('validation directives', () => {
it('required validator should validate checkbox', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelCheckboxRequiredValidator);
const fixture = initTest(NgModelCheckboxRequiredValidator);
fixture.detectChanges();
tick();
@ -882,7 +860,7 @@ export function main() {
}));
it('should support dir validators using bindings', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelValidationBindings);
const fixture = initTest(NgModelValidationBindings);
fixture.componentInstance.required = true;
fixture.componentInstance.minLen = 3;
fixture.componentInstance.maxLen = 3;
@ -926,7 +904,7 @@ export function main() {
}));
it('should support optional fields with string pattern validator', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelMultipleValidators);
const fixture = initTest(NgModelMultipleValidators);
fixture.componentInstance.required = false;
fixture.componentInstance.pattern = '[a-z]+';
fixture.detectChanges();
@ -948,7 +926,7 @@ export function main() {
}));
it('should support optional fields with RegExp pattern validator', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelMultipleValidators);
const fixture = initTest(NgModelMultipleValidators);
fixture.componentInstance.required = false;
fixture.componentInstance.pattern = /^[a-z]+$/;
fixture.detectChanges();
@ -970,7 +948,7 @@ export function main() {
}));
it('should support optional fields with minlength validator', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelMultipleValidators);
const fixture = initTest(NgModelMultipleValidators);
fixture.componentInstance.required = false;
fixture.componentInstance.minLen = 2;
fixture.detectChanges();
@ -993,7 +971,7 @@ export function main() {
it('changes on bound properties should change the validation state of the form',
fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelValidationBindings);
const fixture = initTest(NgModelValidationBindings);
fixture.detectChanges();
tick();
@ -1067,7 +1045,7 @@ export function main() {
describe('ngModel corner cases', () => {
it('should update the view when the model is set back to what used to be in the view',
fakeAsync(() => {
const fixture = TestBed.createComponent(StandaloneNgModel);
const fixture = initTest(StandaloneNgModel);
fixture.componentInstance.name = '';
fixture.detectChanges();
tick();
@ -1095,7 +1073,7 @@ export function main() {
}));
it('should not crash when validity is checked from a binding', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelValidBinding);
const fixture = initTest(NgModelValidBinding);
tick();
expect(() => fixture.detectChanges()).not.toThrowError();
}));