/
formField.component.spec.ts
233 lines (225 loc) · 9.81 KB
/
formField.component.spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
* Copyright 2019 GridGain Systems, Inc. and Contributors.
*
* Licensed under the GridGain Community Edition License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'app/../test/angular-testbed-init';
import {ReactiveFormsModule, FormControl, Validators, FormGroup} from '@angular/forms';
import {assert} from 'chai';
import {TestBed, async, ComponentFixture, tick, fakeAsync} from '@angular/core/testing';
import {Component, Directive, NO_ERRORS_SCHEMA, Input, TemplateRef} from '@angular/core';
import { By } from '@angular/platform-browser';
import {
FormField, FormFieldError, FormFieldHint, FormFieldTooltip,
FormFieldRequiredMarkerStyles, FormFieldErrorStyles, FORM_FIELD_OPTIONS
} from './index';
import {FormFieldErrors} from './errors.component';
import {IgniteIcon} from '../igniteIcon.component';
suite('Angular form-field component', () => {
@Component({selector: 'popper-content', template: ''}) class PopperContentStub {}
@Directive({selector: '[popper]'}) class PopperStub {}
@Component({selector: 'form-field-errors', template: ''}) class ErrorsStub {
@Input()
errorStyle: any;
@Input()
errorType: any;
@Input()
extraErrorMessages: any
}
@Component({selector: 'form-field-tooltip', template: ''}) class TooltipStub {
@Input()
content: any
}
let fixture: ComponentFixture<HostComponent>;
@Component({
template: `
<div [formGroup]='form'>
<form-field>
<form-field-hint>Hello world!</form-field-hint>
<label for="one">One:</label>
<span>Foo</span>
<input type="text" id="one" formControlName='one'>
<i>Bar</i>
<span formFieldOverlay>😂</span>
<span formFieldOverlay>👌</span>
</form-field>
<form-field [requiredMarkerStyle]='requiredMarkerStyle' [errorStyle]='inlineError'>
<label for="two">Two:</label>
<input type="text" id="two" formControlName='two'>
</form-field>
<form-field [errorStyle]='iconError'>
<input type="text" formControlName='three'>
</form-field>
</div>
`,
providers: [
{
provide: FORM_FIELD_OPTIONS,
useValue: {
requiredMarkerStyle: FormFieldRequiredMarkerStyles.OPTIONAL,
errorStyle: FormFieldErrorStyles.INLINE
}
}
]
})
class HostComponent {
form = new FormGroup({
one: new FormControl(null, []),
two: new FormControl(null, [Validators.required]),
three: new FormControl(null, [Validators.required])
});
requiredMarkerStyle = FormFieldRequiredMarkerStyles.REQUIRED;
inlineError = FormFieldErrorStyles.INLINE;
iconError = FormFieldErrorStyles.ICON;
extraMessages = {required: 'Foo'}
}
setup(fakeAsync(async() => {
TestBed.configureTestingModule({
declarations: [
FormField, FormFieldHint,
HostComponent,
ErrorsStub, TooltipStub
],
schemas: [NO_ERRORS_SCHEMA],
imports: [ReactiveFormsModule]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(HostComponent);
fixture.detectChanges();
tick();
fixture.detectChanges();
});
}));
test('Required marker styles', fakeAsync(() => {
assert.ok(
fixture.nativeElement.querySelector('form-field:nth-of-type(1)').matches('.form-field__optional'),
'Has "optional" class when required marker mode is "optional" and required validator is not present'
);
assert.ok(
fixture.nativeElement.querySelector('form-field:nth-of-type(2)').matches('.form-field__required'),
'Has "optional" class when required marker mode is "optional" and required validator is not present'
);
}));
test('Validation styles', () => {
fixture.componentInstance.form.get('two').markAsTouched();
fixture.componentInstance.form.get('three').markAsTouched();
fixture.detectChanges();
assert.ok(
fixture.nativeElement.querySelector('form-field:nth-of-type(2)>form-field-errors'),
'Displays errors inline when "inline" errorStyle is used.'
);
assert.ok(
fixture.nativeElement.querySelector('form-field:nth-of-type(3) .input-overlay form-field-errors'),
'Displays errors in overlay when "icon" errorStyle is used.'
);
});
test('Validation message display conditions', () => {
const hasErrors = (index: number) => !!fixture.nativeElement.querySelector(`form-field:nth-of-type(${index}) form-field-errors`);
assert.isFalse(hasErrors(1), 'Pristine, untouched and valid shows no errors');
fixture.componentInstance.form.get('one').markAsTouched();
fixture.detectChanges();
assert.isFalse(hasErrors(1), 'Pristine, touched and valid shows no errors');
fixture.componentInstance.form.get('one').markAsUntouched();
fixture.componentInstance.form.get('one').markAsDirty();
fixture.detectChanges();
assert.isFalse(hasErrors(1), 'Untouched, dirty and valid shows no errors');
fixture.componentInstance.form.get('two').markAsTouched();
fixture.detectChanges();
assert.isTrue(hasErrors(2), 'Pristine, touched and invalid shows errors');
fixture.componentInstance.form.get('two').markAsUntouched();
fixture.componentInstance.form.get('two').markAsDirty();
fixture.detectChanges();
assert.isTrue(hasErrors(2), 'Dirty, untouched and invalid shows errors');
fixture.componentInstance.form.get('two').markAsTouched();
fixture.componentInstance.form.get('two').markAsPristine();
fixture.detectChanges();
assert.isTrue(hasErrors(2), 'Pristine, touched and invalid shows errors');
fixture.componentInstance.form.get('two').markAsDirty();
fixture.detectChanges();
assert.isTrue(hasErrors(2), 'Dirty, touched and invalid shows errors');
});
test('form-field-errors intgration', () => {
const field = (fixture.debugElement.query(By.css('form-field:nth-of-type(2)')).componentInstance as FormField);
const extraMessages = {
required: {} as TemplateRef<any>,
custom: {} as TemplateRef<any>
};
field.addExtraErrorMessage('required', extraMessages.required);
field.addExtraErrorMessage('custom', extraMessages.custom);
fixture.componentInstance.form.get('two').markAsTouched();
fixture.detectChanges();
const errors = fixture.debugElement.query(By.css('form-field:nth-of-type(2) form-field-errors')).componentInstance as ErrorsStub;
assert.deepEqual(
errors.extraErrorMessages,
extraMessages,
'Public addExtraErrorMessage method passes extra error messages to form-field-errors'
);
assert.equal(
errors.errorStyle,
FormFieldErrorStyles.INLINE,
'Error style value is passed to form-field-errors'
);
assert.equal(
errors.errorType,
'required',
'Current error type is passed to form-field-errors'
);
});
test('Form field hint', () => {
const hint = fixture.debugElement.query(By.directive(FormFieldHint)).componentInstance as FormFieldHint;
hint.popper = {};
fixture.detectChanges();
const tooltip = fixture.debugElement.query(By.directive(TooltipStub)).componentInstance as TooltipStub;
assert.notOk(
fixture.nativeElement.querySelector('form-field:nth-of-type(2) form-field-tooltip'),
'Does not show tooltip if no hint was provided'
);
assert.ok(
fixture.nativeElement.querySelector('form-field:nth-of-type(1) form-field-tooltip'),
'Shows tooltip if hint was provided'
);
assert.equal(
tooltip.content,
hint.popper,
'Passes hint.popper to form-field-tooltip'
);
});
test('Label transclusion', () => {
assert.ok(
fixture.debugElement.query(By.css('form-field:nth-of-type(1) .angular-form-field__label label')),
'It trancludes label element into label wrapper'
);
});
test('Overlay', () => {
assert.equal(
fixture.debugElement.query(By.css('form-field:nth-of-type(1) .input-overlay')).children.length,
2,
'It transcludes overlay nodes into overlay container'
);
assert.equal(
fixture.debugElement
.query(By.css('form-field:nth-of-type(1) .angular-form-field__input'))
.nativeElement.dataset.overlayItemsCount,
'2',
'It exposes overlay items count as data-attribute'
);
});
test('Input transclusion', () => {
assert.equal(
fixture.debugElement
.query(By.css('form-field:nth-of-type(1) .angular-form-field__input'))
.nativeElement.children.length,
4,
'It transcludes the rest of elements into input wrapper'
);
});
});