@@ -5,96 +5,312 @@ import { MatFormFieldModule } from '@angular/material/form-field';
5
5
import { Component , ViewChild } from '@angular/core' ;
6
6
import {
7
7
FormControl ,
8
+ FormGroup ,
9
+ FormsModule ,
8
10
ReactiveFormsModule ,
9
11
ValidationErrors ,
10
12
Validators ,
11
13
} from '@angular/forms' ;
12
14
import { NoopAnimationsModule } from '@angular/platform-browser/animations' ;
13
15
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed' ;
16
+ import { fireEvent } from '@testing-library/dom' ;
14
17
import { ErrorMessageProvider } from './error-message-provider' ;
15
18
import { DynamicErrorDirective } from './dynamic-error.directive' ;
16
19
17
- @Component ( {
18
- template : `<mat-form-field>
19
- <input matInput [formControl]="formControl" />
20
- <mat-error *schamanDynamicError></mat-error>
21
- </mat-form-field>` ,
22
- standalone : true ,
23
- imports : [
24
- DynamicErrorDirective ,
25
- MatInputModule ,
26
- MatFormFieldModule ,
27
- ReactiveFormsModule ,
28
- ] ,
29
- } )
30
- class DirectiveTestComponent {
31
- @ViewChild ( DynamicErrorDirective , { static : true } ) directive :
32
- | DynamicErrorDirective
33
- | undefined ;
34
- public readonly formControl = new FormControl ( '' , Validators . required ) ;
35
- }
36
-
37
- const render = async ( ) => {
38
- await TestBed . configureTestingModule ( {
39
- imports : [ DirectiveTestComponent , NoopAnimationsModule ] ,
40
- providers : [
41
- {
42
- provide : ErrorMessageProvider ,
43
- useValue : {
44
- getErrorMessagesFor : ( error : ValidationErrors ) =>
45
- Object . keys ( error ) [ 0 ] ,
46
- } ,
47
- } ,
48
- ] ,
49
- } ) . compileComponents ( ) ;
50
-
51
- const fixture = TestBed . createComponent ( DirectiveTestComponent ) ;
52
- fixture . detectChanges ( ) ;
53
- const loader = TestbedHarnessEnvironment . loader ( fixture ) ;
54
- return { fixture, loader } ;
55
- } ;
56
-
57
20
describe ( 'DynamicErrorDirective' , ( ) => {
58
- it ( 'should create' , async ( ) => {
59
- const { fixture } = await render ( ) ;
60
- expect ( fixture . componentInstance ) . toBeTruthy ( ) ;
61
- } ) ;
21
+ describe ( 'Reactive form with material input' , ( ) => {
22
+ @Component ( {
23
+ template : `<form [formGroup]="formGroup">
24
+ <mat-form-field>
25
+ <input matInput [formControl]="formControl" />
26
+ <mat-error *schamanDynamicError></mat-error>
27
+ </mat-form-field>
28
+ </form>` ,
29
+ standalone : true ,
30
+ imports : [
31
+ DynamicErrorDirective ,
32
+ MatInputModule ,
33
+ MatFormFieldModule ,
34
+ ReactiveFormsModule ,
35
+ ] ,
36
+ } )
37
+ class DirectiveTestComponent {
38
+ @ViewChild ( DynamicErrorDirective , { static : true } ) directive :
39
+ | DynamicErrorDirective
40
+ | undefined ;
41
+ public readonly formControl = new FormControl ( '' , Validators . required ) ;
42
+ public readonly formGroup = new FormGroup ( {
43
+ formControl : this . formControl ,
44
+ } ) ;
45
+ }
46
+
47
+ const render = async ( ) => {
48
+ await TestBed . configureTestingModule ( {
49
+ imports : [ DirectiveTestComponent , NoopAnimationsModule ] ,
50
+ providers : [
51
+ {
52
+ provide : ErrorMessageProvider ,
53
+ useValue : {
54
+ getErrorMessagesFor : ( error : ValidationErrors ) =>
55
+ Object . keys ( error ) [ 0 ] ,
56
+ } ,
57
+ } ,
58
+ ] ,
59
+ } ) . compileComponents ( ) ;
60
+
61
+ const fixture = TestBed . createComponent ( DirectiveTestComponent ) ;
62
+ fixture . detectChanges ( ) ;
63
+ const loader = TestbedHarnessEnvironment . loader ( fixture ) ;
64
+ return { fixture, loader } ;
65
+ } ;
66
+ it ( 'should create' , async ( ) => {
67
+ const { fixture } = await render ( ) ;
68
+ expect ( fixture . componentInstance ) . toBeTruthy ( ) ;
69
+ } ) ;
70
+
71
+ it ( 'should show error message' , async ( ) => {
72
+ const { fixture, loader } = await render ( ) ;
73
+ const input = await loader . getHarness ( MatInputHarness ) ;
74
+
75
+ await input . focus ( ) ;
76
+ await input . setValue ( 'a' ) ;
77
+ await input . setValue ( '' ) ;
78
+ await input . blur ( ) ;
79
+
80
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
81
+ } ) ;
82
+
83
+ it ( 'should hide error message' , async ( ) => {
84
+ const { fixture, loader } = await render ( ) ;
85
+ const input = await loader . getHarness ( MatInputHarness ) ;
86
+
87
+ await input . focus ( ) ;
88
+ await input . setValue ( 'a' ) ;
89
+ await input . setValue ( '' ) ;
90
+ await input . setValue ( 'a' ) ;
91
+ await input . blur ( ) ;
92
+
93
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
94
+ } ) ;
62
95
63
- it ( 'should show error message ' , async ( ) => {
64
- const { fixture, loader } = await render ( ) ;
65
- const input = await loader . getHarness ( MatInputHarness ) ;
96
+ it ( 'should unsubscribe in on destroy ' , async ( ) => {
97
+ const { fixture, loader } = await render ( ) ;
98
+ const input = await loader . getHarness ( MatInputHarness ) ;
66
99
67
- await input . focus ( ) ;
68
- await input . setValue ( 'a' ) ;
69
- await input . setValue ( '' ) ;
70
- await input . blur ( ) ;
100
+ fixture . componentInstance . directive ?. ngOnDestroy ( ) ;
101
+ await input . focus ( ) ;
102
+ await input . setValue ( 'a' ) ;
103
+ await input . setValue ( '' ) ;
104
+ await input . blur ( ) ;
71
105
72
- expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
106
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
107
+ } ) ;
108
+
109
+ it ( 'should show error message on submit' , async ( ) => {
110
+ const { fixture } = await render ( ) ;
111
+
112
+ const form = fixture . nativeElement . querySelector ( 'form' ) ;
113
+ fireEvent . submit ( form ) ;
114
+
115
+ fixture . detectChanges ( ) ;
116
+
117
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
118
+ } ) ;
73
119
} ) ;
74
120
75
- it ( 'should hide error message' , async ( ) => {
76
- const { fixture, loader } = await render ( ) ;
77
- const input = await loader . getHarness ( MatInputHarness ) ;
121
+ describe ( 'Form with material input' , ( ) => {
122
+ @Component ( {
123
+ template : `<form>
124
+ <mat-form-field>
125
+ <input matInput [(ngModel)]="value" required name="test" />
126
+ <mat-error *schamanDynamicError></mat-error>
127
+ </mat-form-field>
128
+ </form>` ,
129
+ standalone : true ,
130
+ imports : [
131
+ DynamicErrorDirective ,
132
+ MatInputModule ,
133
+ MatFormFieldModule ,
134
+ FormsModule ,
135
+ ] ,
136
+ } )
137
+ class DirectiveTestComponent {
138
+ @ViewChild ( DynamicErrorDirective , { static : true } ) directive :
139
+ | DynamicErrorDirective
140
+ | undefined ;
141
+ public value = '' ;
142
+ }
143
+
144
+ const render = async ( ) => {
145
+ await TestBed . configureTestingModule ( {
146
+ imports : [ DirectiveTestComponent , NoopAnimationsModule ] ,
147
+ providers : [
148
+ {
149
+ provide : ErrorMessageProvider ,
150
+ useValue : {
151
+ getErrorMessagesFor : ( error : ValidationErrors ) =>
152
+ Object . keys ( error ) [ 0 ] ,
153
+ } ,
154
+ } ,
155
+ ] ,
156
+ } ) . compileComponents ( ) ;
157
+
158
+ const fixture = TestBed . createComponent ( DirectiveTestComponent ) ;
159
+ fixture . detectChanges ( ) ;
160
+ const loader = TestbedHarnessEnvironment . loader ( fixture ) ;
161
+ return { fixture, loader } ;
162
+ } ;
163
+ it ( 'should create' , async ( ) => {
164
+ const { fixture } = await render ( ) ;
165
+ expect ( fixture . componentInstance ) . toBeTruthy ( ) ;
166
+ } ) ;
167
+
168
+ it ( 'should show error message' , async ( ) => {
169
+ const { fixture, loader } = await render ( ) ;
170
+ const input = await loader . getHarness ( MatInputHarness ) ;
171
+
172
+ await input . focus ( ) ;
173
+ await input . setValue ( 'a' ) ;
174
+ await input . setValue ( '' ) ;
175
+ await input . blur ( ) ;
176
+
177
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
178
+ } ) ;
179
+
180
+ it ( 'should hide error message' , async ( ) => {
181
+ const { fixture, loader } = await render ( ) ;
182
+ const input = await loader . getHarness ( MatInputHarness ) ;
78
183
79
- await input . focus ( ) ;
80
- await input . setValue ( 'a' ) ;
81
- await input . setValue ( '' ) ;
82
- await input . setValue ( 'a' ) ;
83
- await input . blur ( ) ;
184
+ await input . focus ( ) ;
185
+ await input . setValue ( 'a' ) ;
186
+ await input . setValue ( '' ) ;
187
+ await input . setValue ( 'a' ) ;
188
+ await input . blur ( ) ;
84
189
85
- expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
190
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
191
+ } ) ;
192
+
193
+ it ( 'should unsubscribe in on destroy' , async ( ) => {
194
+ const { fixture, loader } = await render ( ) ;
195
+ const input = await loader . getHarness ( MatInputHarness ) ;
196
+
197
+ fixture . componentInstance . directive ?. ngOnDestroy ( ) ;
198
+ await input . focus ( ) ;
199
+ await input . setValue ( 'a' ) ;
200
+ await input . setValue ( '' ) ;
201
+ await input . blur ( ) ;
202
+
203
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
204
+ } ) ;
205
+
206
+ it ( 'should show error message on submit' , async ( ) => {
207
+ const { fixture } = await render ( ) ;
208
+
209
+ const form = fixture . nativeElement . querySelector ( 'form' ) ;
210
+ fireEvent . submit ( form ) ;
211
+
212
+ fixture . detectChanges ( ) ;
213
+
214
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
215
+ } ) ;
86
216
} ) ;
87
217
88
- it ( 'should unsubscribe in on destroy' , async ( ) => {
89
- const { fixture, loader } = await render ( ) ;
90
- const input = await loader . getHarness ( MatInputHarness ) ;
218
+ describe ( 'Form control bare' , ( ) => {
219
+ @Component ( {
220
+ template : `<form [formGroup]="formGroup">
221
+ <input [formControl]="formControl" />
222
+ <div *schamanDynamicError="formControl"></div>
223
+ </form>` ,
224
+ standalone : true ,
225
+ imports : [ DynamicErrorDirective , ReactiveFormsModule ] ,
226
+ } )
227
+ class DirectiveTestComponent {
228
+ @ViewChild ( DynamicErrorDirective , { static : true } ) directive :
229
+ | DynamicErrorDirective
230
+ | undefined ;
231
+ public readonly formControl = new FormControl ( '' , Validators . required ) ;
232
+ public readonly formGroup = new FormGroup ( {
233
+ formControl : this . formControl ,
234
+ } ) ;
235
+ }
236
+
237
+ const render = async ( ) => {
238
+ await TestBed . configureTestingModule ( {
239
+ imports : [ DirectiveTestComponent , NoopAnimationsModule ] ,
240
+ providers : [
241
+ {
242
+ provide : ErrorMessageProvider ,
243
+ useValue : {
244
+ getErrorMessagesFor : ( error : ValidationErrors ) =>
245
+ Object . keys ( error ) [ 0 ] ,
246
+ } ,
247
+ } ,
248
+ ] ,
249
+ } ) . compileComponents ( ) ;
250
+
251
+ const fixture = TestBed . createComponent ( DirectiveTestComponent ) ;
252
+ fixture . detectChanges ( ) ;
253
+ return { fixture } ;
254
+ } ;
255
+ it ( 'should create' , async ( ) => {
256
+ const { fixture } = await render ( ) ;
257
+ expect ( fixture . componentInstance ) . toBeTruthy ( ) ;
258
+ } ) ;
259
+
260
+ it ( 'should show error message' , async ( ) => {
261
+ const { fixture } = await render ( ) ;
262
+ const input = fixture . nativeElement . querySelector ( 'input' ) ;
263
+
264
+ fireEvent . focus ( input ) ;
265
+ fireEvent . input ( input , { target : { value : 'a' } } ) ;
266
+ fixture . detectChanges ( ) ;
267
+ fireEvent . input ( input , { target : { value : '' } } ) ;
268
+ fireEvent . blur ( input ) ;
269
+ fixture . detectChanges ( ) ;
270
+
271
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
272
+ } ) ;
273
+
274
+ it ( 'should hide error message' , async ( ) => {
275
+ const { fixture } = await render ( ) ;
276
+ const input = fixture . nativeElement . querySelector ( 'input' ) ;
277
+
278
+ fireEvent . focus ( input ) ;
279
+ fireEvent . input ( input , { target : { value : 'a' } } ) ;
280
+ fixture . detectChanges ( ) ;
281
+ fireEvent . input ( input , { target : { value : '' } } ) ;
282
+ fixture . detectChanges ( ) ;
283
+ fireEvent . input ( input , { target : { value : 'a' } } ) ;
284
+ fireEvent . blur ( input ) ;
285
+ fixture . detectChanges ( ) ;
286
+
287
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
288
+ } ) ;
289
+
290
+ it ( 'should unsubscribe in on destroy' , async ( ) => {
291
+ const { fixture } = await render ( ) ;
292
+ const input = fixture . nativeElement . querySelector ( 'input' ) ;
293
+
294
+ fixture . componentInstance . directive ?. ngOnDestroy ( ) ;
295
+ fireEvent . focus ( input ) ;
296
+ fireEvent . input ( input , { target : { value : 'a' } } ) ;
297
+ fixture . detectChanges ( ) ;
298
+ fireEvent . input ( input , { target : { value : '' } } ) ;
299
+ fireEvent . blur ( input ) ;
300
+ fixture . detectChanges ( ) ;
301
+
302
+ expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
303
+ } ) ;
304
+
305
+ it ( 'should show error message on submit' , async ( ) => {
306
+ const { fixture } = await render ( ) ;
307
+
308
+ const form = fixture . nativeElement . querySelector ( 'form' ) ;
309
+ fireEvent . submit ( form ) ;
91
310
92
- fixture . componentInstance . directive ?. ngOnDestroy ( ) ;
93
- await input . focus ( ) ;
94
- await input . setValue ( 'a' ) ;
95
- await input . setValue ( '' ) ;
96
- await input . blur ( ) ;
311
+ fixture . detectChanges ( ) ;
97
312
98
- expect ( fixture . nativeElement . textContent ) . not . toContain ( 'required' ) ;
313
+ expect ( fixture . nativeElement . textContent ) . toContain ( 'required' ) ;
314
+ } ) ;
99
315
} ) ;
100
316
} ) ;
0 commit comments