1
- import { async , TestBed } from '@angular/core/testing' ;
2
- import { Component , ViewChild } from '@angular/core' ;
1
+ import { async , TestBed , inject } from '@angular/core/testing' ;
2
+ import { Component , ViewChild , QueryList , ViewChildren } from '@angular/core' ;
3
3
import { By } from '@angular/platform-browser' ;
4
4
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' ;
5
- import { MatExpansionModule , MatAccordion , MatExpansionPanel } from './index' ;
5
+ import {
6
+ MatExpansionModule ,
7
+ MatAccordion ,
8
+ MatExpansionPanel ,
9
+ MatExpansionPanelHeader ,
10
+ } from './index' ;
11
+ import { dispatchKeyboardEvent } from '@angular/cdk/testing' ;
12
+ import { DOWN_ARROW , UP_ARROW , HOME , END } from '@angular/cdk/keycodes' ;
13
+ import { FocusMonitor } from '@angular/cdk/a11y' ;
6
14
7
15
8
16
describe ( 'MatAccordion' , ( ) => {
17
+ let focusMonitor : FocusMonitor ;
18
+
9
19
beforeEach ( async ( ( ) => {
10
20
TestBed . configureTestingModule ( {
11
21
imports : [
@@ -19,41 +29,53 @@ describe('MatAccordion', () => {
19
29
] ,
20
30
} ) ;
21
31
TestBed . compileComponents ( ) ;
32
+
33
+ inject ( [ FocusMonitor ] , ( fm : FocusMonitor ) => {
34
+ focusMonitor = fm ;
35
+ } ) ( ) ;
22
36
} ) ) ;
23
37
24
38
it ( 'should ensure only one item is expanded at a time' , ( ) => {
25
39
const fixture = TestBed . createComponent ( SetOfItems ) ;
40
+ fixture . detectChanges ( ) ;
41
+
26
42
const items = fixture . debugElement . queryAll ( By . css ( '.mat-expansion-panel' ) ) ;
43
+ const panelInstances = fixture . componentInstance . panels . toArray ( ) ;
27
44
28
- fixture . componentInstance . firstPanelExpanded = true ;
45
+ panelInstances [ 0 ] . expanded = true ;
29
46
fixture . detectChanges ( ) ;
30
47
expect ( items [ 0 ] . classes [ 'mat-expanded' ] ) . toBeTruthy ( ) ;
31
48
expect ( items [ 1 ] . classes [ 'mat-expanded' ] ) . toBeFalsy ( ) ;
32
49
33
- fixture . componentInstance . secondPanelExpanded = true ;
50
+ panelInstances [ 1 ] . expanded = true ;
34
51
fixture . detectChanges ( ) ;
35
52
expect ( items [ 0 ] . classes [ 'mat-expanded' ] ) . toBeFalsy ( ) ;
36
53
expect ( items [ 1 ] . classes [ 'mat-expanded' ] ) . toBeTruthy ( ) ;
37
54
} ) ;
38
55
39
56
it ( 'should allow multiple items to be expanded simultaneously' , ( ) => {
40
57
const fixture = TestBed . createComponent ( SetOfItems ) ;
58
+ fixture . componentInstance . multi = true ;
59
+ fixture . detectChanges ( ) ;
60
+
41
61
const panels = fixture . debugElement . queryAll ( By . css ( '.mat-expansion-panel' ) ) ;
62
+ const panelInstances = fixture . componentInstance . panels . toArray ( ) ;
42
63
43
- fixture . componentInstance . multi = true ;
44
- fixture . componentInstance . firstPanelExpanded = true ;
45
- fixture . componentInstance . secondPanelExpanded = true ;
64
+ panelInstances [ 0 ] . expanded = true ;
65
+ panelInstances [ 1 ] . expanded = true ;
46
66
fixture . detectChanges ( ) ;
47
67
expect ( panels [ 0 ] . classes [ 'mat-expanded' ] ) . toBeTruthy ( ) ;
48
68
expect ( panels [ 1 ] . classes [ 'mat-expanded' ] ) . toBeTruthy ( ) ;
49
69
} ) ;
50
70
51
71
it ( 'should expand or collapse all enabled items' , ( ) => {
52
72
const fixture = TestBed . createComponent ( SetOfItems ) ;
73
+ fixture . detectChanges ( ) ;
74
+
53
75
const panels = fixture . debugElement . queryAll ( By . css ( '.mat-expansion-panel' ) ) ;
54
76
55
77
fixture . componentInstance . multi = true ;
56
- fixture . componentInstance . secondPanelExpanded = true ;
78
+ fixture . componentInstance . panels . toArray ( ) [ 1 ] . expanded = true ;
57
79
fixture . detectChanges ( ) ;
58
80
expect ( panels [ 0 ] . classes [ 'mat-expanded' ] ) . toBeFalsy ( ) ;
59
81
expect ( panels [ 1 ] . classes [ 'mat-expanded' ] ) . toBeTruthy ( ) ;
@@ -71,10 +93,12 @@ describe('MatAccordion', () => {
71
93
72
94
it ( 'should not expand or collapse disabled items' , ( ) => {
73
95
const fixture = TestBed . createComponent ( SetOfItems ) ;
96
+ fixture . detectChanges ( ) ;
97
+
74
98
const panels = fixture . debugElement . queryAll ( By . css ( '.mat-expansion-panel' ) ) ;
75
99
76
100
fixture . componentInstance . multi = true ;
77
- fixture . componentInstance . secondPanelDisabled = true ;
101
+ fixture . componentInstance . panels . toArray ( ) [ 1 ] . disabled = true ;
78
102
fixture . detectChanges ( ) ;
79
103
fixture . componentInstance . accordion . openAll ( ) ;
80
104
fixture . detectChanges ( ) ;
@@ -110,27 +134,107 @@ describe('MatAccordion', () => {
110
134
expect ( panel . nativeElement . querySelector ( '.mat-expansion-indicator' ) )
111
135
. toBeFalsy ( 'Expected the expansion indicator to be removed.' ) ;
112
136
} ) ;
137
+
138
+ it ( 'should move focus to the next header when pressing the down arrow' , ( ) => {
139
+ const fixture = TestBed . createComponent ( SetOfItems ) ;
140
+ fixture . detectChanges ( ) ;
141
+
142
+ const headerElements = fixture . debugElement . queryAll ( By . css ( 'mat-expansion-panel-header' ) ) ;
143
+ const headers = fixture . componentInstance . headers . toArray ( ) ;
144
+
145
+ focusMonitor . focusVia ( headerElements [ 0 ] . nativeElement , 'keyboard' ) ;
146
+ headers . forEach ( header => spyOn ( header , 'focus' ) ) ;
147
+
148
+ // Stop at the second-last header so focus doesn't wrap around.
149
+ for ( let i = 0 ; i < headerElements . length - 1 ; i ++ ) {
150
+ dispatchKeyboardEvent ( headerElements [ i ] . nativeElement , 'keydown' , DOWN_ARROW ) ;
151
+ fixture . detectChanges ( ) ;
152
+ expect ( headers [ i + 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
153
+ }
154
+ } ) ;
155
+
156
+ it ( 'should move focus to the next header when pressing the up arrow' , ( ) => {
157
+ const fixture = TestBed . createComponent ( SetOfItems ) ;
158
+ fixture . detectChanges ( ) ;
159
+
160
+ const headerElements = fixture . debugElement . queryAll ( By . css ( 'mat-expansion-panel-header' ) ) ;
161
+ const headers = fixture . componentInstance . headers . toArray ( ) ;
162
+
163
+ focusMonitor . focusVia ( headerElements [ headerElements . length - 1 ] . nativeElement , 'keyboard' ) ;
164
+ headers . forEach ( header => spyOn ( header , 'focus' ) ) ;
165
+
166
+ // Stop before the first header
167
+ for ( let i = headers . length - 1 ; i > 0 ; i -- ) {
168
+ dispatchKeyboardEvent ( headerElements [ i ] . nativeElement , 'keydown' , UP_ARROW ) ;
169
+ fixture . detectChanges ( ) ;
170
+ expect ( headers [ i - 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
171
+ }
172
+ } ) ;
173
+
174
+ it ( 'should skip disabled items when moving focus with the keyboard' , ( ) => {
175
+ const fixture = TestBed . createComponent ( SetOfItems ) ;
176
+ fixture . detectChanges ( ) ;
177
+
178
+ const headerElements = fixture . debugElement . queryAll ( By . css ( 'mat-expansion-panel-header' ) ) ;
179
+ const panels = fixture . componentInstance . panels . toArray ( ) ;
180
+ const headers = fixture . componentInstance . headers . toArray ( ) ;
181
+
182
+ focusMonitor . focusVia ( headerElements [ 0 ] . nativeElement , 'keyboard' ) ;
183
+ headers . forEach ( header => spyOn ( header , 'focus' ) ) ;
184
+ panels [ 1 ] . disabled = true ;
185
+ fixture . detectChanges ( ) ;
186
+
187
+ dispatchKeyboardEvent ( headerElements [ 0 ] . nativeElement , 'keydown' , DOWN_ARROW ) ;
188
+ fixture . detectChanges ( ) ;
189
+
190
+ expect ( headers [ 1 ] . focus ) . not . toHaveBeenCalled ( ) ;
191
+ expect ( headers [ 2 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
192
+ } ) ;
193
+
194
+ it ( 'should focus the first header when pressing the home key' , ( ) => {
195
+ const fixture = TestBed . createComponent ( SetOfItems ) ;
196
+ fixture . detectChanges ( ) ;
197
+
198
+ const headerElements = fixture . debugElement . queryAll ( By . css ( 'mat-expansion-panel-header' ) ) ;
199
+ const headers = fixture . componentInstance . headers . toArray ( ) ;
200
+
201
+ headers . forEach ( header => spyOn ( header , 'focus' ) ) ;
202
+ dispatchKeyboardEvent ( headerElements [ headerElements . length - 1 ] . nativeElement , 'keydown' , HOME ) ;
203
+ fixture . detectChanges ( ) ;
204
+
205
+ expect ( headers [ 0 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
206
+ } ) ;
207
+
208
+ it ( 'should focus the last header when pressing the end key' , ( ) => {
209
+ const fixture = TestBed . createComponent ( SetOfItems ) ;
210
+ fixture . detectChanges ( ) ;
211
+
212
+ const headerElements = fixture . debugElement . queryAll ( By . css ( 'mat-expansion-panel-header' ) ) ;
213
+ const headers = fixture . componentInstance . headers . toArray ( ) ;
214
+
215
+ headers . forEach ( header => spyOn ( header , 'focus' ) ) ;
216
+ dispatchKeyboardEvent ( headerElements [ 0 ] . nativeElement , 'keydown' , END ) ;
217
+ fixture . detectChanges ( ) ;
218
+
219
+ expect ( headers [ headers . length - 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
220
+ } ) ;
221
+
113
222
} ) ;
114
223
115
224
116
225
@Component ( { template : `
117
226
<mat-accordion [multi]="multi">
118
- <mat-expansion-panel [expanded]="firstPanelExpanded">
119
- <mat-expansion-panel-header>Summary</mat-expansion-panel-header>
120
- <p>Content</p>
121
- </mat-expansion-panel>
122
- <mat-expansion-panel [expanded]="secondPanelExpanded" [disabled]="secondPanelDisabled">
123
- <mat-expansion-panel-header>Summary</mat-expansion-panel-header>
227
+ <mat-expansion-panel *ngFor="let i of [0, 1, 2, 3]">
228
+ <mat-expansion-panel-header>Summary {{i}}</mat-expansion-panel-header>
124
229
<p>Content</p>
125
230
</mat-expansion-panel>
126
231
</mat-accordion>` } )
127
232
class SetOfItems {
128
233
@ViewChild ( MatAccordion ) accordion : MatAccordion ;
234
+ @ViewChildren ( MatExpansionPanel ) panels : QueryList < MatExpansionPanel > ;
235
+ @ViewChildren ( MatExpansionPanelHeader ) headers : QueryList < MatExpansionPanelHeader > ;
129
236
130
237
multi : boolean = false ;
131
- firstPanelExpanded : boolean = false ;
132
- secondPanelExpanded : boolean = false ;
133
- secondPanelDisabled : boolean = false ;
134
238
}
135
239
136
240
@Component ( { template : `
0 commit comments