2016-08-13 20:26:08 -04: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
* /
2017-03-01 13:28:52 -05:00
import { EventEmitter } from '@angular/core' ;
2016-08-13 20:26:08 -04:00
import { fakeAsync , tick } from '@angular/core/testing' ;
2016-09-27 20:12:25 -04:00
import { AsyncTestCompleter , beforeEach , describe , inject , it } from '@angular/core/testing/testing_internal' ;
2016-08-13 20:26:08 -04:00
import { FormControl , FormGroup , Validators } from '@angular/forms' ;
2016-08-24 19:58:43 -04:00
import { FormArray } from '../src/model' ;
2016-08-13 20:26:08 -04:00
export function main() {
2016-09-09 15:00:38 -04:00
function asyncValidator ( expected : string , timeouts = { } ) {
return ( c : FormControl ) = > {
2016-11-12 08:08:58 -05:00
let resolve : ( result : any ) = > void ;
const promise = new Promise ( res = > { resolve = res ; } ) ;
2017-03-02 12:37:01 -05:00
const t = ( timeouts as any ) [ c . value ] != null ? ( timeouts as any ) [ c . value ] : 0 ;
2016-11-12 08:08:58 -05:00
const res = c . value != expected ? { 'async' : true } : null ;
2016-08-13 20:26:08 -04:00
if ( t == 0 ) {
resolve ( res ) ;
} else {
setTimeout ( ( ) = > { resolve ( res ) ; } , t ) ;
}
return promise ;
} ;
}
function asyncValidatorReturningObservable ( c : FormControl ) {
2016-11-12 08:08:58 -05:00
const e = new EventEmitter ( ) ;
2016-08-13 20:26:08 -04:00
Promise . resolve ( null ) . then ( ( ) = > { e . emit ( { 'async' : true } ) ; } ) ;
return e ;
}
function otherAsyncValidator() { return Promise . resolve ( { 'other' : true } ) ; }
2017-01-22 03:37:22 -05:00
function syncValidator ( _ : any /** TODO #9100 */ ) : any /** TODO #9100 */ { return null ; }
2016-08-13 20:26:08 -04:00
describe ( 'FormControl' , ( ) = > {
it ( 'should default the value to null' , ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( ) ;
2016-08-13 20:26:08 -04:00
expect ( c . value ) . toBe ( null ) ;
} ) ;
2016-08-24 19:58:43 -04: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 19:51:42 -04: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 19:58:43 -04: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 20:26:08 -04:00
describe ( 'validator' , ( ) = > {
it ( 'should run validator with the initial value' , ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( 'value' , Validators . required ) ;
2016-08-13 20:26:08 -04:00
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
it ( 'should rerun the validator when the value changes' , ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( 'value' , Validators . required ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( null , Validators . required ) ;
2016-08-13 20:26:08 -04:00
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
} ) ;
it ( 'should set single validator' , ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( null ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( '' ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( '' , Validators . required ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( '' , Validators . required ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'value' , null , asyncValidator ( 'expected' ) ) ;
2016-08-13 20:26:08 -04:00
tick ( ) ;
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
} ) ) ;
it ( 'should support validators returning observables' , fakeAsync ( ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( 'value' , null , asyncValidatorReturningObservable ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'value' , null , asyncValidator ( 'expected' ) ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( '' , Validators . required , asyncValidator ( 'expected' ) ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( '' , null , asyncValidator ( 'expected' ) ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl (
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'value' , null ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'value' , null ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'value' , [ asyncValidator ( 'expected' ) , otherAsyncValidator ] ) ;
2016-08-13 20:26:08 -04:00
c . clearValidators ( ) ;
expect ( c . asyncValidator ) . toEqual ( null ) ;
} ) ) ;
2016-08-24 19:58:43 -04: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 20:26:08 -04: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 19:58:43 -04: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 20:26:08 -04: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 19:58:43 -04: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 20:26:08 -04:00
} ) ;
describe ( 'reset()' , ( ) = > {
let c : FormControl ;
beforeEach ( ( ) = > { c = new FormControl ( 'initial value' ) ; } ) ;
2016-08-24 19:58:43 -04:00
it ( 'should reset to a specific value if passed' , ( ) = > {
2016-08-13 20:26:08 -04:00
c . setValue ( 'new value' ) ;
expect ( c . value ) . toBe ( 'new value' ) ;
c . reset ( 'initial value' ) ;
expect ( c . value ) . toBe ( 'initial value' ) ;
} ) ;
2016-10-18 01:51:13 -04: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 19:58:43 -04: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 20:26:08 -04: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 19:58:43 -04: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 20:26:08 -04: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 12:54:54 -04: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 20:26:08 -04: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 19:58:43 -04: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 20:26:08 -04:00
} ) ;
} ) ;
describe ( 'valueChanges & statusChanges' , ( ) = > {
2016-09-09 15:00:38 -04:00
let c : FormControl ;
2016-08-13 20:26:08 -04: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 08:08:58 -05:00
const c = new FormControl ( 'old' , Validators . required , asyncValidator ( 'expected' ) ) ;
2016-08-13 20:26:08 -04:00
2016-11-12 08:08:58 -05:00
const log : any [ ] /** TODO #9100 */ = [ ] ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'someValue' ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'someValue' , Validators . required ) ;
2016-08-13 20:26:08 -04:00
c . setErrors ( { 'someError' : true } ) ;
c . setValue ( '' ) ;
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
} ) ;
it ( 'should update the parent group\'s validity' , ( ) = > {
2016-08-24 19:58:43 -04:00
const c = new FormControl ( 'someValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'someValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04:00
const c = new FormControl ( 'oldValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-13 20:26:08 -04: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 19:58:43 -04: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 15:00:38 -04: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 19:58:43 -04: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 03:37:22 -05: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 19:58:43 -04:00
} ) ;
} ) ;
2016-08-13 20:26:08 -04:00
} ) ;
}