2016-06-23 12:47:54 -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
|
|
|
|
*/
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
import {afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
|
|
|
|
2016-06-23 20:10:22 -04:00
|
|
|
import {fakeAsync, flushMicrotasks, tick,} from '@angular/core/testing';
|
2015-06-17 17:45:40 -04:00
|
|
|
|
2015-09-30 20:52:33 -04:00
|
|
|
import {SpyNgControl, SpyValueAccessor} from '../spies';
|
|
|
|
|
2016-06-10 13:09:50 -04:00
|
|
|
import {ControlGroup, Control, NgControlName, NgControlGroup, NgFormModel, ControlValueAccessor, Validators, NgForm, NgModel, NgFormControl, NgControl, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, Validator} from '@angular/common/src/forms-deprecated';
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2015-09-30 20:52:33 -04:00
|
|
|
|
2016-06-08 13:44:04 -04:00
|
|
|
import {selectValueAccessor, composeValidators} from '@angular/common/src/forms-deprecated/directives/shared';
|
2016-04-28 20:50:03 -04:00
|
|
|
import {TimerWrapper} from '../../src/facade/async';
|
|
|
|
import {PromiseWrapper} from '../../src/facade/promise';
|
|
|
|
import {SimpleChange} from '@angular/core/src/change_detection';
|
2015-09-30 20:52:33 -04:00
|
|
|
|
2015-05-30 14:56:00 -04:00
|
|
|
class DummyControlValueAccessor implements ControlValueAccessor {
|
2016-06-08 18:45:15 -04:00
|
|
|
writtenValue: any /** TODO #9100 */;
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-08 18:45:15 -04:00
|
|
|
registerOnChange(fn: any /** TODO #9100 */) {}
|
|
|
|
registerOnTouched(fn: any /** TODO #9100 */) {}
|
2015-05-30 14:56:00 -04:00
|
|
|
|
|
|
|
writeValue(obj: any): void { this.writtenValue = obj; }
|
|
|
|
}
|
2015-05-11 15:00:56 -04:00
|
|
|
|
2015-10-28 19:54:27 -04:00
|
|
|
class CustomValidatorDirective implements Validator {
|
2016-06-08 19:38:52 -04:00
|
|
|
validate(c: Control): {[key: string]: any} { return {'custom': true}; }
|
2015-10-28 19:54:27 -04:00
|
|
|
}
|
|
|
|
|
2016-06-08 18:45:15 -04:00
|
|
|
function asyncValidator(expected: any /** TODO #9100 */, timeout = 0) {
|
|
|
|
return (c: any /** TODO #9100 */) => {
|
2015-11-02 13:00:42 -05:00
|
|
|
var completer = PromiseWrapper.completer();
|
2016-06-08 19:38:52 -04:00
|
|
|
var res = c.value != expected ? {'async': true} : null;
|
2015-11-02 13:00:42 -05:00
|
|
|
if (timeout == 0) {
|
|
|
|
completer.resolve(res);
|
|
|
|
} else {
|
|
|
|
TimerWrapper.setTimeout(() => { completer.resolve(res); }, timeout);
|
|
|
|
}
|
|
|
|
return completer.promise;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-05-11 15:00:56 -04:00
|
|
|
export function main() {
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('Form Directives', () => {
|
2016-04-28 20:50:03 -04:00
|
|
|
var defaultAccessor: DefaultValueAccessor;
|
2015-09-30 20:52:33 -04:00
|
|
|
|
|
|
|
beforeEach(() => { defaultAccessor = new DefaultValueAccessor(null, null); });
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('shared', () => {
|
|
|
|
describe('selectValueAccessor', () => {
|
2015-09-30 20:52:33 -04:00
|
|
|
var dir: NgControl;
|
|
|
|
|
|
|
|
beforeEach(() => { dir = <any>new SpyNgControl(); });
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should throw when given an empty array',
|
2015-09-30 20:52:33 -04:00
|
|
|
() => { expect(() => selectValueAccessor(dir, [])).toThrowError(); });
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should return the default value accessor when no other provided',
|
2015-09-30 20:52:33 -04:00
|
|
|
() => { expect(selectValueAccessor(dir, [defaultAccessor])).toEqual(defaultAccessor); });
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should return checkbox accessor when provided', () => {
|
2015-09-30 20:52:33 -04:00
|
|
|
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(selectValueAccessor(dir, [
|
|
|
|
defaultAccessor, checkboxAccessor
|
|
|
|
])).toEqual(checkboxAccessor);
|
2015-09-30 20:52:33 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should return select accessor when provided', () => {
|
2016-04-01 22:27:25 -04:00
|
|
|
var selectAccessor = new SelectControlValueAccessor(null, null);
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(selectValueAccessor(dir, [
|
|
|
|
defaultAccessor, selectAccessor
|
|
|
|
])).toEqual(selectAccessor);
|
2015-09-30 20:52:33 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should throw when more than one build-in accessor is provided', () => {
|
2015-09-30 20:52:33 -04:00
|
|
|
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
2016-04-01 22:27:25 -04:00
|
|
|
var selectAccessor = new SelectControlValueAccessor(null, null);
|
2015-09-30 20:52:33 -04:00
|
|
|
expect(() => selectValueAccessor(dir, [checkboxAccessor, selectAccessor])).toThrowError();
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should return custom accessor when provided', () => {
|
2015-09-30 20:52:33 -04:00
|
|
|
var customAccessor = new SpyValueAccessor();
|
|
|
|
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
2016-04-28 20:50:03 -04:00
|
|
|
expect(selectValueAccessor(dir, <any>[defaultAccessor, customAccessor, checkboxAccessor]))
|
2016-04-12 12:40:37 -04:00
|
|
|
.toEqual(customAccessor);
|
2015-09-30 20:52:33 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should throw when more than one custom accessor is provided', () => {
|
2015-10-05 19:02:21 -04:00
|
|
|
var customAccessor: ControlValueAccessor = <any>new SpyValueAccessor();
|
2015-09-30 20:52:33 -04:00
|
|
|
expect(() => selectValueAccessor(dir, [customAccessor, customAccessor])).toThrowError();
|
|
|
|
});
|
|
|
|
});
|
2015-10-28 19:54:27 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('composeValidators', () => {
|
|
|
|
it('should compose functions', () => {
|
|
|
|
var dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true});
|
|
|
|
var dummy2 = (_: any /** TODO #9100 */) => ({'dummy2': true});
|
2015-10-28 19:54:27 -04:00
|
|
|
var v = composeValidators([dummy1, dummy2]);
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(v(new Control(''))).toEqual({'dummy1': true, 'dummy2': true});
|
2015-10-28 19:54:27 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should compose validator directives', () => {
|
|
|
|
var dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true});
|
2015-10-28 19:54:27 -04:00
|
|
|
var v = composeValidators([dummy1, new CustomValidatorDirective()]);
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(v(new Control(''))).toEqual({'dummy1': true, 'custom': true});
|
2015-10-28 19:54:27 -04:00
|
|
|
});
|
|
|
|
});
|
2015-09-30 20:52:33 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgFormModel', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var form: any /** TODO #9100 */;
|
2015-11-06 20:34:07 -05:00
|
|
|
var formModel: ControlGroup;
|
2016-06-08 18:45:15 -04:00
|
|
|
var loginControlDir: any /** TODO #9100 */;
|
2015-05-30 14:56:00 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
form = new NgFormModel([], []);
|
2015-10-27 17:36:13 -04:00
|
|
|
formModel = new ControlGroup({
|
2016-06-08 19:38:52 -04:00
|
|
|
'login': new Control(),
|
|
|
|
'passwords':
|
|
|
|
new ControlGroup({'password': new Control(), 'passwordConfirm': new Control()})
|
2015-10-27 17:36:13 -04:00
|
|
|
});
|
2015-05-30 14:56:00 -04:00
|
|
|
form.form = formModel;
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
loginControlDir = new NgControlName(
|
|
|
|
form, [Validators.required], [asyncValidator('expected')], [defaultAccessor]);
|
|
|
|
loginControlDir.name = 'login';
|
2015-05-30 14:56:00 -04:00
|
|
|
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => {
|
2015-07-07 18:53:16 -04:00
|
|
|
expect(form.control).toBe(formModel);
|
|
|
|
expect(form.value).toBe(formModel.value);
|
|
|
|
expect(form.valid).toBe(formModel.valid);
|
|
|
|
expect(form.errors).toBe(formModel.errors);
|
|
|
|
expect(form.pristine).toBe(formModel.pristine);
|
|
|
|
expect(form.dirty).toBe(formModel.dirty);
|
|
|
|
expect(form.touched).toBe(formModel.touched);
|
|
|
|
expect(form.untouched).toBe(formModel.untouched);
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('addControl', () => {
|
|
|
|
it('should throw when no control found', () => {
|
2015-11-02 13:00:42 -05:00
|
|
|
var dir = new NgControlName(form, null, null, [defaultAccessor]);
|
2016-06-08 19:38:52 -04:00
|
|
|
dir.name = 'invalidName';
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-22 17:58:57 -04:00
|
|
|
expect(() => form.addControl(dir)).toThrowError(/Cannot find control 'invalidName'/);
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should throw when no value accessor', () => {
|
2015-11-02 13:00:42 -05:00
|
|
|
var dir = new NgControlName(form, null, null, null);
|
2016-06-08 19:38:52 -04:00
|
|
|
dir.name = 'login';
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-22 17:58:57 -04:00
|
|
|
expect(() => form.addControl(dir)).toThrowError(/No value accessor for 'login'/);
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up validators', fakeAsync(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
form.addControl(loginControlDir);
|
|
|
|
|
|
|
|
// sync validators are set
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.hasError('required', ['login'])).toBe(true);
|
|
|
|
expect(formModel.hasError('async', ['login'])).toBe(false);
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
(<Control>formModel.find(['login'])).updateValue('invalid value');
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
// sync validator passes, running async validators
|
|
|
|
expect(formModel.pending).toBe(true);
|
|
|
|
|
|
|
|
tick();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.hasError('required', ['login'])).toBe(false);
|
|
|
|
expect(formModel.hasError('async', ['login'])).toBe(true);
|
2015-11-02 13:00:42 -05:00
|
|
|
}));
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should write value to the DOM', () => {
|
|
|
|
(<Control>formModel.find(['login'])).updateValue('initValue');
|
2015-05-30 14:56:00 -04:00
|
|
|
|
|
|
|
form.addControl(loginControlDir);
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual('initValue');
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should add the directive to the list of directives included in the form', () => {
|
2015-05-30 14:56:00 -04:00
|
|
|
form.addControl(loginControlDir);
|
|
|
|
expect(form.directives).toEqual([loginControlDir]);
|
|
|
|
});
|
2015-05-11 15:00:56 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('addControlGroup', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var matchingPasswordsValidator = (g: any /** TODO #9100 */) => {
|
2016-06-08 19:38:52 -04:00
|
|
|
if (g.controls['password'].value != g.controls['passwordConfirm'].value) {
|
|
|
|
return {'differentPasswords': true};
|
2015-10-27 17:36:13 -04:00
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up validator', fakeAsync(() => {
|
|
|
|
var group = new NgControlGroup(
|
|
|
|
form, [matchingPasswordsValidator], [asyncValidator('expected')]);
|
|
|
|
group.name = 'passwords';
|
2015-11-02 13:00:42 -05:00
|
|
|
form.addControlGroup(group);
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
(<Control>formModel.find(['passwords', 'password'])).updateValue('somePassword');
|
|
|
|
(<Control>formModel.find([
|
|
|
|
'passwords', 'passwordConfirm'
|
|
|
|
])).updateValue('someOtherPassword');
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
// sync validators are set
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.hasError('differentPasswords', ['passwords'])).toEqual(true);
|
2015-11-02 13:00:42 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
(<Control>formModel.find([
|
|
|
|
'passwords', 'passwordConfirm'
|
|
|
|
])).updateValue('somePassword');
|
2015-11-02 13:00:42 -05:00
|
|
|
|
|
|
|
// sync validators pass, running async validators
|
|
|
|
expect(formModel.pending).toBe(true);
|
|
|
|
|
|
|
|
tick();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.hasError('async', ['passwords'])).toBe(true);
|
2015-11-02 13:00:42 -05:00
|
|
|
}));
|
2015-10-27 17:36:13 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('removeControl', () => {
|
|
|
|
it('should remove the directive to the list of directives included in the form', () => {
|
2015-05-30 14:56:00 -04:00
|
|
|
form.addControl(loginControlDir);
|
|
|
|
form.removeControl(loginControlDir);
|
|
|
|
expect(form.directives).toEqual([]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('ngOnChanges', () => {
|
|
|
|
it('should update dom values of all the directives', () => {
|
2015-05-30 14:56:00 -04:00
|
|
|
form.addControl(loginControlDir);
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
(<Control>formModel.find(['login'])).updateValue('new value');
|
2015-05-30 14:56:00 -04:00
|
|
|
|
refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.
To fix, just rename these methods:
* onInit
* onDestroy
* doCheck
* onChanges
* afterContentInit
* afterContentChecked
* afterViewInit
* afterViewChecked
* _Router Hooks_
* onActivate
* onReuse
* onDeactivate
* canReuse
* canDeactivate
To:
* ngOnInit,
* ngOnDestroy,
* ngDoCheck,
* ngOnChanges,
* ngAfterContentInit,
* ngAfterContentChecked,
* ngAfterViewInit,
* ngAfterViewChecked
* _Router Hooks_
* routerOnActivate
* routerOnReuse
* routerOnDeactivate
* routerCanReuse
* routerCanDeactivate
The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.
Closes #5036
2015-11-16 20:04:36 -05:00
|
|
|
form.ngOnChanges({});
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual('new value');
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up a sync validator', () => {
|
|
|
|
var formValidator = (c: any /** TODO #9100 */) => ({'custom': true});
|
2015-11-02 13:00:42 -05:00
|
|
|
var f = new NgFormModel([formValidator], []);
|
2015-10-27 17:36:13 -04:00
|
|
|
f.form = formModel;
|
2016-06-08 19:38:52 -04:00
|
|
|
f.ngOnChanges({'form': new SimpleChange(null, null)});
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.errors).toEqual({'custom': true});
|
2015-10-27 17:36:13 -04:00
|
|
|
});
|
2015-11-02 13:00:42 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up an async validator', fakeAsync(() => {
|
|
|
|
var f = new NgFormModel([], [asyncValidator('expected')]);
|
2015-11-02 13:00:42 -05:00
|
|
|
f.form = formModel;
|
2016-06-08 19:38:52 -04:00
|
|
|
f.ngOnChanges({'form': new SimpleChange(null, null)});
|
2015-11-02 13:00:42 -05:00
|
|
|
|
|
|
|
tick();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.errors).toEqual({'async': true});
|
2015-11-02 13:00:42 -05:00
|
|
|
}));
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgForm', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var form: any /** TODO #9100 */;
|
2015-11-06 20:34:07 -05:00
|
|
|
var formModel: ControlGroup;
|
2016-06-08 18:45:15 -04:00
|
|
|
var loginControlDir: any /** TODO #9100 */;
|
|
|
|
var personControlGroupDir: any /** TODO #9100 */;
|
2015-05-30 14:56:00 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
form = new NgForm([], []);
|
2015-05-30 14:56:00 -04:00
|
|
|
formModel = form.form;
|
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
personControlGroupDir = new NgControlGroup(form, [], []);
|
2016-06-08 19:38:52 -04:00
|
|
|
personControlGroupDir.name = 'person';
|
2015-05-30 14:56:00 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
loginControlDir = new NgControlName(personControlGroupDir, null, null, [defaultAccessor]);
|
2016-06-08 19:38:52 -04:00
|
|
|
loginControlDir.name = 'login';
|
2015-05-30 14:56:00 -04:00
|
|
|
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => {
|
2015-07-07 18:53:16 -04:00
|
|
|
expect(form.control).toBe(formModel);
|
|
|
|
expect(form.value).toBe(formModel.value);
|
|
|
|
expect(form.valid).toBe(formModel.valid);
|
|
|
|
expect(form.errors).toBe(formModel.errors);
|
|
|
|
expect(form.pristine).toBe(formModel.pristine);
|
|
|
|
expect(form.dirty).toBe(formModel.dirty);
|
|
|
|
expect(form.touched).toBe(formModel.touched);
|
|
|
|
expect(form.untouched).toBe(formModel.untouched);
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('addControl & addControlGroup', () => {
|
|
|
|
it('should create a control with the given name', fakeAsync(() => {
|
2015-05-30 14:56:00 -04:00
|
|
|
form.addControlGroup(personControlGroupDir);
|
|
|
|
form.addControl(loginControlDir);
|
|
|
|
|
|
|
|
flushMicrotasks();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.find(['person', 'login'])).not.toBeNull;
|
2015-05-30 14:56:00 -04:00
|
|
|
}));
|
|
|
|
|
|
|
|
// should update the form's value and validity
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('removeControl & removeControlGroup', () => {
|
|
|
|
it('should remove control', fakeAsync(() => {
|
2015-05-30 14:56:00 -04:00
|
|
|
form.addControlGroup(personControlGroupDir);
|
|
|
|
form.addControl(loginControlDir);
|
|
|
|
|
|
|
|
form.removeControlGroup(personControlGroupDir);
|
|
|
|
form.removeControl(loginControlDir);
|
|
|
|
|
|
|
|
flushMicrotasks();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(formModel.find(['person'])).toBeNull();
|
|
|
|
expect(formModel.find(['person', 'login'])).toBeNull();
|
2015-05-30 14:56:00 -04:00
|
|
|
}));
|
|
|
|
|
|
|
|
// should update the form's value and validity
|
|
|
|
});
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up sync validator', fakeAsync(() => {
|
|
|
|
var formValidator = (c: any /** TODO #9100 */) => ({'custom': true});
|
2015-11-02 13:00:42 -05:00
|
|
|
var f = new NgForm([formValidator], []);
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
tick();
|
2015-10-27 17:36:13 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(f.form.errors).toEqual({'custom': true});
|
2015-10-27 17:36:13 -04:00
|
|
|
}));
|
2015-11-02 13:00:42 -05:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up async validator', fakeAsync(() => {
|
|
|
|
var f = new NgForm([], [asyncValidator('expected')]);
|
2015-11-02 13:00:42 -05:00
|
|
|
|
|
|
|
tick();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(f.form.errors).toEqual({'async': true});
|
2015-11-02 13:00:42 -05:00
|
|
|
}));
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgControlGroup', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var formModel: any /** TODO #9100 */;
|
|
|
|
var controlGroupDir: any /** TODO #9100 */;
|
2015-07-07 18:53:16 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2016-06-08 19:38:52 -04:00
|
|
|
formModel = new ControlGroup({'login': new Control(null)});
|
2015-07-07 18:53:16 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
var parent = new NgFormModel([], []);
|
2016-06-08 19:38:52 -04:00
|
|
|
parent.form = new ControlGroup({'group': formModel});
|
2015-11-02 13:00:42 -05:00
|
|
|
controlGroupDir = new NgControlGroup(parent, [], []);
|
2016-06-08 19:38:52 -04:00
|
|
|
controlGroupDir.name = 'group';
|
2015-07-07 18:53:16 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => {
|
2015-07-07 18:53:16 -04:00
|
|
|
expect(controlGroupDir.control).toBe(formModel);
|
|
|
|
expect(controlGroupDir.value).toBe(formModel.value);
|
|
|
|
expect(controlGroupDir.valid).toBe(formModel.valid);
|
|
|
|
expect(controlGroupDir.errors).toBe(formModel.errors);
|
|
|
|
expect(controlGroupDir.pristine).toBe(formModel.pristine);
|
|
|
|
expect(controlGroupDir.dirty).toBe(formModel.dirty);
|
|
|
|
expect(controlGroupDir.touched).toBe(formModel.touched);
|
|
|
|
expect(controlGroupDir.untouched).toBe(formModel.untouched);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgFormControl', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var controlDir: any /** TODO #9100 */;
|
|
|
|
var control: any /** TODO #9100 */;
|
|
|
|
var checkProperties = function(control: any /** TODO #9100 */) {
|
2015-09-27 20:06:52 -04:00
|
|
|
expect(controlDir.control).toBe(control);
|
|
|
|
expect(controlDir.value).toBe(control.value);
|
|
|
|
expect(controlDir.valid).toBe(control.valid);
|
|
|
|
expect(controlDir.errors).toBe(control.errors);
|
|
|
|
expect(controlDir.pristine).toBe(control.pristine);
|
|
|
|
expect(controlDir.dirty).toBe(control.dirty);
|
|
|
|
expect(controlDir.touched).toBe(control.touched);
|
|
|
|
expect(controlDir.untouched).toBe(control.untouched);
|
|
|
|
};
|
2015-05-30 14:56:00 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
controlDir = new NgFormControl([Validators.required], [], [defaultAccessor]);
|
2015-05-30 14:56:00 -04:00
|
|
|
controlDir.valueAccessor = new DummyControlValueAccessor();
|
|
|
|
|
|
|
|
control = new Control(null);
|
2015-06-03 14:56:01 -04:00
|
|
|
controlDir.form = control;
|
2015-05-30 14:56:00 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => { checkProperties(control); });
|
2015-09-27 20:06:52 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport new control properties', () => {
|
2015-09-27 20:06:52 -04:00
|
|
|
var newControl = new Control(null);
|
|
|
|
controlDir.form = newControl;
|
2016-06-08 19:38:52 -04:00
|
|
|
controlDir.ngOnChanges({'form': new SimpleChange(control, newControl)});
|
2015-09-27 20:06:52 -04:00
|
|
|
|
|
|
|
checkProperties(newControl);
|
2015-07-07 18:53:16 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up validator', () => {
|
2015-05-30 14:56:00 -04:00
|
|
|
expect(control.valid).toBe(true);
|
|
|
|
|
|
|
|
// this will add the required validator and recalculate the validity
|
2016-06-08 19:38:52 -04:00
|
|
|
controlDir.ngOnChanges({'form': new SimpleChange(null, control)});
|
2015-05-11 15:00:56 -04:00
|
|
|
|
2015-05-30 14:56:00 -04:00
|
|
|
expect(control.valid).toBe(false);
|
2015-05-11 15:00:56 -04:00
|
|
|
});
|
|
|
|
});
|
2015-06-17 17:45:40 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgModel', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var ngModel: any /** TODO #9100 */;
|
2015-06-17 17:45:40 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
ngModel =
|
2016-06-08 19:38:52 -04:00
|
|
|
new NgModel([Validators.required], [asyncValidator('expected')], [defaultAccessor]);
|
2015-06-17 17:45:40 -04:00
|
|
|
ngModel.valueAccessor = new DummyControlValueAccessor();
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => {
|
2015-07-07 18:53:16 -04:00
|
|
|
var control = ngModel.control;
|
|
|
|
expect(ngModel.control).toBe(control);
|
|
|
|
expect(ngModel.value).toBe(control.value);
|
|
|
|
expect(ngModel.valid).toBe(control.valid);
|
|
|
|
expect(ngModel.errors).toBe(control.errors);
|
|
|
|
expect(ngModel.pristine).toBe(control.pristine);
|
|
|
|
expect(ngModel.dirty).toBe(control.dirty);
|
|
|
|
expect(ngModel.touched).toBe(control.touched);
|
|
|
|
expect(ngModel.untouched).toBe(control.untouched);
|
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should set up validator', fakeAsync(() => {
|
2015-11-02 13:00:42 -05:00
|
|
|
// this will add the required validator and recalculate the validity
|
refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.
To fix, just rename these methods:
* onInit
* onDestroy
* doCheck
* onChanges
* afterContentInit
* afterContentChecked
* afterViewInit
* afterViewChecked
* _Router Hooks_
* onActivate
* onReuse
* onDeactivate
* canReuse
* canDeactivate
To:
* ngOnInit,
* ngOnDestroy,
* ngDoCheck,
* ngOnChanges,
* ngAfterContentInit,
* ngAfterContentChecked,
* ngAfterViewInit,
* ngAfterViewChecked
* _Router Hooks_
* routerOnActivate
* routerOnReuse
* routerOnDeactivate
* routerCanReuse
* routerCanDeactivate
The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.
Closes #5036
2015-11-16 20:04:36 -05:00
|
|
|
ngModel.ngOnChanges({});
|
2015-11-02 13:00:42 -05:00
|
|
|
tick();
|
2015-06-17 17:45:40 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(ngModel.control.errors).toEqual({'required': true});
|
2015-06-17 17:45:40 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
ngModel.control.updateValue('someValue');
|
2015-11-02 13:00:42 -05:00
|
|
|
tick();
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
expect(ngModel.control.errors).toEqual({'async': true});
|
2015-11-02 13:00:42 -05:00
|
|
|
}));
|
2015-06-17 17:45:40 -04:00
|
|
|
});
|
2015-07-07 18:53:16 -04:00
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
describe('NgControlName', () => {
|
2016-06-08 18:45:15 -04:00
|
|
|
var formModel: any /** TODO #9100 */;
|
|
|
|
var controlNameDir: any /** TODO #9100 */;
|
2015-07-07 18:53:16 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2016-06-08 19:38:52 -04:00
|
|
|
formModel = new Control('name');
|
2015-07-07 18:53:16 -04:00
|
|
|
|
2015-11-02 13:00:42 -05:00
|
|
|
var parent = new NgFormModel([], []);
|
2016-06-08 19:38:52 -04:00
|
|
|
parent.form = new ControlGroup({'name': formModel});
|
2015-11-02 13:00:42 -05:00
|
|
|
controlNameDir = new NgControlName(parent, [], [], [defaultAccessor]);
|
2016-06-08 19:38:52 -04:00
|
|
|
controlNameDir.name = 'name';
|
2015-07-07 18:53:16 -04:00
|
|
|
});
|
|
|
|
|
2016-06-08 19:38:52 -04:00
|
|
|
it('should reexport control properties', () => {
|
2015-07-07 18:53:16 -04:00
|
|
|
expect(controlNameDir.control).toBe(formModel);
|
|
|
|
expect(controlNameDir.value).toBe(formModel.value);
|
|
|
|
expect(controlNameDir.valid).toBe(formModel.valid);
|
|
|
|
expect(controlNameDir.errors).toBe(formModel.errors);
|
|
|
|
expect(controlNameDir.pristine).toBe(formModel.pristine);
|
|
|
|
expect(controlNameDir.dirty).toBe(formModel.dirty);
|
|
|
|
expect(controlNameDir.touched).toBe(formModel.touched);
|
|
|
|
expect(controlNameDir.untouched).toBe(formModel.untouched);
|
|
|
|
});
|
|
|
|
});
|
2015-05-11 15:00:56 -04:00
|
|
|
});
|
|
|
|
}
|