refactor(core): move directives, pipes, and forms into common
BREAKING CHANGE
All private exports from 'angular2/src/core/{directives,pipes,forms}' should be replaced with 'angular2/src/common/{directives,pipes,formis}'
Closes #5153
This commit is contained in:
@@ -0,0 +1,492 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
fakeAsync,
|
||||
flushMicrotasks,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
tick
|
||||
} from 'angular2/testing_internal';
|
||||
|
||||
import {SpyNgControl, SpyValueAccessor} from '../spies';
|
||||
|
||||
import {
|
||||
ControlGroup,
|
||||
Control,
|
||||
NgControlName,
|
||||
NgControlGroup,
|
||||
NgFormModel,
|
||||
ControlValueAccessor,
|
||||
Validators,
|
||||
NgForm,
|
||||
NgModel,
|
||||
NgFormControl,
|
||||
NgControl,
|
||||
DefaultValueAccessor,
|
||||
CheckboxControlValueAccessor,
|
||||
SelectControlValueAccessor,
|
||||
QueryList,
|
||||
Validator
|
||||
} from 'angular2/core';
|
||||
|
||||
|
||||
import {selectValueAccessor, composeValidators} from 'angular2/src/common/forms/directives/shared';
|
||||
import {TimerWrapper} from 'angular2/src/core/facade/async';
|
||||
import {PromiseWrapper} from 'angular2/src/core/facade/promise';
|
||||
import {SimpleChange} from 'angular2/src/core/change_detection';
|
||||
|
||||
class DummyControlValueAccessor implements ControlValueAccessor {
|
||||
writtenValue;
|
||||
|
||||
registerOnChange(fn) {}
|
||||
registerOnTouched(fn) {}
|
||||
|
||||
writeValue(obj: any): void { this.writtenValue = obj; }
|
||||
}
|
||||
|
||||
class CustomValidatorDirective implements Validator {
|
||||
validate(c: Control): {[key: string]: any} { return {"custom": true}; }
|
||||
}
|
||||
|
||||
function asyncValidator(expected, timeout = 0) {
|
||||
return (c) => {
|
||||
var completer = PromiseWrapper.completer();
|
||||
var res = c.value != expected ? {"async": true} : null;
|
||||
if (timeout == 0) {
|
||||
completer.resolve(res);
|
||||
} else {
|
||||
TimerWrapper.setTimeout(() => { completer.resolve(res); }, timeout);
|
||||
}
|
||||
return completer.promise;
|
||||
};
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe("Form Directives", () => {
|
||||
var defaultAccessor;
|
||||
|
||||
beforeEach(() => { defaultAccessor = new DefaultValueAccessor(null, null); });
|
||||
|
||||
describe("shared", () => {
|
||||
describe("selectValueAccessor", () => {
|
||||
var dir: NgControl;
|
||||
|
||||
beforeEach(() => { dir = <any>new SpyNgControl(); });
|
||||
|
||||
it("should throw when given an empty array",
|
||||
() => { expect(() => selectValueAccessor(dir, [])).toThrowError(); });
|
||||
|
||||
it("should return the default value accessor when no other provided",
|
||||
() => { expect(selectValueAccessor(dir, [defaultAccessor])).toEqual(defaultAccessor); });
|
||||
|
||||
it("should return checkbox accessor when provided", () => {
|
||||
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
||||
expect(selectValueAccessor(dir, [defaultAccessor, checkboxAccessor]))
|
||||
.toEqual(checkboxAccessor);
|
||||
});
|
||||
|
||||
it("should return select accessor when provided", () => {
|
||||
var selectAccessor = new SelectControlValueAccessor(null, null, new QueryList<any>());
|
||||
expect(selectValueAccessor(dir, [defaultAccessor, selectAccessor]))
|
||||
.toEqual(selectAccessor);
|
||||
});
|
||||
|
||||
it("should throw when more than one build-in accessor is provided", () => {
|
||||
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
||||
var selectAccessor = new SelectControlValueAccessor(null, null, new QueryList<any>());
|
||||
expect(() => selectValueAccessor(dir, [checkboxAccessor, selectAccessor])).toThrowError();
|
||||
});
|
||||
|
||||
it("should return custom accessor when provided", () => {
|
||||
var customAccessor = new SpyValueAccessor();
|
||||
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
|
||||
expect(selectValueAccessor(dir, [defaultAccessor, customAccessor, checkboxAccessor]))
|
||||
.toEqual(customAccessor);
|
||||
});
|
||||
|
||||
it("should throw when more than one custom accessor is provided", () => {
|
||||
var customAccessor: ControlValueAccessor = <any>new SpyValueAccessor();
|
||||
expect(() => selectValueAccessor(dir, [customAccessor, customAccessor])).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe("composeValidators", () => {
|
||||
it("should compose functions", () => {
|
||||
var dummy1 = (_) => ({"dummy1": true});
|
||||
var dummy2 = (_) => ({"dummy2": true});
|
||||
var v = composeValidators([dummy1, dummy2]);
|
||||
expect(v(new Control(""))).toEqual({"dummy1": true, "dummy2": true});
|
||||
});
|
||||
|
||||
it("should compose validator directives", () => {
|
||||
var dummy1 = (_) => ({"dummy1": true});
|
||||
var v = composeValidators([dummy1, new CustomValidatorDirective()]);
|
||||
expect(v(new Control(""))).toEqual({"dummy1": true, "custom": true});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgFormModel", () => {
|
||||
var form;
|
||||
var formModel;
|
||||
var loginControlDir;
|
||||
|
||||
beforeEach(() => {
|
||||
form = new NgFormModel([], []);
|
||||
formModel = new ControlGroup({
|
||||
"login": new Control(),
|
||||
"passwords":
|
||||
new ControlGroup({"password": new Control(), "passwordConfirm": new Control()})
|
||||
});
|
||||
form.form = formModel;
|
||||
|
||||
loginControlDir = new NgControlName(form, [Validators.required],
|
||||
[asyncValidator("expected")], [defaultAccessor]);
|
||||
loginControlDir.name = "login";
|
||||
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
|
||||
describe("addControl", () => {
|
||||
it("should throw when no control found", () => {
|
||||
var dir = new NgControlName(form, null, null, [defaultAccessor]);
|
||||
dir.name = "invalidName";
|
||||
|
||||
expect(() => form.addControl(dir))
|
||||
.toThrowError(new RegExp("Cannot find control 'invalidName'"));
|
||||
});
|
||||
|
||||
it("should throw when no value accessor", () => {
|
||||
var dir = new NgControlName(form, null, null, null);
|
||||
dir.name = "login";
|
||||
|
||||
expect(() => form.addControl(dir))
|
||||
.toThrowError(new RegExp("No value accessor for 'login'"));
|
||||
});
|
||||
|
||||
it("should set up validators", fakeAsync(() => {
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
// sync validators are set
|
||||
expect(formModel.hasError("required", ["login"])).toBe(true);
|
||||
expect(formModel.hasError("async", ["login"])).toBe(false);
|
||||
|
||||
formModel.find(["login"]).updateValue("invalid value");
|
||||
|
||||
// sync validator passes, running async validators
|
||||
expect(formModel.pending).toBe(true);
|
||||
|
||||
tick();
|
||||
|
||||
expect(formModel.hasError("required", ["login"])).toBe(false);
|
||||
expect(formModel.hasError("async", ["login"])).toBe(true);
|
||||
}));
|
||||
|
||||
it("should write value to the DOM", () => {
|
||||
formModel.find(["login"]).updateValue("initValue");
|
||||
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual("initValue");
|
||||
});
|
||||
|
||||
it("should add the directive to the list of directives included in the form", () => {
|
||||
form.addControl(loginControlDir);
|
||||
expect(form.directives).toEqual([loginControlDir]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("addControlGroup", () => {
|
||||
var matchingPasswordsValidator = (g) => {
|
||||
if (g.controls["password"].value != g.controls["passwordConfirm"].value) {
|
||||
return {"differentPasswords": true};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
it("should set up validator", fakeAsync(() => {
|
||||
var group = new NgControlGroup(form, [matchingPasswordsValidator],
|
||||
[asyncValidator('expected')]);
|
||||
group.name = "passwords";
|
||||
form.addControlGroup(group);
|
||||
|
||||
formModel.find(["passwords", "password"]).updateValue("somePassword");
|
||||
formModel.find(["passwords", "passwordConfirm"]).updateValue("someOtherPassword");
|
||||
|
||||
// sync validators are set
|
||||
expect(formModel.hasError("differentPasswords", ["passwords"])).toEqual(true);
|
||||
|
||||
formModel.find(["passwords", "passwordConfirm"]).updateValue("somePassword");
|
||||
|
||||
// sync validators pass, running async validators
|
||||
expect(formModel.pending).toBe(true);
|
||||
|
||||
tick();
|
||||
|
||||
expect(formModel.hasError("async", ["passwords"])).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
||||
describe("removeControl", () => {
|
||||
it("should remove the directive to the list of directives included in the form", () => {
|
||||
form.addControl(loginControlDir);
|
||||
form.removeControl(loginControlDir);
|
||||
expect(form.directives).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onChanges", () => {
|
||||
it("should update dom values of all the directives", () => {
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
formModel.find(["login"]).updateValue("new value");
|
||||
|
||||
form.onChanges({});
|
||||
|
||||
expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual("new value");
|
||||
});
|
||||
|
||||
it("should set up a sync validator", () => {
|
||||
var formValidator = (c) => ({"custom": true});
|
||||
var f = new NgFormModel([formValidator], []);
|
||||
f.form = formModel;
|
||||
f.onChanges({"form": formModel});
|
||||
|
||||
expect(formModel.errors).toEqual({"custom": true});
|
||||
});
|
||||
|
||||
it("should set up an async validator", fakeAsync(() => {
|
||||
var f = new NgFormModel([], [asyncValidator("expected")]);
|
||||
f.form = formModel;
|
||||
f.onChanges({"form": formModel});
|
||||
|
||||
tick();
|
||||
|
||||
expect(formModel.errors).toEqual({"async": true});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgForm", () => {
|
||||
var form;
|
||||
var formModel;
|
||||
var loginControlDir;
|
||||
var personControlGroupDir;
|
||||
|
||||
beforeEach(() => {
|
||||
form = new NgForm([], []);
|
||||
formModel = form.form;
|
||||
|
||||
personControlGroupDir = new NgControlGroup(form, [], []);
|
||||
personControlGroupDir.name = "person";
|
||||
|
||||
loginControlDir = new NgControlName(personControlGroupDir, null, null, [defaultAccessor]);
|
||||
loginControlDir.name = "login";
|
||||
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
|
||||
describe("addControl & addControlGroup", () => {
|
||||
it("should create a control with the given name", fakeAsync(() => {
|
||||
form.addControlGroup(personControlGroupDir);
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
flushMicrotasks();
|
||||
|
||||
expect(formModel.find(["person", "login"])).not.toBeNull;
|
||||
}));
|
||||
|
||||
// should update the form's value and validity
|
||||
});
|
||||
|
||||
describe("removeControl & removeControlGroup", () => {
|
||||
it("should remove control", fakeAsync(() => {
|
||||
form.addControlGroup(personControlGroupDir);
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
form.removeControlGroup(personControlGroupDir);
|
||||
form.removeControl(loginControlDir);
|
||||
|
||||
flushMicrotasks();
|
||||
|
||||
expect(formModel.find(["person"])).toBeNull();
|
||||
expect(formModel.find(["person", "login"])).toBeNull();
|
||||
}));
|
||||
|
||||
// should update the form's value and validity
|
||||
});
|
||||
|
||||
it("should set up sync validator", fakeAsync(() => {
|
||||
var formValidator = (c) => ({"custom": true});
|
||||
var f = new NgForm([formValidator], []);
|
||||
|
||||
tick();
|
||||
|
||||
expect(f.form.errors).toEqual({"custom": true});
|
||||
}));
|
||||
|
||||
it("should set up async validator", fakeAsync(() => {
|
||||
var f = new NgForm([], [asyncValidator("expected")]);
|
||||
|
||||
tick();
|
||||
|
||||
expect(f.form.errors).toEqual({"async": true});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("NgControlGroup", () => {
|
||||
var formModel;
|
||||
var controlGroupDir;
|
||||
|
||||
beforeEach(() => {
|
||||
formModel = new ControlGroup({"login": new Control(null)});
|
||||
|
||||
var parent = new NgFormModel([], []);
|
||||
parent.form = new ControlGroup({"group": formModel});
|
||||
controlGroupDir = new NgControlGroup(parent, [], []);
|
||||
controlGroupDir.name = "group";
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgFormControl", () => {
|
||||
var controlDir;
|
||||
var control;
|
||||
var checkProperties = function(control) {
|
||||
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);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
controlDir = new NgFormControl([Validators.required], [], [defaultAccessor]);
|
||||
controlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
|
||||
control = new Control(null);
|
||||
controlDir.form = control;
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => { checkProperties(control); });
|
||||
|
||||
it("should reexport new control properties", () => {
|
||||
var newControl = new Control(null);
|
||||
controlDir.form = newControl;
|
||||
controlDir.onChanges({"form": new SimpleChange(control, newControl)});
|
||||
|
||||
checkProperties(newControl);
|
||||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
expect(control.valid).toBe(true);
|
||||
|
||||
// this will add the required validator and recalculate the validity
|
||||
controlDir.onChanges({"form": new SimpleChange(null, control)});
|
||||
|
||||
expect(control.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgModel", () => {
|
||||
var ngModel;
|
||||
|
||||
beforeEach(() => {
|
||||
ngModel =
|
||||
new NgModel([Validators.required], [asyncValidator("expected")], [defaultAccessor]);
|
||||
ngModel.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
|
||||
it("should set up validator", fakeAsync(() => {
|
||||
// this will add the required validator and recalculate the validity
|
||||
ngModel.onChanges({});
|
||||
tick();
|
||||
|
||||
expect(ngModel.control.errors).toEqual({"required": true});
|
||||
|
||||
ngModel.control.updateValue("someValue");
|
||||
tick();
|
||||
|
||||
expect(ngModel.control.errors).toEqual({"async": true});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("NgControlName", () => {
|
||||
var formModel;
|
||||
var controlNameDir;
|
||||
|
||||
beforeEach(() => {
|
||||
formModel = new Control("name");
|
||||
|
||||
var parent = new NgFormModel([], []);
|
||||
parent.form = new ControlGroup({"name": formModel});
|
||||
controlNameDir = new NgControlName(parent, [], [], [defaultAccessor]);
|
||||
controlNameDir.name = "name";
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el
|
||||
} from 'angular2/testing_internal';
|
||||
import {Control, FormBuilder} from 'angular2/core';
|
||||
import {PromiseWrapper} from 'angular2/src/core/facade/promise';
|
||||
|
||||
export function main() {
|
||||
function syncValidator(_) { return null; }
|
||||
function asyncValidator(_) { return PromiseWrapper.resolve(null); }
|
||||
|
||||
describe("Form Builder", () => {
|
||||
var b;
|
||||
|
||||
beforeEach(() => { b = new FormBuilder(); });
|
||||
|
||||
it("should create controls from a value", () => {
|
||||
var g = b.group({"login": "some value"});
|
||||
|
||||
expect(g.controls["login"].value).toEqual("some value");
|
||||
});
|
||||
|
||||
it("should create controls from an array", () => {
|
||||
var g = b.group(
|
||||
{"login": ["some value"], "password": ["some value", syncValidator, asyncValidator]});
|
||||
|
||||
expect(g.controls["login"].value).toEqual("some value");
|
||||
expect(g.controls["password"].value).toEqual("some value");
|
||||
expect(g.controls["password"].validator).toEqual(syncValidator);
|
||||
expect(g.controls["password"].asyncValidator).toEqual(asyncValidator);
|
||||
});
|
||||
|
||||
it("should use controls", () => {
|
||||
var g = b.group({"login": b.control("some value", syncValidator, asyncValidator)});
|
||||
|
||||
expect(g.controls["login"].value).toEqual("some value");
|
||||
expect(g.controls["login"].validator).toBe(syncValidator);
|
||||
expect(g.controls["login"].asyncValidator).toBe(asyncValidator);
|
||||
});
|
||||
|
||||
it("should create groups with optional controls", () => {
|
||||
var g = b.group({"login": "some value"}, {"optionals": {"login": false}});
|
||||
|
||||
expect(g.contains("login")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should create groups with a custom validator", () => {
|
||||
var g = b.group({"login": "some value"},
|
||||
{"validator": syncValidator, "asyncValidator": asyncValidator});
|
||||
|
||||
expect(g.validator).toBe(syncValidator);
|
||||
expect(g.asyncValidator).toBe(asyncValidator);
|
||||
});
|
||||
|
||||
it("should create control arrays", () => {
|
||||
var c = b.control("three");
|
||||
var a = b.array(["one", ["two", syncValidator], c, b.array(['four'])], syncValidator,
|
||||
asyncValidator);
|
||||
|
||||
expect(a.value).toEqual(['one', 'two', 'three', ['four']]);
|
||||
expect(a.validator).toBe(syncValidator);
|
||||
expect(a.asyncValidator).toBe(asyncValidator);
|
||||
});
|
||||
});
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,823 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el,
|
||||
AsyncTestCompleter,
|
||||
fakeAsync,
|
||||
tick,
|
||||
inject
|
||||
} from 'angular2/testing_internal';
|
||||
import {ControlGroup, Control, ControlArray, Validators} from 'angular2/core';
|
||||
import {isPresent, CONST_EXPR} from 'angular2/src/core/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/core/facade/promise';
|
||||
import {TimerWrapper, ObservableWrapper} from 'angular2/src/core/facade/async';
|
||||
import {IS_DART} from 'angular2/src/core/facade/lang';
|
||||
|
||||
export function main() {
|
||||
function asyncValidator(expected, timeouts = CONST_EXPR({})) {
|
||||
return (c) => {
|
||||
var completer = PromiseWrapper.completer();
|
||||
var t = isPresent(timeouts[c.value]) ? timeouts[c.value] : 0;
|
||||
var res = c.value != expected ? {"async": true} : null;
|
||||
|
||||
if (t == 0) {
|
||||
completer.resolve(res);
|
||||
} else {
|
||||
TimerWrapper.setTimeout(() => { completer.resolve(res); }, t);
|
||||
}
|
||||
|
||||
return completer.promise;
|
||||
};
|
||||
}
|
||||
|
||||
describe("Form Model", () => {
|
||||
describe("Control", () => {
|
||||
it("should default the value to null", () => {
|
||||
var c = new Control();
|
||||
expect(c.value).toBe(null);
|
||||
});
|
||||
|
||||
describe("validator", () => {
|
||||
it("should run validator with the initial value", () => {
|
||||
var c = new Control("value", Validators.required);
|
||||
expect(c.valid).toEqual(true);
|
||||
});
|
||||
|
||||
it("should rerun the validator when the value changes", () => {
|
||||
var c = new Control("value", Validators.required);
|
||||
c.updateValue(null);
|
||||
expect(c.valid).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return errors", () => {
|
||||
var c = new Control(null, Validators.required);
|
||||
expect(c.errors).toEqual({"required": true});
|
||||
});
|
||||
});
|
||||
|
||||
describe("asyncValidator", () => {
|
||||
it("should run validator with the initial value", fakeAsync(() => {
|
||||
var c = new Control("value", null, asyncValidator("expected"));
|
||||
tick();
|
||||
|
||||
expect(c.valid).toEqual(false);
|
||||
expect(c.errors).toEqual({"async": true});
|
||||
}));
|
||||
|
||||
it("should rerun the validator when the value changes", fakeAsync(() => {
|
||||
var c = new Control("value", null, asyncValidator("expected"));
|
||||
|
||||
c.updateValue("expected");
|
||||
tick();
|
||||
|
||||
expect(c.valid).toEqual(true);
|
||||
}));
|
||||
|
||||
it("should run the async validator only when the sync validator passes", fakeAsync(() => {
|
||||
var c = new Control("", Validators.required, asyncValidator("expected"));
|
||||
tick();
|
||||
|
||||
expect(c.errors).toEqual({"required": true});
|
||||
|
||||
c.updateValue("some value");
|
||||
tick();
|
||||
|
||||
expect(c.errors).toEqual({"async": true});
|
||||
}));
|
||||
|
||||
it("should mark the control as pending while running the async validation",
|
||||
fakeAsync(() => {
|
||||
var c = new Control("", null, asyncValidator("expected"));
|
||||
|
||||
expect(c.pending).toEqual(true);
|
||||
|
||||
tick();
|
||||
|
||||
expect(c.pending).toEqual(false);
|
||||
}));
|
||||
|
||||
it("should only use the latest async validation run", fakeAsync(() => {
|
||||
var c =
|
||||
new Control("", null, asyncValidator("expected", {"long": 200, "expected": 100}));
|
||||
|
||||
c.updateValue("long");
|
||||
c.updateValue("expected");
|
||||
|
||||
tick(300);
|
||||
|
||||
expect(c.valid).toEqual(true);
|
||||
}));
|
||||
});
|
||||
|
||||
describe("dirty", () => {
|
||||
it("should be false after creating a control", () => {
|
||||
var c = new Control("value");
|
||||
expect(c.dirty).toEqual(false);
|
||||
});
|
||||
|
||||
it("should be true after changing the value of the control", () => {
|
||||
var c = new Control("value");
|
||||
c.markAsDirty();
|
||||
expect(c.dirty).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateValue", () => {
|
||||
var g, c;
|
||||
beforeEach(() => {
|
||||
c = new Control("oldValue");
|
||||
g = new ControlGroup({"one": c});
|
||||
});
|
||||
|
||||
it("should update the value of the control", () => {
|
||||
c.updateValue("newValue");
|
||||
expect(c.value).toEqual("newValue");
|
||||
});
|
||||
|
||||
it("should invoke onChanges if it is present", () => {
|
||||
var onChanges;
|
||||
c.registerOnChange((v) => onChanges = ["invoked", v]);
|
||||
|
||||
c.updateValue("newValue");
|
||||
|
||||
expect(onChanges).toEqual(["invoked", "newValue"]);
|
||||
});
|
||||
|
||||
it("should not invoke on change when explicitly specified", () => {
|
||||
var onChange = null;
|
||||
c.registerOnChange((v) => onChange = ["invoked", v]);
|
||||
|
||||
c.updateValue("newValue", {emitModelToViewChange: false});
|
||||
|
||||
expect(onChange).toBeNull();
|
||||
});
|
||||
|
||||
it("should update the parent", () => {
|
||||
c.updateValue("newValue");
|
||||
expect(g.value).toEqual({"one": "newValue"});
|
||||
});
|
||||
|
||||
it("should not update the parent when explicitly specified", () => {
|
||||
c.updateValue("newValue", {onlySelf: true});
|
||||
expect(g.value).toEqual({"one": "oldValue"});
|
||||
});
|
||||
|
||||
it("should fire an event", fakeAsync(() => {
|
||||
ObservableWrapper.subscribe(c.valueChanges,
|
||||
(value) => { expect(value).toEqual("newValue"); });
|
||||
|
||||
c.updateValue("newValue");
|
||||
tick();
|
||||
}));
|
||||
|
||||
it("should not fire an event when explicitly specified", fakeAsync(() => {
|
||||
ObservableWrapper.subscribe(c.valueChanges, (value) => { throw "Should not happen"; });
|
||||
|
||||
c.updateValue("newValue", {emitEvent: false});
|
||||
|
||||
tick();
|
||||
}));
|
||||
});
|
||||
|
||||
describe("valueChanges", () => {
|
||||
var c;
|
||||
|
||||
beforeEach(() => { c = new Control("old", Validators.required); });
|
||||
|
||||
it("should fire an event after the value has been updated",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
ObservableWrapper.subscribe(c.valueChanges, (value) => {
|
||||
expect(c.value).toEqual('new');
|
||||
expect(value).toEqual('new');
|
||||
async.done();
|
||||
});
|
||||
c.updateValue("new");
|
||||
}));
|
||||
|
||||
// TODO: remove the if statement after making observable delivery sync
|
||||
if (!IS_DART) {
|
||||
it("should update set errors and status before emitting an event",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
c.valueChanges.subscribe(value => {
|
||||
expect(c.valid).toEqual(false);
|
||||
expect(c.errors).toEqual({"required": true});
|
||||
async.done();
|
||||
});
|
||||
c.updateValue("");
|
||||
}));
|
||||
}
|
||||
|
||||
it("should return a cold observable", inject([AsyncTestCompleter], (async) => {
|
||||
c.updateValue("will be ignored");
|
||||
ObservableWrapper.subscribe(c.valueChanges, (value) => {
|
||||
expect(value).toEqual('new');
|
||||
async.done();
|
||||
});
|
||||
c.updateValue("new");
|
||||
}));
|
||||
});
|
||||
|
||||
describe("setErrors", () => {
|
||||
it("should set errors on a control", () => {
|
||||
var c = new Control("someValue");
|
||||
|
||||
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", () => {
|
||||
var c = new Control("someValue", Validators.required);
|
||||
|
||||
c.setErrors({"someError": true});
|
||||
c.updateValue("");
|
||||
|
||||
expect(c.errors).toEqual({"required": true});
|
||||
});
|
||||
|
||||
it("should update the parent group's validity", () => {
|
||||
var c = new Control("someValue");
|
||||
var g = new ControlGroup({"one": c});
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
|
||||
c.setErrors({"someError": true});
|
||||
|
||||
expect(g.controlsErrors).toEqual({"one": {"someError": true}});
|
||||
expect(g.valid).toEqual(false);
|
||||
});
|
||||
|
||||
it("should not reset parent's errors", () => {
|
||||
var c = new Control("someValue");
|
||||
var g = new ControlGroup({"one": c});
|
||||
|
||||
g.setErrors({"someGroupError": true});
|
||||
c.setErrors({"someError": true});
|
||||
|
||||
expect(g.errors).toEqual({"someGroupError": true});
|
||||
});
|
||||
|
||||
it("should reset errors when updating a value", () => {
|
||||
var c = new Control("oldValue");
|
||||
var g = new ControlGroup({"one": c});
|
||||
|
||||
g.setErrors({"someGroupError": true});
|
||||
c.setErrors({"someError": true});
|
||||
|
||||
c.updateValue("newValue");
|
||||
|
||||
expect(c.errors).toEqual(null);
|
||||
expect(g.errors).toEqual(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ControlGroup", () => {
|
||||
describe("value", () => {
|
||||
it("should be the reduced value of the child controls", () => {
|
||||
var g = new ControlGroup({"one": new Control("111"), "two": new Control("222")});
|
||||
expect(g.value).toEqual({"one": "111", "two": "222"});
|
||||
});
|
||||
|
||||
it("should be empty when there are no child controls", () => {
|
||||
var g = new ControlGroup({});
|
||||
expect(g.value).toEqual({});
|
||||
});
|
||||
|
||||
it("should support nested groups", () => {
|
||||
var g = new ControlGroup(
|
||||
{"one": new Control("111"), "nested": new ControlGroup({"two": new Control("222")})});
|
||||
expect(g.value).toEqual({"one": "111", "nested": {"two": "222"}});
|
||||
|
||||
(<Control>(g.controls["nested"].find("two"))).updateValue("333");
|
||||
|
||||
expect(g.value).toEqual({"one": "111", "nested": {"two": "333"}});
|
||||
});
|
||||
});
|
||||
|
||||
describe("controlsErrors", () => {
|
||||
it("should be null when no errors", () => {
|
||||
var g = new ControlGroup({"one": new Control('value', Validators.required)});
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
expect(g.controlsErrors).toEqual(null);
|
||||
});
|
||||
|
||||
it("should collect errors from the child controls", () => {
|
||||
var one = new Control(null, Validators.required);
|
||||
var g = new ControlGroup({"one": one});
|
||||
|
||||
expect(g.valid).toEqual(false);
|
||||
expect(g.controlsErrors).toEqual({"one": {"required": true}});
|
||||
});
|
||||
|
||||
it("should not include controls that have no errors", () => {
|
||||
var one = new Control(null, Validators.required);
|
||||
var two = new Control("two");
|
||||
var g = new ControlGroup({"one": one, "two": two});
|
||||
|
||||
expect(g.controlsErrors).toEqual({"one": {"required": true}});
|
||||
});
|
||||
|
||||
it("should run the validator with the value changes", () => {
|
||||
var c = new Control(null, Validators.required);
|
||||
var g = new ControlGroup({"one": c});
|
||||
|
||||
c.updateValue("some value");
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
expect(g.controlsErrors).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
it("should run the validator when the value changes", () => {
|
||||
var simpleValidator = (c) =>
|
||||
c.controls["one"].value != "correct" ? {"broken": true} : null;
|
||||
|
||||
var c = new Control(null);
|
||||
var g = new ControlGroup({"one": c}, null, simpleValidator);
|
||||
|
||||
c.updateValue("correct");
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
expect(g.errors).toEqual(null);
|
||||
|
||||
c.updateValue("incorrect");
|
||||
|
||||
expect(g.valid).toEqual(false);
|
||||
expect(g.errors).toEqual({"broken": true});
|
||||
});
|
||||
});
|
||||
|
||||
describe("dirty", () => {
|
||||
var c, g;
|
||||
|
||||
beforeEach(() => {
|
||||
c = new Control('value');
|
||||
g = new ControlGroup({"one": c});
|
||||
});
|
||||
|
||||
it("should be false after creating a control", () => { expect(g.dirty).toEqual(false); });
|
||||
|
||||
it("should be false after changing the value of the control", () => {
|
||||
c.markAsDirty();
|
||||
|
||||
expect(g.dirty).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("optional components", () => {
|
||||
describe("contains", () => {
|
||||
var group;
|
||||
|
||||
beforeEach(() => {
|
||||
group = new ControlGroup(
|
||||
{
|
||||
"required": new Control("requiredValue"),
|
||||
"optional": new Control("optionalValue")
|
||||
},
|
||||
{"optional": false});
|
||||
});
|
||||
|
||||
// rename contains into has
|
||||
it("should return false when the component is not included",
|
||||
() => { expect(group.contains("optional")).toEqual(false); })
|
||||
|
||||
it("should return false when there is no component with the given name",
|
||||
() => { expect(group.contains("something else")).toEqual(false); });
|
||||
|
||||
it("should return true when the component is included", () => {
|
||||
expect(group.contains("required")).toEqual(true);
|
||||
|
||||
group.include("optional");
|
||||
|
||||
expect(group.contains("optional")).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not include an inactive component into the group value", () => {
|
||||
var group = new ControlGroup(
|
||||
{"required": new Control("requiredValue"), "optional": new Control("optionalValue")},
|
||||
{"optional": false});
|
||||
|
||||
expect(group.value).toEqual({"required": "requiredValue"});
|
||||
|
||||
group.include("optional");
|
||||
|
||||
expect(group.value).toEqual({"required": "requiredValue", "optional": "optionalValue"});
|
||||
});
|
||||
|
||||
it("should not run Validators on an inactive component", () => {
|
||||
var group = new ControlGroup(
|
||||
{
|
||||
"required": new Control("requiredValue", Validators.required),
|
||||
"optional": new Control("", Validators.required)
|
||||
},
|
||||
{"optional": false});
|
||||
|
||||
expect(group.valid).toEqual(true);
|
||||
|
||||
group.include("optional");
|
||||
|
||||
expect(group.valid).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("valueChanges", () => {
|
||||
var g, c1, c2;
|
||||
|
||||
beforeEach(() => {
|
||||
c1 = new Control("old1");
|
||||
c2 = new Control("old2");
|
||||
g = new ControlGroup({"one": c1, "two": c2}, {"two": true});
|
||||
});
|
||||
|
||||
it("should fire an event after the value has been updated",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
ObservableWrapper.subscribe(g.valueChanges, (value) => {
|
||||
expect(g.value).toEqual({'one': 'new1', 'two': 'old2'});
|
||||
expect(value).toEqual({'one': 'new1', 'two': 'old2'});
|
||||
async.done();
|
||||
});
|
||||
c1.updateValue("new1");
|
||||
}));
|
||||
|
||||
it("should fire an event after the control's observable fired an event",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var controlCallbackIsCalled = false;
|
||||
|
||||
ObservableWrapper.subscribe(c1.valueChanges,
|
||||
(value) => { controlCallbackIsCalled = true; });
|
||||
|
||||
ObservableWrapper.subscribe(g.valueChanges, (value) => {
|
||||
expect(controlCallbackIsCalled).toBe(true);
|
||||
async.done();
|
||||
});
|
||||
|
||||
c1.updateValue("new1");
|
||||
}));
|
||||
|
||||
it("should fire an event when a control is excluded",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
ObservableWrapper.subscribe(g.valueChanges, (value) => {
|
||||
expect(value).toEqual({'one': 'old1'});
|
||||
async.done();
|
||||
});
|
||||
|
||||
g.exclude("two");
|
||||
}));
|
||||
|
||||
it("should fire an event when a control is included",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
g.exclude("two");
|
||||
|
||||
ObservableWrapper.subscribe(g.valueChanges, (value) => {
|
||||
expect(value).toEqual({'one': 'old1', 'two': 'old2'});
|
||||
async.done();
|
||||
});
|
||||
|
||||
g.include("two");
|
||||
}));
|
||||
|
||||
it("should fire an event every time a control is updated",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var loggedValues = [];
|
||||
|
||||
ObservableWrapper.subscribe(g.valueChanges, (value) => {
|
||||
loggedValues.push(value);
|
||||
|
||||
if (loggedValues.length == 2) {
|
||||
expect(loggedValues)
|
||||
.toEqual([{"one": "new1", "two": "old2"}, {"one": "new1", "two": "new2"}]);
|
||||
async.done();
|
||||
}
|
||||
});
|
||||
|
||||
c1.updateValue("new1");
|
||||
c2.updateValue("new2");
|
||||
}));
|
||||
|
||||
xit("should not fire an event when an excluded control is updated",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
// hard to test without hacking zones
|
||||
}));
|
||||
});
|
||||
|
||||
describe("getError", () => {
|
||||
it("should return the error when it is present", () => {
|
||||
var c = new Control("", Validators.required);
|
||||
var g = new ControlGroup({"one": c});
|
||||
expect(c.getError("required")).toEqual(true);
|
||||
expect(g.getError("required", ["one"])).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return null otherwise", () => {
|
||||
var c = new Control("not empty", Validators.required);
|
||||
var g = new ControlGroup({"one": c});
|
||||
expect(c.getError("invalid")).toEqual(null);
|
||||
expect(g.getError("required", ["one"])).toEqual(null);
|
||||
expect(g.getError("required", ["invalid"])).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("asyncValidator", () => {
|
||||
it("should run the async validator", fakeAsync(() => {
|
||||
var c = new Control("value");
|
||||
var g = new ControlGroup({"one": c}, null, null, asyncValidator("expected"));
|
||||
|
||||
expect(g.pending).toEqual(true);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(g.errors).toEqual({"async": true});
|
||||
expect(g.pending).toEqual(false);
|
||||
}));
|
||||
|
||||
it("should set the parent group's status to pending", fakeAsync(() => {
|
||||
var c = new Control("value", null, asyncValidator("expected"));
|
||||
var g = new ControlGroup({"one": c});
|
||||
|
||||
expect(g.pending).toEqual(true);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(g.pending).toEqual(false);
|
||||
}));
|
||||
|
||||
it("should run the parent group's async validator when children are pending",
|
||||
fakeAsync(() => {
|
||||
var c = new Control("value", null, asyncValidator("expected"));
|
||||
var g = new ControlGroup({"one": c}, null, null, asyncValidator("expected"));
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(g.errors).toEqual({"async": true});
|
||||
expect(g.find(["one"]).errors).toEqual({"async": true});
|
||||
}));
|
||||
})
|
||||
});
|
||||
|
||||
describe("ControlArray", () => {
|
||||
describe("adding/removing", () => {
|
||||
var a: ControlArray;
|
||||
var c1, c2, c3;
|
||||
|
||||
beforeEach(() => {
|
||||
a = new ControlArray([]);
|
||||
c1 = new Control(1);
|
||||
c2 = new Control(2);
|
||||
c3 = new Control(3);
|
||||
});
|
||||
|
||||
it("should support pushing", () => {
|
||||
a.push(c1);
|
||||
expect(a.length).toEqual(1);
|
||||
expect(a.controls).toEqual([c1]);
|
||||
});
|
||||
|
||||
it("should support removing", () => {
|
||||
a.push(c1);
|
||||
a.push(c2);
|
||||
a.push(c3);
|
||||
|
||||
a.removeAt(1);
|
||||
|
||||
expect(a.controls).toEqual([c1, c3]);
|
||||
});
|
||||
|
||||
it("should support inserting", () => {
|
||||
a.push(c1);
|
||||
a.push(c3);
|
||||
|
||||
a.insert(1, c2);
|
||||
|
||||
expect(a.controls).toEqual([c1, c2, c3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("value", () => {
|
||||
it("should be the reduced value of the child controls", () => {
|
||||
var a = new ControlArray([new Control(1), new Control(2)]);
|
||||
expect(a.value).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it("should be an empty array when there are no child controls", () => {
|
||||
var a = new ControlArray([]);
|
||||
expect(a.value).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("controlsErrors", () => {
|
||||
it("should return null when no errors", () => {
|
||||
var a = new ControlArray(
|
||||
[new Control(1, Validators.required), new Control(2, Validators.required)]);
|
||||
|
||||
expect(a.valid).toBe(true);
|
||||
expect(a.controlsErrors).toBe(null);
|
||||
});
|
||||
|
||||
it("should collect errors from the child controls", () => {
|
||||
var a = new ControlArray([
|
||||
new Control(1, Validators.required),
|
||||
new Control(null, Validators.required),
|
||||
new Control(2, Validators.required)
|
||||
]);
|
||||
|
||||
expect(a.valid).toBe(false);
|
||||
expect(a.controlsErrors).toEqual([null, {"required": true}, null]);
|
||||
});
|
||||
|
||||
it("should run the validator when the value changes", () => {
|
||||
var a = new ControlArray([]);
|
||||
var c = new Control(null, Validators.required);
|
||||
a.push(c);
|
||||
expect(a.valid).toBe(false);
|
||||
|
||||
c.updateValue("some value");
|
||||
|
||||
expect(a.valid).toBe(true);
|
||||
expect(a.controlsErrors).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
it("should run the validator when the value changes", () => {
|
||||
var simpleValidator = (c) => c.controls[0].value != "correct" ? {"broken": true} : null;
|
||||
|
||||
var c = new Control(null);
|
||||
var g = new ControlArray([c], simpleValidator);
|
||||
|
||||
c.updateValue("correct");
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
expect(g.errors).toEqual(null);
|
||||
|
||||
c.updateValue("incorrect");
|
||||
|
||||
expect(g.valid).toEqual(false);
|
||||
expect(g.errors).toEqual({"broken": true});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("dirty", () => {
|
||||
var c: Control;
|
||||
var a: ControlArray;
|
||||
|
||||
beforeEach(() => {
|
||||
c = new Control('value');
|
||||
a = new ControlArray([c]);
|
||||
});
|
||||
|
||||
it("should be false after creating a control", () => { expect(a.dirty).toEqual(false); });
|
||||
|
||||
it("should be false after changing the value of the control", () => {
|
||||
c.markAsDirty();
|
||||
|
||||
expect(a.dirty).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pending", () => {
|
||||
var c: Control;
|
||||
var a: ControlArray;
|
||||
|
||||
beforeEach(() => {
|
||||
c = new Control('value');
|
||||
a = new ControlArray([c]);
|
||||
});
|
||||
|
||||
it("should be false after creating a control", () => {
|
||||
expect(c.pending).toEqual(false);
|
||||
expect(a.pending).toEqual(false);
|
||||
});
|
||||
|
||||
it("should be true after changing the value of the control", () => {
|
||||
c.markAsPending();
|
||||
|
||||
expect(c.pending).toEqual(true);
|
||||
expect(a.pending).toEqual(true);
|
||||
});
|
||||
|
||||
it("should not update the parent when onlySelf = true", () => {
|
||||
c.markAsPending({onlySelf: true});
|
||||
|
||||
expect(c.pending).toEqual(true);
|
||||
expect(a.pending).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("valueChanges", () => {
|
||||
var a: ControlArray;
|
||||
var c1, c2;
|
||||
|
||||
beforeEach(() => {
|
||||
c1 = new Control("old1");
|
||||
c2 = new Control("old2");
|
||||
a = new ControlArray([c1, c2]);
|
||||
});
|
||||
|
||||
it("should fire an event after the value has been updated",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
ObservableWrapper.subscribe(a.valueChanges, (value) => {
|
||||
expect(a.value).toEqual(['new1', 'old2']);
|
||||
expect(value).toEqual(['new1', 'old2']);
|
||||
async.done();
|
||||
});
|
||||
c1.updateValue("new1");
|
||||
}));
|
||||
|
||||
it("should fire an event after the control's observable fired an event",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
var controlCallbackIsCalled = false;
|
||||
|
||||
ObservableWrapper.subscribe(c1.valueChanges,
|
||||
(value) => { controlCallbackIsCalled = true; });
|
||||
|
||||
ObservableWrapper.subscribe(a.valueChanges, (value) => {
|
||||
expect(controlCallbackIsCalled).toBe(true);
|
||||
async.done();
|
||||
});
|
||||
|
||||
c1.updateValue("new1");
|
||||
}));
|
||||
|
||||
it("should fire an event when a control is removed",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
ObservableWrapper.subscribe(a.valueChanges, (value) => {
|
||||
expect(value).toEqual(['old1']);
|
||||
async.done();
|
||||
});
|
||||
|
||||
a.removeAt(1);
|
||||
}));
|
||||
|
||||
it("should fire an event when a control is added", inject([AsyncTestCompleter], (async) => {
|
||||
a.removeAt(1);
|
||||
|
||||
ObservableWrapper.subscribe(a.valueChanges, (value) => {
|
||||
expect(value).toEqual(['old1', 'old2']);
|
||||
async.done();
|
||||
});
|
||||
|
||||
a.push(c2);
|
||||
}));
|
||||
});
|
||||
|
||||
describe("find", () => {
|
||||
it("should return null when path is null", () => {
|
||||
var g = new ControlGroup({});
|
||||
expect(g.find(null)).toEqual(null);
|
||||
});
|
||||
|
||||
it("should return null when path is empty", () => {
|
||||
var g = new ControlGroup({});
|
||||
expect(g.find([])).toEqual(null);
|
||||
});
|
||||
|
||||
it("should return null when path is invalid", () => {
|
||||
var g = new ControlGroup({});
|
||||
expect(g.find(["one", "two"])).toEqual(null);
|
||||
});
|
||||
|
||||
it("should return a child of a control group", () => {
|
||||
var g = new ControlGroup(
|
||||
{"one": new Control("111"), "nested": new ControlGroup({"two": new Control("222")})});
|
||||
|
||||
expect(g.find(["nested", "two"]).value).toEqual("222");
|
||||
expect(g.find(["one"]).value).toEqual("111");
|
||||
expect(g.find("nested/two").value).toEqual("222");
|
||||
expect(g.find("one").value).toEqual("111");
|
||||
});
|
||||
|
||||
it("should return an element of an array", () => {
|
||||
var g = new ControlGroup({"array": new ControlArray([new Control("111")])});
|
||||
|
||||
expect(g.find(["array", 0]).value).toEqual("111");
|
||||
});
|
||||
});
|
||||
|
||||
describe("asyncValidator", () => {
|
||||
it("should run the async validator", fakeAsync(() => {
|
||||
var c = new Control("value");
|
||||
var g = new ControlArray([c], null, asyncValidator("expected"));
|
||||
|
||||
expect(g.pending).toEqual(true);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(g.errors).toEqual({"async": true});
|
||||
expect(g.pending).toEqual(false);
|
||||
}));
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
fakeAsync,
|
||||
tick,
|
||||
el
|
||||
} from 'angular2/testing_internal';
|
||||
import {ControlGroup, Control, Validators, AbstractControl, ControlArray} from 'angular2/core';
|
||||
import {PromiseWrapper} from 'angular2/src/core/facade/promise';
|
||||
import {TimerWrapper} from 'angular2/src/core/facade/async';
|
||||
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
|
||||
|
||||
export function main() {
|
||||
function validator(key: string, error: any) {
|
||||
return function(c: AbstractControl) {
|
||||
var r = {};
|
||||
r[key] = error;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
describe("Validators", () => {
|
||||
describe("required", () => {
|
||||
it("should error on an empty string",
|
||||
() => { expect(Validators.required(new Control(""))).toEqual({"required": true}); });
|
||||
|
||||
it("should error on null",
|
||||
() => { expect(Validators.required(new Control(null))).toEqual({"required": true}); });
|
||||
|
||||
it("should not error on a non-empty string",
|
||||
() => { expect(Validators.required(new Control("not empty"))).toEqual(null); });
|
||||
});
|
||||
|
||||
describe("minLength", () => {
|
||||
it("should not error on an empty string",
|
||||
() => { expect(Validators.minLength(2)(new Control(""))).toEqual(null); });
|
||||
|
||||
it("should not error on null",
|
||||
() => { expect(Validators.minLength(2)(new Control(null))).toEqual(null); });
|
||||
|
||||
it("should not error on valid strings",
|
||||
() => { expect(Validators.minLength(2)(new Control("aa"))).toEqual(null); });
|
||||
|
||||
it("should error on short strings", () => {
|
||||
expect(Validators.minLength(2)(new Control("a")))
|
||||
.toEqual({"minlength": {"requiredLength": 2, "actualLength": 1}});
|
||||
});
|
||||
});
|
||||
|
||||
describe("maxLength", () => {
|
||||
it("should not error on an empty string",
|
||||
() => { expect(Validators.maxLength(2)(new Control(""))).toEqual(null); });
|
||||
|
||||
it("should not error on null",
|
||||
() => { expect(Validators.maxLength(2)(new Control(null))).toEqual(null); });
|
||||
|
||||
it("should not error on valid strings",
|
||||
() => { expect(Validators.maxLength(2)(new Control("aa"))).toEqual(null); });
|
||||
|
||||
it("should error on short strings", () => {
|
||||
expect(Validators.maxLength(2)(new Control("aaa")))
|
||||
.toEqual({"maxlength": {"requiredLength": 2, "actualLength": 3}});
|
||||
});
|
||||
});
|
||||
|
||||
describe("compose", () => {
|
||||
it("should return null when given null",
|
||||
() => { expect(Validators.compose(null)).toBe(null); });
|
||||
|
||||
it("should collect errors from all the validators", () => {
|
||||
var c = Validators.compose([validator("a", true), validator("b", true)]);
|
||||
expect(c(new Control(""))).toEqual({"a": true, "b": true});
|
||||
});
|
||||
|
||||
it("should run validators left to right", () => {
|
||||
var c = Validators.compose([validator("a", 1), validator("a", 2)]);
|
||||
expect(c(new Control(""))).toEqual({"a": 2});
|
||||
});
|
||||
|
||||
it("should return null when no errors", () => {
|
||||
var c = Validators.compose([Validators.nullValidator, Validators.nullValidator]);
|
||||
expect(c(new Control(""))).toEqual(null);
|
||||
});
|
||||
|
||||
it("should ignore nulls", () => {
|
||||
var c = Validators.compose([null, Validators.required]);
|
||||
expect(c(new Control(""))).toEqual({"required": true});
|
||||
});
|
||||
});
|
||||
|
||||
describe("composeAsync", () => {
|
||||
function asyncValidator(expected, response, timeout = 0) {
|
||||
return (c) => {
|
||||
var completer = PromiseWrapper.completer();
|
||||
var res = c.value != expected ? response : null;
|
||||
TimerWrapper.setTimeout(() => { completer.resolve(res); }, timeout);
|
||||
return completer.promise;
|
||||
};
|
||||
}
|
||||
|
||||
it("should return null when given null",
|
||||
() => { expect(Validators.composeAsync(null)).toEqual(null); });
|
||||
|
||||
it("should collect errors from all the validators", fakeAsync(() => {
|
||||
var c = Validators.composeAsync([
|
||||
asyncValidator("expected", {"one": true}),
|
||||
asyncValidator("expected", {"two": true})
|
||||
]);
|
||||
|
||||
var value = null;
|
||||
c(new Control("invalid")).then(v => value = v);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(value).toEqual({"one": true, "two": true});
|
||||
}));
|
||||
|
||||
it("should return null when no errors", fakeAsync(() => {
|
||||
var c = Validators.composeAsync([asyncValidator("expected", {"one": true})]);
|
||||
|
||||
var value = null;
|
||||
c(new Control("expected")).then(v => value = v);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(value).toEqual(null);
|
||||
}));
|
||||
|
||||
it("should ignore nulls", fakeAsync(() => {
|
||||
var c = Validators.composeAsync([asyncValidator("expected", {"one": true}), null]);
|
||||
|
||||
var value = null;
|
||||
c(new Control("invalid")).then(v => value = v);
|
||||
|
||||
tick(1);
|
||||
|
||||
expect(value).toEqual({"one": true});
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user