refactor(core): move more modules into core
This commit is contained in:
308
modules/angular2/test/core/forms/directives_spec.ts
Normal file
308
modules/angular2/test/core/forms/directives_spec.ts
Normal file
@ -0,0 +1,308 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
fakeAsync,
|
||||
flushMicrotasks,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el,
|
||||
AsyncTestCompleter,
|
||||
inject
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
ControlGroup,
|
||||
Control,
|
||||
NgControlName,
|
||||
NgControlGroup,
|
||||
NgFormModel,
|
||||
ControlValueAccessor,
|
||||
Validators,
|
||||
NgForm,
|
||||
NgModel,
|
||||
NgFormControl,
|
||||
DefaultValidators
|
||||
} from 'angular2/forms';
|
||||
|
||||
class DummyControlValueAccessor implements ControlValueAccessor {
|
||||
writtenValue;
|
||||
|
||||
registerOnChange(fn) {}
|
||||
registerOnTouched(fn) {}
|
||||
|
||||
writeValue(obj: any): void { this.writtenValue = obj; }
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe("Form Directives", () => {
|
||||
describe("NgFormModel", () => {
|
||||
var form;
|
||||
var formModel;
|
||||
var loginControlDir;
|
||||
|
||||
beforeEach(() => {
|
||||
form = new NgFormModel();
|
||||
formModel = new ControlGroup({"login": new Control(null)});
|
||||
form.form = formModel;
|
||||
|
||||
loginControlDir = new NgControlName(form, []);
|
||||
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);
|
||||
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);
|
||||
dir.name = "login";
|
||||
|
||||
expect(() => form.addControl(dir))
|
||||
.toThrowError(new RegExp("No value accessor for 'login'"));
|
||||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
loginControlDir.validators = [Validators.required];
|
||||
|
||||
expect(formModel.find(["login"]).valid).toBe(true);
|
||||
|
||||
// this will add the required validator and recalculate the validity
|
||||
form.addControl(loginControlDir);
|
||||
|
||||
expect(formModel.find(["login"]).valid).toBe(false);
|
||||
});
|
||||
|
||||
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("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(null);
|
||||
|
||||
expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual("new value");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
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
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
beforeEach(() => {
|
||||
controlDir = new NgFormControl([]);
|
||||
controlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
|
||||
control = new Control(null);
|
||||
controlDir.form = control;
|
||||
});
|
||||
|
||||
it("should reexport control properties", () => {
|
||||
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);
|
||||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
controlDir.validators = [Validators.required];
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
|
||||
// this will add the required validator and recalculate the validity
|
||||
controlDir.onChanges({});
|
||||
|
||||
expect(control.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgModel", () => {
|
||||
var ngModel;
|
||||
|
||||
beforeEach(() => {
|
||||
ngModel = new NgModel([]);
|
||||
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", () => {
|
||||
ngModel.validators = [Validators.required];
|
||||
|
||||
expect(ngModel.control.valid).toBe(true);
|
||||
|
||||
// this will add the required validator and recalculate the validity
|
||||
ngModel.onChanges({});
|
||||
|
||||
expect(ngModel.control.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
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, []);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
66
modules/angular2/test/core/forms/form_builder_spec.ts
Normal file
66
modules/angular2/test/core/forms/form_builder_spec.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el
|
||||
} from 'angular2/test_lib';
|
||||
import {Control, FormBuilder, Validators} from 'angular2/forms';
|
||||
|
||||
export function main() {
|
||||
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", Validators.required]});
|
||||
|
||||
expect(g.controls["login"].value).toEqual("some value");
|
||||
expect(g.controls["password"].value).toEqual("some value");
|
||||
expect(g.controls["password"].validator).toEqual(Validators.required);
|
||||
});
|
||||
|
||||
it("should use controls", () => {
|
||||
var g = b.group({"login": b.control("some value", Validators.required)});
|
||||
|
||||
expect(g.controls["login"].value).toEqual("some value");
|
||||
expect(g.controls["login"].validator).toBe(Validators.required);
|
||||
});
|
||||
|
||||
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": Validators.nullValidator});
|
||||
|
||||
expect(g.validator).toBe(Validators.nullValidator);
|
||||
});
|
||||
|
||||
it("should use default validators when no validators are provided", () => {
|
||||
var g = b.group({"login": "some value"});
|
||||
expect(g.controls["login"].validator).toBe(Validators.nullValidator);
|
||||
expect(g.validator).toBe(Validators.group);
|
||||
});
|
||||
|
||||
it("should create control arrays", () => {
|
||||
var c = b.control("three");
|
||||
var a = b.array(["one", ["two", Validators.required], c, b.array(['four'])]);
|
||||
|
||||
expect(a.value).toEqual(['one', 'two', 'three', ['four']]);
|
||||
});
|
||||
});
|
||||
}
|
787
modules/angular2/test/core/forms/integration_spec.ts
Normal file
787
modules/angular2/test/core/forms/integration_spec.ts
Normal file
@ -0,0 +1,787 @@
|
||||
import {Component, Directive, View} from 'angular2/angular2';
|
||||
import {
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
TestComponentBuilder,
|
||||
By,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
dispatchEvent,
|
||||
fakeAsync,
|
||||
tick,
|
||||
expect,
|
||||
it,
|
||||
inject,
|
||||
iit,
|
||||
xit,
|
||||
browserDetection
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {NgIf, NgFor} from 'angular2/directives';
|
||||
|
||||
import {
|
||||
Control,
|
||||
ControlGroup,
|
||||
NgForm,
|
||||
FORM_DIRECTIVES,
|
||||
Validators,
|
||||
NgControl,
|
||||
ControlValueAccessor
|
||||
} from 'angular2/forms';
|
||||
|
||||
export function main() {
|
||||
describe("integration tests", () => {
|
||||
it("should initialize DOM elements with the given form object",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"login": new Control("loginValue")});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("loginValue");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should update the control group values on DOM change",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form = new ControlGroup({"login": new Control("oldValue")});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
var input = rootTC.query(By.css("input"));
|
||||
|
||||
input.nativeElement.value = "updatedValue";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(form.value).toEqual({"login": "updatedValue"});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should emit ng-submit event on submit",
|
||||
inject(
|
||||
[TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t =
|
||||
`<div><form [ng-form-model]="form" (ng-submit)="name='updated'"></form><span>{{name}}</span></div>`;
|
||||
|
||||
var rootTC;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((root) => { rootTC = root; });
|
||||
tick();
|
||||
|
||||
rootTC.componentInstance.form = new ControlGroup({});
|
||||
rootTC.componentInstance.name = 'old';
|
||||
|
||||
tick();
|
||||
|
||||
var form = rootTC.query(By.css("form"));
|
||||
dispatchEvent(form.nativeElement, "submit");
|
||||
|
||||
tick();
|
||||
expect(rootTC.componentInstance.name).toEqual('updated');
|
||||
})));
|
||||
|
||||
it("should work with single controls",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var control = new Control("loginValue");
|
||||
|
||||
var t = `<div><input type="text" [ng-form-control]="form"></div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = control;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("loginValue");
|
||||
|
||||
input.nativeElement.value = "updatedValue";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(control.value).toEqual("updatedValue");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should update DOM elements when rebinding the control group",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"login": new Control("oldValue")});
|
||||
rootTC.detectChanges();
|
||||
|
||||
rootTC.componentInstance.form = new ControlGroup({"login": new Control("newValue")});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("newValue");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should update DOM elements when updating the value of a control",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var login = new Control("oldValue");
|
||||
var form = new ControlGroup({"login": login});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
login.updateValue("newValue");
|
||||
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("newValue");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should mark controls as touched after interacting with the DOM control",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var login = new Control("oldValue");
|
||||
var form = new ControlGroup({"login": login});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var loginEl = rootTC.query(By.css("input"));
|
||||
expect(login.touched).toBe(false);
|
||||
|
||||
dispatchEvent(loginEl.nativeElement, "blur");
|
||||
|
||||
expect(login.touched).toBe(true);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
describe("different control types", () => {
|
||||
it("should support <input type=text>",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="text">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"text": new Control("old")});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("old");
|
||||
|
||||
input.nativeElement.value = "new";
|
||||
dispatchEvent(input.nativeElement, "input");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"text": "new"});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support <input> without type",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input ng-control="text">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"text": new Control("old")});
|
||||
rootTC.detectChanges();
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("old");
|
||||
|
||||
input.nativeElement.value = "new";
|
||||
dispatchEvent(input.nativeElement, "input");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"text": "new"});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support <textarea>",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<textarea ng-control="text"></textarea>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"text": new Control('old')});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var textarea = rootTC.query(By.css("textarea"));
|
||||
expect(textarea.nativeElement.value).toEqual("old");
|
||||
|
||||
textarea.nativeElement.value = "new";
|
||||
dispatchEvent(textarea.nativeElement, "input");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"text": 'new'});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support <type=checkbox>",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="checkbox" ng-control="checkbox">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"checkbox": new Control(true)});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.checked).toBe(true);
|
||||
|
||||
input.nativeElement.checked = false;
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"checkbox": false});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support <select>",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<select ng-control="city">
|
||||
<option value="SF"></option>
|
||||
<option value="NYC"></option>
|
||||
</select>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"city": new Control("SF")});
|
||||
rootTC.detectChanges();
|
||||
|
||||
var select = rootTC.query(By.css("select"));
|
||||
var sfOption = rootTC.query(By.css("option"));
|
||||
expect(select.nativeElement.value).toEqual('SF');
|
||||
expect(sfOption.nativeElement.selected).toBe(true);
|
||||
|
||||
select.nativeElement.value = 'NYC';
|
||||
dispatchEvent(select.nativeElement, "change");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"city": 'NYC'});
|
||||
expect(sfOption.nativeElement.selected).toBe(false);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support <select> with a dynamic list of options",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<select ng-control="city">
|
||||
<option *ng-for="#c of data" [value]="c"></option>
|
||||
</select>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"city": new Control("NYC")});
|
||||
rootTC.componentInstance.data = ['SF', 'NYC'];
|
||||
rootTC.detectChanges();
|
||||
|
||||
var select = rootTC.query(By.css('select'));
|
||||
expect(select.nativeElement.value).toEqual('NYC');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support custom value accessors",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="name" wrapped-value>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = new ControlGroup({"name": new Control("aa")});
|
||||
rootTC.detectChanges();
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("!aa!");
|
||||
|
||||
input.nativeElement.value = "!bb!";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(rootTC.componentInstance.form.value).toEqual({"name": "bb"});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("validations", () => {
|
||||
it("should use validators defined in html",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form = new ControlGroup({"login": new Control("aa")});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login" required>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
expect(form.valid).toEqual(true);
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
|
||||
input.nativeElement.value = "";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(form.valid).toEqual(false);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should use validators defined in the model",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form = new ControlGroup({"login": new Control("aa", Validators.required)});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<input type="text" ng-control="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
expect(form.valid).toEqual(true);
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
|
||||
input.nativeElement.value = "";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(form.valid).toEqual(false);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("nested forms", () => {
|
||||
it("should init DOM with the given form object",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form =
|
||||
new ControlGroup({"nested": new ControlGroup({"login": new Control("value")})});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<div ng-control-group="nested">
|
||||
<input type="text" ng-control="login">
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input"));
|
||||
expect(input.nativeElement.value).toEqual("value");
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should update the control group values on DOM change",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form =
|
||||
new ControlGroup({"nested": new ControlGroup({"login": new Control("value")})});
|
||||
|
||||
var t = `<div [ng-form-model]="form">
|
||||
<div ng-control-group="nested">
|
||||
<input type="text" ng-control="login">
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
var input = rootTC.query(By.css("input"));
|
||||
|
||||
input.nativeElement.value = "updatedValue";
|
||||
dispatchEvent(input.nativeElement, "change");
|
||||
|
||||
expect(form.value).toEqual({"nested": {"login": "updatedValue"}});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it("should support ng-model for complex forms",
|
||||
inject(
|
||||
[TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var form = new ControlGroup({"name": new Control("")});
|
||||
|
||||
var t =
|
||||
`<div [ng-form-model]="form"><input type="text" ng-control="name" [(ng-model)]="name"></div>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((root) => { rootTC = root; });
|
||||
tick();
|
||||
|
||||
rootTC.componentInstance.name = 'oldValue';
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(input.value).toEqual("oldValue");
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
|
||||
tick();
|
||||
expect(rootTC.componentInstance.name).toEqual("updatedValue");
|
||||
})));
|
||||
|
||||
it("should support ng-model for single fields",
|
||||
inject(
|
||||
[TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var form = new Control("");
|
||||
|
||||
var t = `<div><input type="text" [ng-form-control]="form" [(ng-model)]="name"></div>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.componentInstance.name = "oldValue";
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(input.value).toEqual("oldValue");
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
tick();
|
||||
|
||||
expect(rootTC.componentInstance.name).toEqual("updatedValue");
|
||||
})));
|
||||
|
||||
describe("template-driven forms", () => {
|
||||
it("should add new controls and control groups",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<form>
|
||||
<div ng-control-group="user">
|
||||
<input type="text" ng-control="login">
|
||||
</div>
|
||||
</form>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = null;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var form = rootTC.componentViewChildren[0].inject(NgForm);
|
||||
expect(form.controls['user']).not.toBeDefined();
|
||||
|
||||
tick();
|
||||
|
||||
expect(form.controls['user']).toBeDefined();
|
||||
expect(form.controls['user'].controls['login']).toBeDefined();
|
||||
})));
|
||||
|
||||
it("should emit ng-submit event on submit",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<div><form (ng-submit)="name='updated'"></form></div>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = 'old';
|
||||
var form = rootTC.query(By.css("form"));
|
||||
|
||||
dispatchEvent(form.nativeElement, "submit");
|
||||
tick();
|
||||
|
||||
expect(rootTC.componentInstance.name).toEqual("updated");
|
||||
})));
|
||||
|
||||
it("should not create a template-driven form when ng-no-form is used",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<form ng-no-form>
|
||||
</form>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.name = null;
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(rootTC.componentViewChildren.length).toEqual(0);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should remove controls",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<form>
|
||||
<div *ng-if="name == 'show'">
|
||||
<input type="text" ng-control="login">
|
||||
</div>
|
||||
</form>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = 'show';
|
||||
rootTC.detectChanges();
|
||||
tick();
|
||||
var form = rootTC.componentViewChildren[0].inject(NgForm);
|
||||
|
||||
|
||||
expect(form.controls['login']).toBeDefined();
|
||||
|
||||
rootTC.componentInstance.name = 'hide';
|
||||
rootTC.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(form.controls['login']).not.toBeDefined();
|
||||
})));
|
||||
|
||||
it("should remove control groups",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<form>
|
||||
<div *ng-if="name=='show'" ng-control-group="user">
|
||||
<input type="text" ng-control="login">
|
||||
</div>
|
||||
</form>`;
|
||||
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = 'show';
|
||||
rootTC.detectChanges();
|
||||
tick();
|
||||
var form = rootTC.componentViewChildren[0].inject(NgForm);
|
||||
|
||||
expect(form.controls['user']).toBeDefined();
|
||||
|
||||
rootTC.componentInstance.name = 'hide';
|
||||
rootTC.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(form.controls['user']).not.toBeDefined();
|
||||
})));
|
||||
|
||||
it("should support ng-model for complex forms",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<form>
|
||||
<input type="text" ng-control="name" [(ng-model)]="name">
|
||||
</form>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = "oldValue";
|
||||
rootTC.detectChanges();
|
||||
tick();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(input.value).toEqual("oldValue");
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
tick();
|
||||
|
||||
expect(rootTC.componentInstance.name).toEqual("updatedValue");
|
||||
})));
|
||||
|
||||
|
||||
it("should support ng-model for single fields",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var t = `<div><input type="text" [(ng-model)]="name"></div>`;
|
||||
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.name = "oldValue";
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(input.value).toEqual("oldValue");
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
tick();
|
||||
|
||||
expect(rootTC.componentInstance.name).toEqual("updatedValue");
|
||||
})));
|
||||
});
|
||||
|
||||
|
||||
describe("setting status classes", () => {
|
||||
it("should work with single fields",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form = new Control("", Validators.required);
|
||||
|
||||
var t = `<div><input type="text" [ng-form-control]="form"></div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(['ng-binding', 'ng-invalid', 'ng-pristine', 'ng-untouched']);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should work with complex model-driven forms",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var form = new ControlGroup({"name": new Control("", Validators.required)});
|
||||
|
||||
var t = `<form [ng-form-model]="form"><input type="text" ng-control="name"></form>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should work with ng-model",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
var t = `<div><input [(ng-model)]="name" required></div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((rootTC) => {
|
||||
rootTC.componentInstance.name = "";
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("ng-model corner cases", () => {
|
||||
it("should not update the view when the value initially came from the view",
|
||||
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
|
||||
var form = new Control("");
|
||||
|
||||
var t =
|
||||
`<div><input type="text" [ng-form-control]="form" [(ng-model)]="name"></div>`;
|
||||
var rootTC;
|
||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then(
|
||||
(root) => { rootTC = root; });
|
||||
tick();
|
||||
rootTC.componentInstance.form = form;
|
||||
rootTC.detectChanges();
|
||||
|
||||
// In Firefox, effective text selection in the real DOM requires an actual focus
|
||||
// of the field. This is not an issue in a new HTML document.
|
||||
if (browserDetection.isFirefox) {
|
||||
var fakeDoc = DOM.createHtmlDocument();
|
||||
DOM.appendChild(fakeDoc.body, rootTC.nativeElement);
|
||||
}
|
||||
|
||||
var input = rootTC.query(By.css("input")).nativeElement;
|
||||
input.value = "aa";
|
||||
input.selectionStart = 1;
|
||||
dispatchEvent(input, "change");
|
||||
|
||||
tick();
|
||||
rootTC.detectChanges();
|
||||
|
||||
// selection start has not changed because we did not reset the value
|
||||
expect(input.selectionStart).toEqual(1);
|
||||
})));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: '[wrapped-value]',
|
||||
host: {'(change)': 'handleOnChange($event.target.value)', '[value]': 'value'}
|
||||
})
|
||||
class WrappedValue implements ControlValueAccessor {
|
||||
value;
|
||||
onChange: Function;
|
||||
|
||||
constructor(cd: NgControl) { cd.valueAccessor = this; }
|
||||
|
||||
writeValue(value) { this.value = `!${value}!`; }
|
||||
|
||||
registerOnChange(fn) { this.onChange = fn; }
|
||||
registerOnTouched(fn) {}
|
||||
|
||||
handleOnChange(value) { this.onChange(value.substring(1, value.length - 1)); }
|
||||
}
|
||||
|
||||
@Component({selector: "my-comp"})
|
||||
@View({directives: [FORM_DIRECTIVES, WrappedValue, NgIf, NgFor]})
|
||||
class MyComp {
|
||||
form: any;
|
||||
name: string;
|
||||
data: any;
|
||||
}
|
559
modules/angular2/test/core/forms/model_spec.ts
Normal file
559
modules/angular2/test/core/forms/model_spec.ts
Normal file
@ -0,0 +1,559 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el,
|
||||
AsyncTestCompleter,
|
||||
fakeAsync,
|
||||
tick,
|
||||
inject
|
||||
} from 'angular2/test_lib';
|
||||
import {ControlGroup, Control, ControlArray, Validators} from 'angular2/forms';
|
||||
import {ObservableWrapper} from 'angular2/src/core/facade/async';
|
||||
|
||||
export function main() {
|
||||
describe("Form Model", () => {
|
||||
describe("Control", () => {
|
||||
it("should default the value to null", () => {
|
||||
var c = new Control();
|
||||
expect(c.value).toBe(null);
|
||||
expect(c.validator).toBe(Validators.nullValidator);
|
||||
});
|
||||
|
||||
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("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"); });
|
||||
|
||||
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");
|
||||
}));
|
||||
|
||||
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("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"}});
|
||||
|
||||
g.controls["nested"].controls["two"].updateValue("333");
|
||||
|
||||
expect(g.value).toEqual({"one": "111", "nested": {"two": "333"}});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("validator", () => {
|
||||
it("should run the validator with the initial value (valid)", () => {
|
||||
var g = new ControlGroup({"one": new Control('value', Validators.required)});
|
||||
|
||||
expect(g.valid).toEqual(true);
|
||||
|
||||
expect(g.errors).toEqual(null);
|
||||
});
|
||||
|
||||
it("should run the validator with the initial value (invalid)", () => {
|
||||
var one = new Control(null, Validators.required);
|
||||
var g = new ControlGroup({"one": one});
|
||||
|
||||
expect(g.valid).toEqual(false);
|
||||
|
||||
expect(g.errors).toEqual({"required": [one]});
|
||||
});
|
||||
|
||||
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.errors).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
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("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("validator", () => {
|
||||
it("should run the validator with the initial value (valid)", () => {
|
||||
var a = new ControlArray(
|
||||
[new Control(1, Validators.required), new Control(2, Validators.required)]);
|
||||
|
||||
expect(a.valid).toBe(true);
|
||||
expect(a.errors).toBe(null);
|
||||
});
|
||||
|
||||
it("should run the validator with the initial value (invalid)", () => {
|
||||
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.errors).toEqual({"required": [a.controls[1]]});
|
||||
});
|
||||
|
||||
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.errors).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
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("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");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
79
modules/angular2/test/core/forms/validators_spec.ts
Normal file
79
modules/angular2/test/core/forms/validators_spec.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
el
|
||||
} from 'angular2/test_lib';
|
||||
import {ControlGroup, Control, Validators} from 'angular2/forms';
|
||||
|
||||
export function main() {
|
||||
function validator(key: string, error: any) {
|
||||
return function(c: Control) {
|
||||
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("compose", () => {
|
||||
it("should return a null validator when given null",
|
||||
() => { expect(Validators.compose(null)).toBe(Validators.nullValidator); });
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe("controlGroupValidator", () => {
|
||||
it("should collect errors from the child controls", () => {
|
||||
var one = new Control("one", validator("a", true));
|
||||
var two = new Control("one", validator("b", true));
|
||||
var g = new ControlGroup({"one": one, "two": two});
|
||||
|
||||
expect(Validators.group(g)).toEqual({"a": [one], "b": [two]});
|
||||
});
|
||||
|
||||
it("should not include controls that have no errors", () => {
|
||||
var one = new Control("one", validator("a", true));
|
||||
var two = new Control("two");
|
||||
var g = new ControlGroup({"one": one, "two": two});
|
||||
|
||||
expect(Validators.group(g)).toEqual({"a": [one]});
|
||||
});
|
||||
|
||||
it("should return null when no errors", () => {
|
||||
var g = new ControlGroup({"one": new Control("one")});
|
||||
|
||||
expect(Validators.group(g)).toEqual(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
221
modules/angular2/test/core/pipes/async_pipe_spec.ts
Normal file
221
modules/angular2/test/core/pipes/async_pipe_spec.ts
Normal file
@ -0,0 +1,221 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
SpyObject,
|
||||
browserDetection
|
||||
} from 'angular2/test_lib';
|
||||
import {SpyChangeDetectorRef} from './spies';
|
||||
|
||||
import {isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {WrappedValue} from 'angular2/change_detection';
|
||||
import {AsyncPipe} from 'angular2/pipes';
|
||||
import {
|
||||
EventEmitter,
|
||||
ObservableWrapper,
|
||||
PromiseWrapper,
|
||||
TimerWrapper
|
||||
} from 'angular2/src/core/facade/async';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
|
||||
export function main() {
|
||||
describe("AsyncPipe", () => {
|
||||
|
||||
describe('Observable', () => {
|
||||
var emitter;
|
||||
var pipe;
|
||||
var ref;
|
||||
var message = new Object();
|
||||
|
||||
beforeEach(() => {
|
||||
emitter = new EventEmitter();
|
||||
ref = new SpyChangeDetectorRef();
|
||||
pipe = new AsyncPipe(ref);
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return null when subscribing to an observable",
|
||||
() => { expect(pipe.transform(emitter)).toBe(null); });
|
||||
|
||||
it("should return the latest available value wrapped",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(emitter);
|
||||
|
||||
ObservableWrapper.callNext(emitter, message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(emitter)).toEqual(new WrappedValue(message));
|
||||
async.done();
|
||||
}, 0)
|
||||
}));
|
||||
|
||||
|
||||
it("should return same value when nothing has changed since the last call",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(emitter);
|
||||
ObservableWrapper.callNext(emitter, message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
pipe.transform(emitter);
|
||||
expect(pipe.transform(emitter)).toBe(message);
|
||||
async.done();
|
||||
}, 0)
|
||||
}));
|
||||
|
||||
it("should dispose of the existing subscription when subscribing to a new observable",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(emitter);
|
||||
|
||||
var newEmitter = new EventEmitter();
|
||||
expect(pipe.transform(newEmitter)).toBe(null);
|
||||
|
||||
// this should not affect the pipe
|
||||
ObservableWrapper.callNext(emitter, message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(newEmitter)).toBe(null);
|
||||
async.done();
|
||||
}, 0)
|
||||
}));
|
||||
|
||||
it("should request a change detection check upon receiving a new value",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(emitter);
|
||||
ObservableWrapper.callNext(emitter, message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(ref.spy('markForCheck')).toHaveBeenCalled();
|
||||
async.done();
|
||||
}, 0)
|
||||
}));
|
||||
});
|
||||
|
||||
describe("onDestroy", () => {
|
||||
it("should do nothing when no subscription",
|
||||
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
||||
|
||||
it("should dispose of the existing subscription", inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(emitter);
|
||||
pipe.onDestroy();
|
||||
|
||||
ObservableWrapper.callNext(emitter, message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(emitter)).toBe(null);
|
||||
async.done();
|
||||
}, 0)
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("Promise", () => {
|
||||
var message = new Object();
|
||||
var pipe;
|
||||
var completer;
|
||||
var ref;
|
||||
// adds longer timers for passing tests in IE
|
||||
var timer = (!isBlank(DOM) && browserDetection.isIE) ? 50 : 0;
|
||||
|
||||
beforeEach(() => {
|
||||
completer = PromiseWrapper.completer();
|
||||
ref = new SpyChangeDetectorRef();
|
||||
pipe = new AsyncPipe(ref);
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return null when subscribing to a promise",
|
||||
() => { expect(pipe.transform(completer.promise)).toBe(null); });
|
||||
|
||||
it("should return the latest available value", inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(completer.promise);
|
||||
|
||||
completer.resolve(message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
||||
async.done();
|
||||
}, timer)
|
||||
}));
|
||||
|
||||
it("should return unwrapped value when nothing has changed since the last call",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(completer.promise);
|
||||
completer.resolve(message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
pipe.transform(completer.promise);
|
||||
expect(pipe.transform(completer.promise)).toBe(message);
|
||||
async.done();
|
||||
}, timer)
|
||||
}));
|
||||
|
||||
it("should dispose of the existing subscription when subscribing to a new promise",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(completer.promise);
|
||||
|
||||
var newCompleter = PromiseWrapper.completer();
|
||||
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
||||
|
||||
// this should not affect the pipe, so it should return WrappedValue
|
||||
completer.resolve(message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(newCompleter.promise)).toBe(null);
|
||||
async.done();
|
||||
}, timer)
|
||||
}));
|
||||
|
||||
it("should request a change detection check upon receiving a new value",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(completer.promise);
|
||||
completer.resolve(message);
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(ref.spy('markForCheck')).toHaveBeenCalled();
|
||||
async.done();
|
||||
}, timer)
|
||||
}));
|
||||
|
||||
describe("onDestroy", () => {
|
||||
it("should do nothing when no source",
|
||||
() => { expect(() => pipe.onDestroy()).not.toThrow(); });
|
||||
|
||||
it("should dispose of the existing source", inject([AsyncTestCompleter], (async) => {
|
||||
pipe.transform(completer.promise);
|
||||
expect(pipe.transform(completer.promise)).toBe(null);
|
||||
completer.resolve(message)
|
||||
|
||||
|
||||
TimerWrapper.setTimeout(() => {
|
||||
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
|
||||
pipe.onDestroy();
|
||||
expect(pipe.transform(completer.promise)).toBe(null);
|
||||
async.done();
|
||||
}, timer);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('null', () => {
|
||||
it('should return null when given null', () => {
|
||||
var pipe = new AsyncPipe(null);
|
||||
expect(pipe.transform(null, [])).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('other types', () => {
|
||||
it('should throw when given an invalid object', () => {
|
||||
var pipe = new AsyncPipe(null);
|
||||
expect(() => pipe.transform(<any>"some bogus object", [])).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
78
modules/angular2/test/core/pipes/date_pipe_spec.ts
Normal file
78
modules/angular2/test/core/pipes/date_pipe_spec.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
browserDetection
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DatePipe} from 'angular2/pipes';
|
||||
import {DateWrapper} from 'angular2/src/core/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe("DatePipe", () => {
|
||||
var date;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
date = DateWrapper.create(2015, 6, 15, 21, 43, 11);
|
||||
pipe = new DatePipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support date", () => { expect(pipe.supports(date)).toBe(true); });
|
||||
it("should support int", () => { expect(pipe.supports(123456789)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(mlaval): enable tests when Intl API is no longer used, see
|
||||
// https://github.com/angular/angular/issues/3333
|
||||
if (browserDetection.supportsIntlApi) {
|
||||
describe("transform", () => {
|
||||
it('should format each component correctly', () => {
|
||||
expect(pipe.transform(date, ['y'])).toEqual('2015');
|
||||
expect(pipe.transform(date, ['yy'])).toEqual('15');
|
||||
expect(pipe.transform(date, ['M'])).toEqual('6');
|
||||
expect(pipe.transform(date, ['MM'])).toEqual('06');
|
||||
expect(pipe.transform(date, ['MMM'])).toEqual('Jun');
|
||||
expect(pipe.transform(date, ['MMMM'])).toEqual('June');
|
||||
expect(pipe.transform(date, ['d'])).toEqual('15');
|
||||
expect(pipe.transform(date, ['E'])).toEqual('Mon');
|
||||
expect(pipe.transform(date, ['EEEE'])).toEqual('Monday');
|
||||
expect(pipe.transform(date, ['H'])).toEqual('21');
|
||||
expect(pipe.transform(date, ['j'])).toEqual('9 PM');
|
||||
expect(pipe.transform(date, ['m'])).toEqual('43');
|
||||
expect(pipe.transform(date, ['s'])).toEqual('11');
|
||||
});
|
||||
|
||||
it('should format common multi component patterns', () => {
|
||||
expect(pipe.transform(date, ['yMEd'])).toEqual('Mon, 6/15/2015');
|
||||
expect(pipe.transform(date, ['MEd'])).toEqual('Mon, 6/15');
|
||||
expect(pipe.transform(date, ['MMMd'])).toEqual('Jun 15');
|
||||
expect(pipe.transform(date, ['yMMMMEEEEd'])).toEqual('Monday, June 15, 2015');
|
||||
expect(pipe.transform(date, ['jms'])).toEqual('9:43:11 PM');
|
||||
expect(pipe.transform(date, ['ms'])).toEqual('43:11');
|
||||
});
|
||||
|
||||
it('should format with pattern aliases', () => {
|
||||
expect(pipe.transform(date, ['medium'])).toEqual('Jun 15, 2015, 9:43:11 PM');
|
||||
expect(pipe.transform(date, ['short'])).toEqual('6/15/2015, 9:43 PM');
|
||||
expect(pipe.transform(date, ['fullDate'])).toEqual('Monday, June 15, 2015');
|
||||
expect(pipe.transform(date, ['longDate'])).toEqual('June 15, 2015');
|
||||
expect(pipe.transform(date, ['mediumDate'])).toEqual('Jun 15, 2015');
|
||||
expect(pipe.transform(date, ['shortDate'])).toEqual('6/15/2015');
|
||||
expect(pipe.transform(date, ['mediumTime'])).toEqual('9:43:11 PM');
|
||||
expect(pipe.transform(date, ['shortTime'])).toEqual('9:43 PM');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
76
modules/angular2/test/core/pipes/json_pipe_spec.ts
Normal file
76
modules/angular2/test/core/pipes/json_pipe_spec.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
proxy,
|
||||
SpyObject
|
||||
} from 'angular2/test_lib';
|
||||
import {Json, RegExp, NumberWrapper, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||
|
||||
import {JsonPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("JsonPipe", () => {
|
||||
var regNewLine = '\n';
|
||||
var inceptionObj;
|
||||
var inceptionObjString;
|
||||
var pipe;
|
||||
var collection: number[];
|
||||
|
||||
function normalize(obj: string): string { return StringWrapper.replace(obj, regNewLine, ''); }
|
||||
|
||||
beforeEach(() => {
|
||||
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
|
||||
inceptionObjString = "{\n" + " \"dream\": {\n" + " \"dream\": {\n" +
|
||||
" \"dream\": \"Limbo\"\n" + " }\n" + " }\n" + "}";
|
||||
|
||||
|
||||
pipe = new JsonPipe();
|
||||
collection = [];
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return JSON-formatted string",
|
||||
() => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); });
|
||||
|
||||
it("should return JSON-formatted string even when normalized", () => {
|
||||
var dream1 = normalize(pipe.transform(inceptionObj));
|
||||
var dream2 = normalize(inceptionObjString);
|
||||
expect(dream1).toEqual(dream2);
|
||||
});
|
||||
|
||||
it("should return JSON-formatted string similar to Json.stringify", () => {
|
||||
var dream1 = normalize(pipe.transform(inceptionObj));
|
||||
var dream2 = normalize(Json.stringify(inceptionObj));
|
||||
expect(dream1).toEqual(dream2);
|
||||
});
|
||||
|
||||
it("should return same ref when nothing has changed since the last call", () => {
|
||||
expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString);
|
||||
expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString);
|
||||
});
|
||||
|
||||
|
||||
it("should return a new value when something changed but the ref hasn't", () => {
|
||||
var stringCollection = '[]';
|
||||
var stringCollectionWith1 = '[\n' +
|
||||
' 1' +
|
||||
'\n]';
|
||||
|
||||
expect(pipe.transform(collection)).toEqual(stringCollection);
|
||||
|
||||
collection.push(1);
|
||||
|
||||
expect(pipe.transform(collection)).toEqual(stringCollectionWith1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
57
modules/angular2/test/core/pipes/limit_to_pipe_spec.ts
Normal file
57
modules/angular2/test/core/pipes/limit_to_pipe_spec.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {LimitToPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("LimitToPipe", () => {
|
||||
var list;
|
||||
var str;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
list = [1, 2, 3, 4, 5];
|
||||
str = 'tuvwxyz';
|
||||
pipe = new LimitToPipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support strings", () => { expect(pipe.supports(str)).toBe(true); });
|
||||
it("should support lists", () => { expect(pipe.supports(list)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it('should return the first X items when X is positive', () => {
|
||||
expect(pipe.transform(list, [3])).toEqual([1, 2, 3]);
|
||||
expect(pipe.transform(str, [3])).toEqual('tuv');
|
||||
});
|
||||
|
||||
it('should return the last X items when X is negative', () => {
|
||||
expect(pipe.transform(list, [-3])).toEqual([3, 4, 5]);
|
||||
expect(pipe.transform(str, [-3])).toEqual('xyz');
|
||||
});
|
||||
|
||||
it('should return a copy of input array if X is exceeds array length', () => {
|
||||
expect(pipe.transform(list, [20])).toEqual(list);
|
||||
expect(pipe.transform(list, [-20])).toEqual(list);
|
||||
});
|
||||
|
||||
it('should return the entire string if X exceeds input length', () => {
|
||||
expect(pipe.transform(str, [20])).toEqual(str);
|
||||
expect(pipe.transform(str, [-20])).toEqual(str);
|
||||
});
|
||||
|
||||
it('should not modify the input list', () => {
|
||||
expect(pipe.transform(list, [3])).toEqual([1, 2, 3]);
|
||||
expect(list).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
35
modules/angular2/test/core/pipes/lowercase_pipe_spec.ts
Normal file
35
modules/angular2/test/core/pipes/lowercase_pipe_spec.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {LowerCasePipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("LowerCasePipe", () => {
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new LowerCasePipe();
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return lowercase", () => {
|
||||
var val = pipe.transform(upper);
|
||||
expect(val).toEqual(lower);
|
||||
});
|
||||
|
||||
it("should lowercase when there is a new value", () => {
|
||||
var val = pipe.transform(upper);
|
||||
expect(val).toEqual(lower);
|
||||
var val2 = pipe.transform('WAT');
|
||||
expect(val2).toEqual('wat');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
72
modules/angular2/test/core/pipes/number_pipe_spec.ts
Normal file
72
modules/angular2/test/core/pipes/number_pipe_spec.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
browserDetection
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {DecimalPipe, PercentPipe, CurrencyPipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
// TODO(mlaval): enable tests when Intl API is no longer used, see
|
||||
// https://github.com/angular/angular/issues/3333
|
||||
if (browserDetection.supportsIntlApi) {
|
||||
describe("DecimalPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new DecimalPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(12345, [])).toEqual('12,345');
|
||||
expect(pipe.transform(123, ['.2'])).toEqual('123.00');
|
||||
expect(pipe.transform(1, ['3.'])).toEqual('001');
|
||||
expect(pipe.transform(1.1, ['3.4-5'])).toEqual('001.1000');
|
||||
|
||||
expect(pipe.transform(1.123456, ['3.4-5'])).toEqual('001.12346');
|
||||
expect(pipe.transform(1.1234, [])).toEqual('1.123');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe("PercentPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new PercentPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(1.23, [])).toEqual('123%');
|
||||
expect(pipe.transform(1.2, ['.2'])).toEqual('120.00%');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
describe("CurrencyPipe", () => {
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => { pipe = new CurrencyPipe(); });
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(123, [])).toEqual('USD123');
|
||||
expect(pipe.transform(12, ['EUR', false, '.2'])).toEqual('EUR12.00');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
9
modules/angular2/test/core/pipes/spies.dart
Normal file
9
modules/angular2/test/core/pipes/spies.dart
Normal file
@ -0,0 +1,9 @@
|
||||
library pipes.spies;
|
||||
|
||||
import 'package:angular2/src/core/change_detection/change_detection.dart';
|
||||
import 'package:angular2/test_lib.dart';
|
||||
|
||||
@proxy
|
||||
class SpyChangeDetectorRef extends SpyObject implements ChangeDetectorRef {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
7
modules/angular2/test/core/pipes/spies.ts
Normal file
7
modules/angular2/test/core/pipes/spies.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
import {SpyObject, proxy} from 'angular2/test_lib';
|
||||
|
||||
export class SpyChangeDetectorRef extends SpyObject {
|
||||
constructor() { super(ChangeDetectorRef); }
|
||||
}
|
36
modules/angular2/test/core/pipes/uppercase_pipe_spec.ts
Normal file
36
modules/angular2/test/core/pipes/uppercase_pipe_spec.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {UpperCasePipe} from 'angular2/pipes';
|
||||
|
||||
export function main() {
|
||||
describe("UpperCasePipe", () => {
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new UpperCasePipe();
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it("should return uppercase", () => {
|
||||
var val = pipe.transform(lower);
|
||||
expect(val).toEqual(upper);
|
||||
});
|
||||
|
||||
it("should uppercase when there is a new value", () => {
|
||||
var val = pipe.transform(lower);
|
||||
expect(val).toEqual(upper);
|
||||
var val2 = pipe.transform('wat');
|
||||
expect(val2).toEqual('WAT');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user