2016-08-13 17:26:08 -07:00
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { fakeAsync , tick } from '@angular/core/testing' ;
2016-09-27 17:12:25 -07:00
import { AsyncTestCompleter , beforeEach , describe , inject , it } from '@angular/core/testing/testing_internal' ;
2016-08-13 17:26:08 -07:00
import { FormControl , FormGroup , Validators } from '@angular/forms' ;
import { EventEmitter } from '../src/facade/async' ;
import { isPresent } from '../src/facade/lang' ;
2016-08-24 16:58:43 -07:00
import { FormArray } from '../src/model' ;
2016-08-13 17:26:08 -07:00
export function main() {
2016-09-09 12:00:38 -07:00
function asyncValidator ( expected : string , timeouts = {}) {
return ( c : FormControl ) => {
2016-11-12 14:08:58 +01:00
let resolve : ( result : any ) => void ;
const promise = new Promise ( res => { resolve = res ; });
const t = isPresent (( timeouts as any )[ c . value ]) ? ( timeouts as any )[ c . value ] : 0 ;
const res = c . value != expected ? { 'async' : true } : null ;
2016-08-13 17:26:08 -07:00
if ( t == 0 ) {
resolve ( res );
} else {
setTimeout (() => { resolve ( res ); }, t );
}
return promise ;
};
}
function asyncValidatorReturningObservable ( c : FormControl ) {
2016-11-12 14:08:58 +01:00
const e = new EventEmitter ();
2016-08-13 17:26:08 -07:00
Promise . resolve ( null ). then (() => { e . emit ({ 'async' : true }); });
return e ;
}
function otherAsyncValidator() { return Promise . resolve ({ 'other' : true }); }
2017-01-22 21:37:22 +13:00
function syncValidator ( _ : any /** TODO #9100 */ ) : any /** TODO #9100 */ { return null ; }
2016-08-13 17:26:08 -07:00
describe ( 'FormControl' , () => {
it ( 'should default the value to null' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ();
2016-08-13 17:26:08 -07:00
expect ( c . value ). toBe ( null );
});
2016-08-24 16:58:43 -07:00
describe ( 'boxed values' , () => {
it ( 'should support valid boxed values on creation' , () => {
const c = new FormControl ({ value : 'some val' , disabled : true }, null , null );
expect ( c . disabled ). toBe ( true );
expect ( c . value ). toBe ( 'some val' );
expect ( c . status ). toBe ( 'DISABLED' );
});
2016-09-01 16:51:42 -07:00
it ( 'should honor boxed value with disabled control when validating' , () => {
const c = new FormControl ({ value : '' , disabled : true }, Validators . required );
expect ( c . disabled ). toBe ( true );
expect ( c . valid ). toBe ( false );
expect ( c . status ). toBe ( 'DISABLED' );
});
2016-08-24 16:58:43 -07:00
it ( 'should not treat objects as boxed values if they have more than two props' , () => {
const c = new FormControl ({ value : '' , disabled : true , test : 'test' }, null , null );
expect ( c . value ). toEqual ({ value : '' , disabled : true , test : 'test' });
expect ( c . disabled ). toBe ( false );
});
it ( 'should not treat objects as boxed values if disabled is missing' , () => {
const c = new FormControl ({ value : '' , test : 'test' }, null , null );
expect ( c . value ). toEqual ({ value : '' , test : 'test' });
expect ( c . disabled ). toBe ( false );
});
});
2016-08-13 17:26:08 -07:00
describe ( 'validator' , () => {
it ( 'should run validator with the initial value' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , Validators . required );
2016-08-13 17:26:08 -07:00
expect ( c . valid ). toEqual ( true );
});
it ( 'should rerun the validator when the value changes' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , Validators . required );
2016-08-13 17:26:08 -07:00
c . setValue ( null );
expect ( c . valid ). toEqual ( false );
});
it ( 'should support arrays of validator functions if passed' , () => {
const c = new FormControl ( 'value' , [ Validators . required , Validators . minLength ( 3 )]);
c . setValue ( 'a' );
expect ( c . valid ). toEqual ( false );
c . setValue ( 'aaa' );
expect ( c . valid ). toEqual ( true );
});
it ( 'should return errors' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( null , Validators . required );
2016-08-13 17:26:08 -07:00
expect ( c . errors ). toEqual ({ 'required' : true });
});
it ( 'should set single validator' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( null );
2016-08-13 17:26:08 -07:00
expect ( c . valid ). toEqual ( true );
c . setValidators ( Validators . required );
c . setValue ( null );
expect ( c . valid ). toEqual ( false );
c . setValue ( 'abc' );
expect ( c . valid ). toEqual ( true );
});
it ( 'should set multiple validators from array' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( '' );
2016-08-13 17:26:08 -07:00
expect ( c . valid ). toEqual ( true );
c . setValidators ([ Validators . minLength ( 5 ), Validators . required ]);
c . setValue ( '' );
expect ( c . valid ). toEqual ( false );
c . setValue ( 'abc' );
expect ( c . valid ). toEqual ( false );
c . setValue ( 'abcde' );
expect ( c . valid ). toEqual ( true );
});
it ( 'should clear validators' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( '' , Validators . required );
2016-08-13 17:26:08 -07:00
expect ( c . valid ). toEqual ( false );
c . clearValidators ();
expect ( c . validator ). toEqual ( null );
c . setValue ( '' );
expect ( c . valid ). toEqual ( true );
});
it ( 'should add after clearing' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( '' , Validators . required );
2016-08-13 17:26:08 -07:00
expect ( c . valid ). toEqual ( false );
c . clearValidators ();
expect ( c . validator ). toEqual ( null );
c . setValidators ([ Validators . required ]);
expect ( c . validator ). not . toBe ( null );
});
});
describe ( 'asyncValidator' , () => {
it ( 'should run validator with the initial value' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , null , asyncValidator ( 'expected' ));
2016-08-13 17:26:08 -07:00
tick ();
expect ( c . valid ). toEqual ( false );
expect ( c . errors ). toEqual ({ 'async' : true });
}));
it ( 'should support validators returning observables' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , null , asyncValidatorReturningObservable );
2016-08-13 17:26:08 -07:00
tick ();
expect ( c . valid ). toEqual ( false );
expect ( c . errors ). toEqual ({ 'async' : true });
}));
it ( 'should rerun the validator when the value changes' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , null , asyncValidator ( 'expected' ));
2016-08-13 17:26:08 -07:00
c . setValue ( 'expected' );
tick ();
expect ( c . valid ). toEqual ( true );
}));
it ( 'should run the async validator only when the sync validator passes' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( '' , Validators . required , asyncValidator ( 'expected' ));
2016-08-13 17:26:08 -07:00
tick ();
expect ( c . errors ). toEqual ({ 'required' : true });
c . setValue ( 'some value' );
tick ();
expect ( c . errors ). toEqual ({ 'async' : true });
}));
it ( 'should mark the control as pending while running the async validation' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( '' , null , asyncValidator ( 'expected' ));
2016-08-13 17:26:08 -07:00
expect ( c . pending ). toEqual ( true );
tick ();
expect ( c . pending ). toEqual ( false );
}));
it ( 'should only use the latest async validation run' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl (
2016-08-13 17:26:08 -07:00
'' , null , asyncValidator ( 'expected' , { 'long' : 200 , 'expected' : 100 }));
c . setValue ( 'long' );
c . setValue ( 'expected' );
tick ( 300 );
expect ( c . valid ). toEqual ( true );
}));
it ( 'should support arrays of async validator functions if passed' , fakeAsync (() => {
const c =
new FormControl ( 'value' , null , [ asyncValidator ( 'expected' ), otherAsyncValidator ]);
tick ();
expect ( c . errors ). toEqual ({ 'async' : true , 'other' : true });
}));
it ( 'should add single async validator' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , null );
2016-08-13 17:26:08 -07:00
c . setAsyncValidators ( asyncValidator ( 'expected' ));
expect ( c . asyncValidator ). not . toEqual ( null );
c . setValue ( 'expected' );
tick ();
expect ( c . valid ). toEqual ( true );
}));
it ( 'should add async validator from array' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , null );
2016-08-13 17:26:08 -07:00
c . setAsyncValidators ([ asyncValidator ( 'expected' )]);
expect ( c . asyncValidator ). not . toEqual ( null );
c . setValue ( 'expected' );
tick ();
expect ( c . valid ). toEqual ( true );
}));
it ( 'should clear async validators' , fakeAsync (() => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'value' , [ asyncValidator ( 'expected' ), otherAsyncValidator ]);
2016-08-13 17:26:08 -07:00
c . clearValidators ();
expect ( c . asyncValidator ). toEqual ( null );
}));
2016-08-24 16:58:43 -07:00
it ( 'should not change validity state if control is disabled while async validating' ,
fakeAsync (() => {
const c = new FormControl ( 'value' , [ asyncValidator ( 'expected' )]);
c . disable ();
tick ();
expect ( c . status ). toEqual ( 'DISABLED' );
}));
2016-08-13 17:26:08 -07:00
});
describe ( 'dirty' , () => {
it ( 'should be false after creating a control' , () => {
const c = new FormControl ( 'value' );
expect ( c . dirty ). toEqual ( false );
});
it ( 'should be true after changing the value of the control' , () => {
const c = new FormControl ( 'value' );
c . markAsDirty ();
expect ( c . dirty ). toEqual ( true );
});
});
describe ( 'touched' , () => {
it ( 'should be false after creating a control' , () => {
const c = new FormControl ( 'value' );
expect ( c . touched ). toEqual ( false );
});
it ( 'should be true after markAsTouched runs' , () => {
const c = new FormControl ( 'value' );
c . markAsTouched ();
expect ( c . touched ). toEqual ( true );
});
});
describe ( 'setValue' , () => {
let g : FormGroup , c : FormControl ;
beforeEach (() => {
c = new FormControl ( 'oldValue' );
g = new FormGroup ({ 'one' : c });
});
it ( 'should set the value of the control' , () => {
c . setValue ( 'newValue' );
expect ( c . value ). toEqual ( 'newValue' );
});
it ( 'should invoke ngOnChanges if it is present' , () => {
let ngOnChanges : any ;
c . registerOnChange (( v : any ) => ngOnChanges = [ 'invoked' , v ]);
c . setValue ( 'newValue' );
expect ( ngOnChanges ). toEqual ([ 'invoked' , 'newValue' ]);
});
it ( 'should not invoke on change when explicitly specified' , () => {
let onChange : any = null ;
c . registerOnChange (( v : any ) => onChange = [ 'invoked' , v ]);
c . setValue ( 'newValue' , { emitModelToViewChange : false });
expect ( onChange ). toBeNull ();
});
it ( 'should set the parent' , () => {
c . setValue ( 'newValue' );
expect ( g . value ). toEqual ({ 'one' : 'newValue' });
});
it ( 'should not set the parent when explicitly specified' , () => {
c . setValue ( 'newValue' , { onlySelf : true });
expect ( g . value ). toEqual ({ 'one' : 'oldValue' });
});
it ( 'should fire an event' , fakeAsync (() => {
c . valueChanges . subscribe (( value ) => { expect ( value ). toEqual ( 'newValue' ); });
c . setValue ( 'newValue' );
tick ();
}));
it ( 'should not fire an event when explicitly specified' , fakeAsync (() => {
c . valueChanges . subscribe (( value ) => { throw 'Should not happen' ; });
c . setValue ( 'newValue' , { emitEvent : false });
tick ();
}));
2016-08-24 16:58:43 -07:00
it ( 'should work on a disabled control' , () => {
g . addControl ( 'two' , new FormControl ( 'two' ));
c . disable ();
c . setValue ( 'new value' );
expect ( c . value ). toEqual ( 'new value' );
expect ( g . value ). toEqual ({ 'two' : 'two' });
});
2016-08-13 17:26:08 -07:00
});
describe ( 'patchValue' , () => {
let g : FormGroup , c : FormControl ;
beforeEach (() => {
c = new FormControl ( 'oldValue' );
g = new FormGroup ({ 'one' : c });
});
it ( 'should set the value of the control' , () => {
c . patchValue ( 'newValue' );
expect ( c . value ). toEqual ( 'newValue' );
});
it ( 'should invoke ngOnChanges if it is present' , () => {
let ngOnChanges : any ;
c . registerOnChange (( v : any ) => ngOnChanges = [ 'invoked' , v ]);
c . patchValue ( 'newValue' );
expect ( ngOnChanges ). toEqual ([ 'invoked' , 'newValue' ]);
});
it ( 'should not invoke on change when explicitly specified' , () => {
let onChange : any = null ;
c . registerOnChange (( v : any ) => onChange = [ 'invoked' , v ]);
c . patchValue ( 'newValue' , { emitModelToViewChange : false });
expect ( onChange ). toBeNull ();
});
it ( 'should set the parent' , () => {
c . patchValue ( 'newValue' );
expect ( g . value ). toEqual ({ 'one' : 'newValue' });
});
it ( 'should not set the parent when explicitly specified' , () => {
c . patchValue ( 'newValue' , { onlySelf : true });
expect ( g . value ). toEqual ({ 'one' : 'oldValue' });
});
it ( 'should fire an event' , fakeAsync (() => {
c . valueChanges . subscribe (( value ) => { expect ( value ). toEqual ( 'newValue' ); });
c . patchValue ( 'newValue' );
tick ();
}));
it ( 'should not fire an event when explicitly specified' , fakeAsync (() => {
c . valueChanges . subscribe (( value ) => { throw 'Should not happen' ; });
c . patchValue ( 'newValue' , { emitEvent : false });
tick ();
}));
2016-08-24 16:58:43 -07:00
it ( 'should patch value on a disabled control' , () => {
g . addControl ( 'two' , new FormControl ( 'two' ));
c . disable ();
c . patchValue ( 'new value' );
expect ( c . value ). toEqual ( 'new value' );
expect ( g . value ). toEqual ({ 'two' : 'two' });
});
2016-08-13 17:26:08 -07:00
});
describe ( 'reset()' , () => {
let c : FormControl ;
beforeEach (() => { c = new FormControl ( 'initial value' ); });
2016-08-24 16:58:43 -07:00
it ( 'should reset to a specific value if passed' , () => {
2016-08-13 17:26:08 -07:00
c . setValue ( 'new value' );
expect ( c . value ). toBe ( 'new value' );
c . reset ( 'initial value' );
expect ( c . value ). toBe ( 'initial value' );
});
2016-10-18 07:51:13 +02:00
it ( 'should not set the parent when explicitly specified' , () => {
const g = new FormGroup ({ 'one' : c });
c . patchValue ( 'newValue' , { onlySelf : true });
expect ( g . value ). toEqual ({ 'one' : 'initial value' });
});
2016-08-24 16:58:43 -07:00
it ( 'should reset to a specific value if passed with boxed value' , () => {
c . setValue ( 'new value' );
expect ( c . value ). toBe ( 'new value' );
c . reset ({ value : 'initial value' , disabled : false });
expect ( c . value ). toBe ( 'initial value' );
});
2016-08-13 17:26:08 -07:00
it ( 'should clear the control value if no value is passed' , () => {
c . setValue ( 'new value' );
expect ( c . value ). toBe ( 'new value' );
c . reset ();
expect ( c . value ). toBe ( null );
});
it ( 'should update the value of any parent controls with passed value' , () => {
const g = new FormGroup ({ 'one' : c });
c . setValue ( 'new value' );
expect ( g . value ). toEqual ({ 'one' : 'new value' });
c . reset ( 'initial value' );
expect ( g . value ). toEqual ({ 'one' : 'initial value' });
});
it ( 'should update the value of any parent controls with null value' , () => {
const g = new FormGroup ({ 'one' : c });
c . setValue ( 'new value' );
expect ( g . value ). toEqual ({ 'one' : 'new value' });
c . reset ();
expect ( g . value ). toEqual ({ 'one' : null });
});
it ( 'should mark the control as pristine' , () => {
c . markAsDirty ();
expect ( c . pristine ). toBe ( false );
c . reset ();
expect ( c . pristine ). toBe ( true );
});
it ( 'should set the parent pristine state if all pristine' , () => {
const g = new FormGroup ({ 'one' : c });
c . markAsDirty ();
expect ( g . pristine ). toBe ( false );
c . reset ();
expect ( g . pristine ). toBe ( true );
});
it ( 'should not set the parent pristine state if it has other dirty controls' , () => {
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ 'one' : c , 'two' : c2 });
c . markAsDirty ();
c2 . markAsDirty ();
c . reset ();
expect ( g . pristine ). toBe ( false );
});
it ( 'should mark the control as untouched' , () => {
c . markAsTouched ();
expect ( c . untouched ). toBe ( false );
c . reset ();
expect ( c . untouched ). toBe ( true );
});
it ( 'should set the parent untouched state if all untouched' , () => {
const g = new FormGroup ({ 'one' : c });
c . markAsTouched ();
expect ( g . untouched ). toBe ( false );
c . reset ();
expect ( g . untouched ). toBe ( true );
});
it ( 'should not set the parent untouched state if other touched controls' , () => {
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ 'one' : c , 'two' : c2 });
c . markAsTouched ();
c2 . markAsTouched ();
c . reset ();
expect ( g . untouched ). toBe ( false );
});
2016-08-24 16:58:43 -07:00
it ( 'should retain the disabled state of the control' , () => {
c . disable ();
c . reset ();
expect ( c . disabled ). toBe ( true );
});
it ( 'should set disabled state based on boxed value if passed' , () => {
c . disable ();
c . reset ({ value : null , disabled : false });
expect ( c . disabled ). toBe ( false );
});
2016-08-13 17:26:08 -07:00
describe ( 'reset() events' , () => {
let g : FormGroup , c2 : FormControl , logger : any [];
beforeEach (() => {
c2 = new FormControl ( 'two' );
g = new FormGroup ({ 'one' : c , 'two' : c2 });
logger = [];
});
it ( 'should emit one valueChange event per reset control' , () => {
g . valueChanges . subscribe (() => logger . push ( 'group' ));
c . valueChanges . subscribe (() => logger . push ( 'control1' ));
c2 . valueChanges . subscribe (() => logger . push ( 'control2' ));
c . reset ();
expect ( logger ). toEqual ([ 'control1' , 'group' ]);
});
2016-10-19 18:54:54 +02:00
it ( 'should not fire an event when explicitly specified' , fakeAsync (() => {
g . valueChanges . subscribe (( value ) => { throw 'Should not happen' ; });
c . valueChanges . subscribe (( value ) => { throw 'Should not happen' ; });
c2 . valueChanges . subscribe (( value ) => { throw 'Should not happen' ; });
c . reset ( null , { emitEvent : false });
tick ();
}));
2016-08-13 17:26:08 -07:00
it ( 'should emit one statusChange event per reset control' , () => {
g . statusChanges . subscribe (() => logger . push ( 'group' ));
c . statusChanges . subscribe (() => logger . push ( 'control1' ));
c2 . statusChanges . subscribe (() => logger . push ( 'control2' ));
c . reset ();
expect ( logger ). toEqual ([ 'control1' , 'group' ]);
});
2016-08-24 16:58:43 -07:00
it ( 'should emit one statusChange event per disabled control' , () => {
g . statusChanges . subscribe (() => logger . push ( 'group' ));
c . statusChanges . subscribe (() => logger . push ( 'control1' ));
c2 . statusChanges . subscribe (() => logger . push ( 'control2' ));
c . reset ({ value : null , disabled : true });
expect ( logger ). toEqual ([ 'control1' , 'group' ]);
});
2016-08-13 17:26:08 -07:00
});
});
describe ( 'valueChanges & statusChanges' , () => {
2016-09-09 12:00:38 -07:00
let c : FormControl ;
2016-08-13 17:26:08 -07:00
beforeEach (() => { c = new FormControl ( 'old' , Validators . required ); });
it ( 'should fire an event after the value has been updated' ,
inject ([ AsyncTestCompleter ], ( async : AsyncTestCompleter ) => {
c . valueChanges . subscribe ({
next : ( value : any ) => {
expect ( c . value ). toEqual ( 'new' );
expect ( value ). toEqual ( 'new' );
async . done ();
}
});
c . setValue ( 'new' );
}));
it ( 'should fire an event after the status has been updated to invalid' , fakeAsync (() => {
c . statusChanges . subscribe ({
next : ( status : any ) => {
expect ( c . status ). toEqual ( 'INVALID' );
expect ( status ). toEqual ( 'INVALID' );
}
});
c . setValue ( '' );
tick ();
}));
it ( 'should fire an event after the status has been updated to pending' , fakeAsync (() => {
2016-11-12 14:08:58 +01:00
const c = new FormControl ( 'old' , Validators . required , asyncValidator ( 'expected' ));
2016-08-13 17:26:08 -07:00
2016-11-12 14:08:58 +01:00
const log : any [] /** TODO #9100 */ = [];
2016-08-13 17:26:08 -07:00
c . valueChanges . subscribe ({ next : ( value : any ) => log . push ( `value: ' ${ value } '` )});
c . statusChanges . subscribe ({ next : ( status : any ) => log . push ( `status: ' ${ status } '` )});
c . setValue ( '' );
tick ();
c . setValue ( 'nonEmpty' );
tick ();
c . setValue ( 'expected' );
tick ();
expect ( log ). toEqual ([
'' +
'value: \'\'' ,
'status: \'INVALID\'' ,
'value: \'nonEmpty\'' ,
'status: \'PENDING\'' ,
'status: \'INVALID\'' ,
'value: \'expected\'' ,
'status: \'PENDING\'' ,
'status: \'VALID\'' ,
]);
}));
// TODO: remove the if statement after making observable delivery sync
it ( 'should update set errors and status before emitting an event' ,
inject ([ AsyncTestCompleter ], ( async : AsyncTestCompleter ) => {
c . valueChanges . subscribe (( value : any /** TODO #9100 */ ) => {
expect ( c . valid ). toEqual ( false );
expect ( c . errors ). toEqual ({ 'required' : true });
async . done ();
});
c . setValue ( '' );
}));
it ( 'should return a cold observable' ,
inject ([ AsyncTestCompleter ], ( async : AsyncTestCompleter ) => {
c . setValue ( 'will be ignored' );
c . valueChanges . subscribe ({
next : ( value : any ) => {
expect ( value ). toEqual ( 'new' );
async . done ();
}
});
c . setValue ( 'new' );
}));
});
describe ( 'setErrors' , () => {
it ( 'should set errors on a control' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'someValue' );
2016-08-13 17:26:08 -07:00
c . setErrors ({ 'someError' : true });
expect ( c . valid ). toEqual ( false );
expect ( c . errors ). toEqual ({ 'someError' : true });
});
it ( 'should reset the errors and validity when the value changes' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'someValue' , Validators . required );
2016-08-13 17:26:08 -07:00
c . setErrors ({ 'someError' : true });
c . setValue ( '' );
expect ( c . errors ). toEqual ({ 'required' : true });
});
it ( 'should update the parent group\'s validity' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'someValue' );
const g = new FormGroup ({ 'one' : c });
2016-08-13 17:26:08 -07:00
expect ( g . valid ). toEqual ( true );
c . setErrors ({ 'someError' : true });
expect ( g . valid ). toEqual ( false );
});
it ( 'should not reset parent\'s errors' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'someValue' );
const g = new FormGroup ({ 'one' : c });
2016-08-13 17:26:08 -07:00
g . setErrors ({ 'someGroupError' : true });
c . setErrors ({ 'someError' : true });
expect ( g . errors ). toEqual ({ 'someGroupError' : true });
});
it ( 'should reset errors when updating a value' , () => {
2016-08-24 16:58:43 -07:00
const c = new FormControl ( 'oldValue' );
const g = new FormGroup ({ 'one' : c });
2016-08-13 17:26:08 -07:00
g . setErrors ({ 'someGroupError' : true });
c . setErrors ({ 'someError' : true });
c . setValue ( 'newValue' );
expect ( c . errors ). toEqual ( null );
expect ( g . errors ). toEqual ( null );
});
});
2016-08-24 16:58:43 -07:00
describe ( 'disable() & enable()' , () => {
it ( 'should mark the control as disabled' , () => {
const c = new FormControl ( null );
expect ( c . disabled ). toBe ( false );
expect ( c . valid ). toBe ( true );
c . disable ();
expect ( c . disabled ). toBe ( true );
expect ( c . valid ). toBe ( false );
c . enable ();
expect ( c . disabled ). toBe ( false );
expect ( c . valid ). toBe ( true );
});
it ( 'should set the control status as disabled' , () => {
const c = new FormControl ( null );
expect ( c . status ). toEqual ( 'VALID' );
c . disable ();
expect ( c . status ). toEqual ( 'DISABLED' );
c . enable ();
expect ( c . status ). toEqual ( 'VALID' );
});
it ( 'should retain the original value when disabled' , () => {
const c = new FormControl ( 'some value' );
expect ( c . value ). toEqual ( 'some value' );
c . disable ();
expect ( c . value ). toEqual ( 'some value' );
c . enable ();
expect ( c . value ). toEqual ( 'some value' );
});
it ( 'should keep the disabled control in the group, but return false for contains()' , () => {
const c = new FormControl ( '' );
const g = new FormGroup ({ 'one' : c });
expect ( g . get ( 'one' )). toBeDefined ();
expect ( g . contains ( 'one' )). toBe ( true );
c . disable ();
expect ( g . get ( 'one' )). toBeDefined ();
expect ( g . contains ( 'one' )). toBe ( false );
});
it ( 'should mark the parent group disabled if all controls are disabled' , () => {
const c = new FormControl ();
const c2 = new FormControl ();
const g = new FormGroup ({ 'one' : c , 'two' : c2 });
expect ( g . enabled ). toBe ( true );
c . disable ();
expect ( g . enabled ). toBe ( true );
c2 . disable ();
expect ( g . enabled ). toBe ( false );
c . enable ();
expect ( g . enabled ). toBe ( true );
});
it ( 'should update the parent group value when child control status changes' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ 'one' : c , 'two' : c2 });
expect ( g . value ). toEqual ({ 'one' : 'one' , 'two' : 'two' });
c . disable ();
expect ( g . value ). toEqual ({ 'two' : 'two' });
c2 . disable ();
expect ( g . value ). toEqual ({ 'one' : 'one' , 'two' : 'two' });
c . enable ();
expect ( g . value ). toEqual ({ 'one' : 'one' });
});
it ( 'should mark the parent array disabled if all controls are disabled' , () => {
const c = new FormControl ();
const c2 = new FormControl ();
const a = new FormArray ([ c , c2 ]);
expect ( a . enabled ). toBe ( true );
c . disable ();
expect ( a . enabled ). toBe ( true );
c2 . disable ();
expect ( a . enabled ). toBe ( false );
c . enable ();
expect ( a . enabled ). toBe ( true );
});
it ( 'should update the parent array value when child control status changes' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const a = new FormArray ([ c , c2 ]);
expect ( a . value ). toEqual ([ 'one' , 'two' ]);
c . disable ();
expect ( a . value ). toEqual ([ 'two' ]);
c2 . disable ();
expect ( a . value ). toEqual ([ 'one' , 'two' ]);
c . enable ();
expect ( a . value ). toEqual ([ 'one' ]);
});
it ( 'should ignore disabled controls in validation' , () => {
const c = new FormControl ( null , Validators . required );
const c2 = new FormControl ( null );
const g = new FormGroup ({ one : c , two : c2 });
expect ( g . valid ). toBe ( false );
c . disable ();
expect ( g . valid ). toBe ( true );
c . enable ();
expect ( g . valid ). toBe ( false );
});
it ( 'should ignore disabled controls when serializing value in a group' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ one : c , two : c2 });
expect ( g . value ). toEqual ({ one : 'one' , two : 'two' });
c . disable ();
expect ( g . value ). toEqual ({ two : 'two' });
c . enable ();
expect ( g . value ). toEqual ({ one : 'one' , two : 'two' });
});
it ( 'should ignore disabled controls when serializing value in an array' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const a = new FormArray ([ c , c2 ]);
expect ( a . value ). toEqual ([ 'one' , 'two' ]);
c . disable ();
expect ( a . value ). toEqual ([ 'two' ]);
c . enable ();
expect ( a . value ). toEqual ([ 'one' , 'two' ]);
});
it ( 'should ignore disabled controls when determining dirtiness' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ one : c , two : c2 });
c . markAsDirty ();
expect ( g . dirty ). toBe ( true );
c . disable ();
expect ( c . dirty ). toBe ( true );
expect ( g . dirty ). toBe ( false );
c . enable ();
expect ( g . dirty ). toBe ( true );
});
it ( 'should ignore disabled controls when determining touched state' , () => {
const c = new FormControl ( 'one' );
const c2 = new FormControl ( 'two' );
const g = new FormGroup ({ one : c , two : c2 });
c . markAsTouched ();
expect ( g . touched ). toBe ( true );
c . disable ();
expect ( c . touched ). toBe ( true );
expect ( g . touched ). toBe ( false );
c . enable ();
expect ( g . touched ). toBe ( true );
});
2016-09-09 12:00:38 -07:00
it ( 'should not run validators on disabled controls' , () => {
const validator = jasmine . createSpy ( 'validator' );
const c = new FormControl ( '' , validator );
expect ( validator . calls . count ()). toEqual ( 1 );
c . disable ();
expect ( validator . calls . count ()). toEqual ( 1 );
c . setValue ( 'value' );
expect ( validator . calls . count ()). toEqual ( 1 );
c . enable ();
expect ( validator . calls . count ()). toEqual ( 2 );
});
describe ( 'disabled errors' , () => {
it ( 'should clear out the errors when disabled' , () => {
const c = new FormControl ( '' , Validators . required );
expect ( c . errors ). toEqual ({ required : true });
c . disable ();
expect ( c . errors ). toEqual ( null );
c . enable ();
expect ( c . errors ). toEqual ({ required : true });
});
it ( 'should clear out async errors when disabled' , fakeAsync (() => {
const c = new FormControl ( '' , null , asyncValidator ( 'expected' ));
tick ();
expect ( c . errors ). toEqual ({ 'async' : true });
c . disable ();
expect ( c . errors ). toEqual ( null );
c . enable ();
tick ();
expect ( c . errors ). toEqual ({ 'async' : true });
}));
});
2016-08-24 16:58:43 -07:00
describe ( 'disabled events' , () => {
let logger : string [];
let c : FormControl ;
let g : FormGroup ;
beforeEach (() => {
logger = [];
c = new FormControl ( '' , Validators . required );
g = new FormGroup ({ one : c });
});
it ( 'should emit a statusChange event when disabled status changes' , () => {
c . statusChanges . subscribe (( status : string ) => logger . push ( status ));
c . disable ();
expect ( logger ). toEqual ([ 'DISABLED' ]);
c . enable ();
expect ( logger ). toEqual ([ 'DISABLED' , 'INVALID' ]);
});
it ( 'should emit status change events in correct order' , () => {
c . statusChanges . subscribe (() => logger . push ( 'control' ));
g . statusChanges . subscribe (() => logger . push ( 'group' ));
c . disable ();
expect ( logger ). toEqual ([ 'control' , 'group' ]);
});
2017-01-22 21:37:22 +13:00
it ( 'should throw when sync validator passed into async validator param' , () => {
const fn = () => new FormControl ( '' , syncValidator , syncValidator );
// test for the specific error since without the error check it would still throw an error
// but
// not a meaningful one
expect ( fn ). toThrowError (
`expected the following validator to return Promise or Observable: ${ syncValidator } . If you are using FormBuilder; did you forget to brace your validators in an array?` );
});
2016-08-24 16:58:43 -07:00
});
});
2016-08-13 17:26:08 -07:00
});
}