Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 18ec087

Browse files
authored
docs(forms): fix css, form validation e2e, other tweaks (#2235)
1 parent 0c96271 commit 18ec087

File tree

7 files changed

+196
-82
lines changed

7 files changed

+196
-82
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/// <reference path="../_protractor/e2e.d.ts" />
2+
'use strict'; // necessary for node!
3+
4+
// THESE TESTS ARE INCOMPLETE
5+
describeIf(browser.appIsTs || browser.appIsJs, 'Form Validation Tests', function () {
6+
7+
beforeAll(function () {
8+
browser.get('');
9+
});
10+
11+
describe('Hero Form 1', () => {
12+
beforeAll(() => {
13+
getPage('hero-form-template1');
14+
});
15+
16+
tests();
17+
});
18+
19+
describe('Hero Form 2', () => {
20+
beforeAll(() => {
21+
getPage('hero-form-template2');
22+
});
23+
24+
tests();
25+
bobTests();
26+
});
27+
28+
describe('Hero Form 3 (Reactive)', () => {
29+
beforeAll(() => {
30+
getPage('hero-form-reactive3');
31+
makeNameTooLong();
32+
});
33+
34+
tests();
35+
bobTests();
36+
});
37+
});
38+
39+
//////////
40+
41+
const testName = 'Test Name';
42+
43+
let page: {
44+
section: protractor.ElementFinder,
45+
form: protractor.ElementFinder,
46+
title: protractor.ElementFinder,
47+
nameInput: protractor.ElementFinder,
48+
alterEgoInput: protractor.ElementFinder,
49+
powerSelect: protractor.ElementFinder,
50+
errorMessages: protractor.ElementArrayFinder,
51+
heroFormButtons: protractor.ElementArrayFinder,
52+
heroSubmitted: protractor.ElementFinder
53+
};
54+
55+
function getPage(sectionTag: string) {
56+
let section = element(by.css(sectionTag));
57+
let buttons = section.all(by.css('button'));
58+
59+
page = {
60+
section: section,
61+
form: section.element(by.css('form')),
62+
title: section.element(by.css('h1')),
63+
nameInput: section.element(by.css('#name')),
64+
alterEgoInput: section.element(by.css('#alterEgo')),
65+
powerSelect: section.element(by.css('#power')),
66+
errorMessages: section.all(by.css('div.alert')),
67+
heroFormButtons: buttons,
68+
heroSubmitted: section.element(by.css('hero-submitted > div'))
69+
};
70+
}
71+
72+
function tests() {
73+
it('should display correct title', function () {
74+
expect(page.title.getText()).toContain('Hero Form');
75+
});
76+
77+
it('should not display submitted message before submit', function () {
78+
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(false);
79+
});
80+
81+
it('should have form buttons', function () {
82+
expect(page.heroFormButtons.count()).toEqual(2);
83+
});
84+
85+
it('should have error at start', function () {
86+
expectFormIsInvalid();
87+
});
88+
89+
// it('showForm', function () {
90+
// page.form.getInnerHtml().then(html => console.log(html));
91+
// });
92+
93+
it('should have disabled submit button', function () {
94+
expect(page.heroFormButtons.get(0).isEnabled()).toBe(false);
95+
});
96+
97+
it('resetting name to valid name should clear errors', function () {
98+
const ele = page.nameInput;
99+
expect(ele.isPresent()).toBe(true, 'nameInput should exist');
100+
ele.clear();
101+
ele.sendKeys(testName);
102+
expectFormIsValid();
103+
});
104+
105+
it('should produce "required" error after clearing name', function () {
106+
page.nameInput.clear();
107+
// page.alterEgoInput.click(); // to blur ... didn't work
108+
page.nameInput.sendKeys('x', protractor.Key.BACK_SPACE); // ugh!
109+
expect(page.form.getAttribute('class')).toMatch('ng-invalid');
110+
expect(page.errorMessages.get(0).getText()).toContain('required');
111+
});
112+
113+
it('should produce "at least 4 characters" error when name="x"', function () {
114+
page.nameInput.clear();
115+
page.nameInput.sendKeys('x'); // too short
116+
expectFormIsInvalid();
117+
expect(page.errorMessages.get(0).getText()).toContain('at least 4 characters');
118+
});
119+
120+
it('resetting name to valid name again should clear errors', function () {
121+
page.nameInput.sendKeys(testName);
122+
expectFormIsValid();
123+
});
124+
125+
it('should have enabled submit button', function () {
126+
const submitBtn = page.heroFormButtons.get(0);
127+
expect(submitBtn.isEnabled()).toBe(true);
128+
});
129+
130+
it('should hide form after submit', function () {
131+
page.heroFormButtons.get(0).click();
132+
expect(page.title.isDisplayed()).toBe(false);
133+
});
134+
135+
it('submitted form should be displayed', function () {
136+
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(true);
137+
});
138+
139+
it('submitted form should have new hero name', function () {
140+
expect(page.heroSubmitted.getText()).toContain(testName);
141+
});
142+
143+
it('clicking edit button should reveal form again', function () {
144+
const editBtn = page.heroSubmitted.element(by.css('button'));
145+
editBtn.click();
146+
expect(page.heroSubmitted.isElementPresent(by.css('h2')))
147+
.toBe(false, 'submitted hidden again');
148+
expect(page.title.isDisplayed()).toBe(true, 'can see form title');
149+
});
150+
}
151+
152+
function expectFormIsValid() {
153+
expect(page.form.getAttribute('class')).toMatch('ng-valid');
154+
}
155+
156+
function expectFormIsInvalid() {
157+
expect(page.form.getAttribute('class')).toMatch('ng-invalid');
158+
}
159+
160+
function bobTests() {
161+
const emsg = 'Someone named "Bob" cannot be a hero.';
162+
163+
it('should produce "no bob" error after setting name to "Bobby"', function () {
164+
page.nameInput.clear();
165+
page.nameInput.sendKeys('Bobby');
166+
expectFormIsInvalid();
167+
expect(page.errorMessages.get(0).getText()).toBe(emsg);
168+
});
169+
170+
it('should be ok again with valid name', function () {
171+
page.nameInput.clear();
172+
page.nameInput.sendKeys(testName);
173+
expectFormIsValid();
174+
});
175+
}
176+
177+
function makeNameTooLong() {
178+
// make the first name invalid
179+
page.nameInput.sendKeys('ThisHeroNameHasWayWayTooManyLetters');
180+
}

public/docs/_examples/cb-form-validation/e2e-spec.ts.disabled

Lines changed: 0 additions & 64 deletions
This file was deleted.

public/docs/_examples/cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ export class HeroFormReactiveComponent implements OnInit {
3838
addHero() {
3939
this.hero = new Hero(42, '', '');
4040
this.buildForm();
41-
this.onValueChanged();
4241
// #enddocregion add-hero
4342
// #enddocregion class
4443

@@ -74,17 +73,20 @@ export class HeroFormReactiveComponent implements OnInit {
7473

7574
this.heroForm.valueChanges
7675
.subscribe(data => this.onValueChanged(data));
76+
77+
this.onValueChanged(); // (re)set validation messages now
7778
}
7879

7980
// #enddocregion form-builder
8081

8182
onValueChanged(data?: any) {
82-
const controls = this.heroForm ? this.heroForm.controls : {};
83+
if (!this.heroForm) { return; }
84+
const form = this.heroForm;
8385

8486
for (const field in this.formErrors) {
8587
// clear previous error message (if any)
8688
this.formErrors[field] = '';
87-
const control = controls[field];
89+
const control = form.get(field);
8890

8991
if (control && control.dirty && !control.valid) {
9092
const messages = this.validationMessages[field];

public/docs/_examples/cb-form-validation/ts/app/template/hero-form-template2.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ export class HeroFormTemplate2Component implements AfterViewChecked {
6060

6161
// #docregion handler
6262
onValueChanged(data?: any) {
63-
const controls = this.heroForm ? this.heroForm.controls : {};
63+
if (!this.heroForm) { return; }
64+
const form = this.heroForm.form;
6465

6566
for (const field in this.formErrors) {
6667
// clear previous error message (if any)
6768
this.formErrors[field] = '';
68-
const control = controls[field];
69+
const control = form.get(field);
6970

7071
if (control && control.dirty && !control.valid) {
7172
const messages = this.validationMessages[field];
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
.ng-valid[required] {
1+
.ng-valid[required], .ng-valid.required {
22
border-left: 5px solid #42A948; /* green */
33
}
44

5-
.ng-invalid {
5+
.ng-invalid:not(form) {
66
border-left: 5px solid #a94442; /* red */
77
}
8-
9-
.ng-valid.required {
10-
border-left: 5px solid #42A948; /* green */
11-
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* #docregion */
2-
.ng-valid[required] {
2+
.ng-valid[required], .ng-valid.required {
33
border-left: 5px solid #42A948; /* green */
44
}
55

6-
.ng-invalid {
6+
.ng-invalid:not(form) {
77
border-left: 5px solid #a94442; /* red */
88
}
9-
/* #enddocregion */
9+
/* #enddocregion */

public/docs/ts/latest/cookbook/form-validation.jade

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ a#reactive
327327
A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook.
328328
:marked
329329
- the `buildForm` method uses the `FormBuilder` (`fb`) to declare the form control model.
330-
Then it attaches the same `onValueChanged` handler to the form.
330+
Then it attaches the same `onValueChanged` handler (there's a one line difference)
331+
to the form's `valueChanged` event and calls it immediately
332+
to set error messages for the new control model.
331333

332334
:marked
333335
#### _FormBuilder_ declaration
@@ -371,9 +373,6 @@ a#reactive
371373
Then it calls `buildForm` again which replaces the previous `heroForm` control model with a new one.
372374
The `<form>` tag's `[formGroup]` binding refreshes the page with the new control model.
373375

374-
Finally, it calls the `onValueChanged` handler to clear previous error messages and reset them
375-
to reflect Angular's validation of the new `hero` object.
376-
377376
Here's the complete reactive component file, compared to the two template-driven component files.
378377
+makeTabs(
379378
`cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts,

0 commit comments

Comments
 (0)