1
1
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
import React from 'react' ;
4
+ import { waitFor } from '@testing-library/react' ;
4
5
5
6
import AppLayout from '../../../lib/components/app-layout' ;
6
7
import { AppLayoutWrapper } from '../../../lib/components/test-utils/dom' ;
@@ -12,13 +13,15 @@ jest.mock('@cloudscape-design/component-toolkit', () => ({
12
13
} ) ) ;
13
14
14
15
describeEachAppLayout ( ( { theme, size } ) => {
15
- test ( 'Default state' , ( ) => {
16
+ test ( 'Default state' , async ( ) => {
16
17
const { wrapper } = renderComponent ( < AppLayout /> ) ;
17
18
18
19
expect ( wrapper . findNavigationToggle ( ) ) . toBeTruthy ( ) ;
19
20
expect ( wrapper . findNavigation ( ) ) . toBeTruthy ( ) ;
20
21
expect ( wrapper . findNavigationClose ( ) ) . toBeTruthy ( ) ;
21
- expect ( wrapper . findToolsToggle ( ) ) . toBeTruthy ( ) ;
22
+ await waitFor ( ( ) => {
23
+ expect ( wrapper . findToolsToggle ( ) ) . toBeTruthy ( ) ;
24
+ } ) ;
22
25
expect ( wrapper . findTools ( ) ) . toBeTruthy ( ) ;
23
26
expect ( wrapper . findToolsClose ( ) ) . toBeTruthy ( ) ;
24
27
expect ( wrapper . findContentRegion ( ) ) . toBeTruthy ( ) ;
@@ -38,9 +41,11 @@ describeEachAppLayout(({ theme, size }) => {
38
41
expect ( wrapper . findBreadcrumbs ( ) ) . toBeTruthy ( ) ;
39
42
} ) ;
40
43
41
- test ( 'should not find tools slot as findActiveDrawer utility' , ( ) => {
44
+ test ( 'should not find tools slot as findActiveDrawer utility' , async ( ) => {
42
45
const { wrapper } = renderComponent ( < AppLayout toolsOpen = { true } tools = "test content" /> ) ;
43
- expect ( wrapper . findTools ( ) ! . getElement ( ) ) . toHaveTextContent ( 'test content' ) ;
46
+ await waitFor ( ( ) => {
47
+ expect ( wrapper . findTools ( ) ! . getElement ( ) ) . toHaveTextContent ( 'test content' ) ;
48
+ } ) ;
44
49
expect ( wrapper . findActiveDrawer ( ) ) . toBeFalsy ( ) ;
45
50
} ) ;
46
51
@@ -80,52 +85,70 @@ describeEachAppLayout(({ theme, size }) => {
80
85
findClose,
81
86
} ) => {
82
87
describe ( `${ openProp } prop` , ( ) => {
83
- test ( `Should call handler once on open when toggle is clicked` , ( ) => {
88
+ const waitForAppLayoutLoaded = ( wrapper : AppLayoutWrapper ) => {
89
+ return waitFor ( ( ) => {
90
+ if ( openProp === 'navigationOpen' ) {
91
+ expect ( wrapper . findNavigationToggle ( ) ) . toBeTruthy ( ) ;
92
+ } else {
93
+ expect ( wrapper . findToolsToggle ( ) ) . toBeTruthy ( ) ;
94
+ }
95
+ } ) ;
96
+ } ;
97
+ test ( `Should call handler once on open when toggle is clicked` , async ( ) => {
84
98
const onToggle = jest . fn ( ) ;
85
99
const props = {
86
100
[ openProp ] : false ,
87
101
[ handler ] : onToggle ,
88
102
} ;
89
103
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
90
104
105
+ await waitForAppLayoutLoaded ( wrapper ) ;
106
+
91
107
findToggle ( wrapper ) . click ( ) ;
92
108
expect ( onToggle ) . toHaveBeenCalledTimes ( size === 'mobile' ? expectedCallsOnMobileToggle : 1 ) ;
93
109
expect ( onToggle ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { detail : { open : true } } ) ) ;
94
110
} ) ;
95
111
96
- test ( `Should call handler once on open when span inside toggle is clicked` , ( ) => {
112
+ test ( `Should call handler once on open when span inside toggle is clicked` , async ( ) => {
97
113
const onToggle = jest . fn ( ) ;
98
114
const props = {
99
115
[ openProp ] : false ,
100
116
[ handler ] : onToggle ,
101
117
} ;
102
118
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
103
119
120
+ await waitForAppLayoutLoaded ( wrapper ) ;
121
+
104
122
// Chrome bubbles up events from specific elements inside <button>s.
105
123
findToggle ( wrapper ) . find ( 'span' ) ! . click ( ) ;
106
124
expect ( onToggle ) . toHaveBeenCalledTimes ( size === 'mobile' ? expectedCallsOnMobileToggle : 1 ) ;
107
125
expect ( onToggle ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { detail : { open : true } } ) ) ;
108
126
} ) ;
109
127
110
- test ( `Should call handler once on close` , ( ) => {
128
+ test ( `Should call handler once on close` , async ( ) => {
111
129
const onToggle = jest . fn ( ) ;
112
130
const props = {
113
131
[ openProp ] : true ,
114
132
[ handler ] : onToggle ,
115
133
} ;
116
134
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
117
135
136
+ await waitForAppLayoutLoaded ( wrapper ) ;
137
+
118
138
findClose ( wrapper ) . click ( ) ;
119
139
expect ( onToggle ) . toHaveBeenCalledTimes ( size === 'mobile' ? expectedCallsOnMobileToggle : 1 ) ;
120
140
expect ( onToggle ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { detail : { open : false } } ) ) ;
121
141
} ) ;
122
142
123
- test ( 'Renders two landmarks in closed state' , ( ) => {
143
+ test ( 'Renders two landmarks in closed state' , async ( ) => {
124
144
const props = {
125
145
[ openProp ] : false ,
126
146
[ handler ] : ( ) => { } ,
127
147
} ;
128
148
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
149
+
150
+ await waitForAppLayoutLoaded ( wrapper ) ;
151
+
129
152
const landmarks = findLandmarks ( wrapper ) ;
130
153
expect ( landmarks ) . toHaveLength ( 2 ) ;
131
154
@@ -147,12 +170,15 @@ describeEachAppLayout(({ theme, size }) => {
147
170
}
148
171
} ) ;
149
172
150
- test ( 'Renders two landmarks in open state' , ( ) => {
173
+ test ( 'Renders two landmarks in open state' , async ( ) => {
151
174
const props = {
152
175
[ openProp ] : true ,
153
176
[ handler ] : ( ) => { } ,
154
177
} ;
155
178
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
179
+
180
+ await waitForAppLayoutLoaded ( wrapper ) ;
181
+
156
182
const landmarks = findLandmarks ( wrapper ) ;
157
183
expect ( landmarks ) . toHaveLength ( 2 ) ;
158
184
const toggleElement = findToggle ( wrapper ) . getElement ( ) ;
@@ -173,26 +199,30 @@ describeEachAppLayout(({ theme, size }) => {
173
199
}
174
200
} ) ;
175
201
176
- test ( 'Renders aria-expanded only on toggle' , ( ) => {
202
+ test ( 'Renders aria-expanded only on toggle' , async ( ) => {
177
203
const props = {
178
204
[ openProp ] : false ,
179
205
[ handler ] : ( ) => { } ,
180
206
} ;
181
207
182
208
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
209
+
210
+ await waitForAppLayoutLoaded ( wrapper ) ;
211
+
183
212
expect ( findToggle ( wrapper ) . getElement ( ) ) . toHaveAttribute ( 'aria-expanded' , 'false' ) ;
184
213
expect ( findToggle ( wrapper ) . getElement ( ) ) . toHaveAttribute ( 'aria-haspopup' , 'true' ) ;
185
214
expect ( findClose ( wrapper ) . getElement ( ) ) . not . toHaveAttribute ( 'aria-expanded' ) ;
186
215
expect ( findClose ( wrapper ) . getElement ( ) ) . not . toHaveAttribute ( 'aria-haspopup' ) ;
187
216
} ) ;
188
217
189
- test ( 'Does not add a label to the toggle and landmark when they are not defined' , ( ) => {
218
+ test ( 'Does not add a label to the toggle and landmark when they are not defined' , async ( ) => {
190
219
const { wrapper } = renderComponent ( < AppLayout /> ) ;
220
+ await waitForAppLayoutLoaded ( wrapper ) ;
191
221
expect ( findToggle ( wrapper ) . getElement ( ) ) . not . toHaveAttribute ( 'aria-label' ) ;
192
222
expect ( findLandmarks ( wrapper ) [ 0 ] . getElement ( ) ) . not . toHaveAttribute ( 'aria-label' ) ;
193
223
} ) ;
194
224
195
- test ( 'Adds labels to toggle button and landmark when defined' , ( ) => {
225
+ test ( 'Adds labels to toggle button and landmark when defined' , async ( ) => {
196
226
const labels = {
197
227
navigationToggle : 'toggle' ,
198
228
toolsToggle : 'toggle' ,
@@ -201,34 +231,42 @@ describeEachAppLayout(({ theme, size }) => {
201
231
} ;
202
232
203
233
const { wrapper } = renderComponent ( < AppLayout ariaLabels = { labels } /> ) ;
234
+ await waitForAppLayoutLoaded ( wrapper ) ;
204
235
expect ( findToggle ( wrapper ) . getElement ( ) ) . toHaveAttribute ( 'aria-label' , 'toggle' ) ;
205
236
expect ( findLandmarks ( wrapper ) [ theme === 'refresh-toolbar' ? 1 : 0 ] . getElement ( ) ) . toHaveAttribute (
206
237
'aria-label' ,
207
238
'landmark'
208
239
) ;
209
240
} ) ;
210
241
211
- test ( 'Close button does have a label if it is defined' , ( ) => {
242
+ test ( 'Close button does have a label if it is defined' , async ( ) => {
212
243
const props = { [ openProp ] : true , [ handler ] : ( ) => { } } ;
213
244
const labels = {
214
245
navigationClose : 'close label' ,
215
246
toolsClose : 'close label' ,
216
247
} ;
217
248
const { wrapper } = renderComponent ( < AppLayout { ...props } ariaLabels = { labels } /> ) ;
218
249
250
+ await waitForAppLayoutLoaded ( wrapper ) ;
251
+
219
252
expect ( findClose ( wrapper ) . getElement ( ) ) . toHaveAttribute ( 'aria-label' , 'close label' ) ;
220
253
} ) ;
221
254
222
- test ( 'Close button does not render a label if is not defined' , ( ) => {
255
+ test ( 'Close button does not render a label if is not defined' , async ( ) => {
223
256
const props = { [ openProp ] : true , [ handler ] : ( ) => { } } ;
224
257
const { wrapper } = renderComponent ( < AppLayout { ...props } /> ) ;
225
258
259
+ await waitForAppLayoutLoaded ( wrapper ) ;
260
+
226
261
expect ( findClose ( wrapper ) . getElement ( ) ) . not . toHaveAttribute ( 'aria-label' ) ;
227
262
} ) ;
228
263
229
- test ( 'Opens and closes drawer in uncontrolled mode' , ( ) => {
264
+ test ( 'Opens and closes drawer in uncontrolled mode' , async ( ) => {
230
265
// use content type with initial closed state for all drawers
231
266
const { wrapper } = renderComponent ( < AppLayout contentType = "form" /> ) ;
267
+
268
+ await waitForAppLayoutLoaded ( wrapper ) ;
269
+
232
270
expect ( findOpenElement ( wrapper ) ) . toBeFalsy ( ) ;
233
271
234
272
findToggle ( wrapper ) . click ( ) ;
@@ -238,10 +276,12 @@ describeEachAppLayout(({ theme, size }) => {
238
276
expect ( findOpenElement ( wrapper ) ) . toBeFalsy ( ) ;
239
277
} ) ;
240
278
241
- test ( 'Moves focus between open and close buttons' , ( ) => {
279
+ test ( 'Moves focus between open and close buttons' , async ( ) => {
242
280
// use content type with initial closed state for all drawers
243
281
const { wrapper } = renderComponent ( < AppLayout contentType = "form" /> ) ;
244
282
283
+ await waitForAppLayoutLoaded ( wrapper ) ;
284
+
245
285
findToggle ( wrapper ) . click ( ) ;
246
286
expect ( findClose ( wrapper ) . getElement ( ) ) . toBe ( document . activeElement ) ;
247
287
@@ -263,28 +303,33 @@ describeEachAppLayout(({ theme, size }) => {
263
303
// Drawers tests
264
304
265
305
describe ( `Drawers` , ( ) => {
266
- test ( `Should call handler once on open when toggle is clicked` , ( ) => {
306
+ test ( `Should call handler once on open when toggle is clicked` , async ( ) => {
267
307
const onChange = jest . fn ( ) ;
268
308
const { wrapper } = renderComponent (
269
309
< AppLayout drawers = { [ testDrawer ] } onDrawerChange = { event => onChange ( event . detail ) } />
270
310
) ;
311
+ await waitFor ( ( ) => {
312
+ expect ( wrapper . findDrawerTriggerById ( 'security' ) ) . toBeTruthy ( ) ;
313
+ } ) ;
271
314
wrapper . findDrawerTriggerById ( 'security' ) ! . click ( ) ;
272
315
expect ( onChange ) . toHaveBeenCalledWith ( { activeDrawerId : 'security' } ) ;
273
316
} ) ;
274
317
275
- test ( `Should call handler once on open when span inside toggle is clicked` , ( ) => {
318
+ test ( `Should call handler once on open when span inside toggle is clicked` , async ( ) => {
276
319
const onChange = jest . fn ( ) ;
277
320
const { wrapper } = renderComponent (
278
321
< AppLayout drawers = { [ testDrawer ] } onDrawerChange = { event => onChange ( event . detail ) } />
279
322
) ;
280
-
323
+ await waitFor ( ( ) => {
324
+ expect ( wrapper . findDrawerTriggerById ( 'security' ) ) . toBeTruthy ( ) ;
325
+ } ) ;
281
326
// Chrome bubbles up events from specific elements inside <button>s.
282
327
wrapper . findDrawerTriggerById ( 'security' ) ! . find ( 'span' ) ! . click ( ) ;
283
328
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
284
329
expect ( onChange ) . toHaveBeenCalledWith ( { activeDrawerId : 'security' } ) ;
285
330
} ) ;
286
331
287
- test ( `Should call handler once on close` , ( ) => {
332
+ test ( `Should call handler once on close` , async ( ) => {
288
333
const onChange = jest . fn ( ) ;
289
334
const { wrapper } = renderComponent (
290
335
< AppLayout
@@ -293,15 +338,21 @@ describeEachAppLayout(({ theme, size }) => {
293
338
onDrawerChange = { event => onChange ( event . detail ) }
294
339
/>
295
340
) ;
296
-
341
+ await waitFor ( ( ) => {
342
+ expect ( wrapper . findActiveDrawerCloseButton ( ) ) . toBeTruthy ( ) ;
343
+ } ) ;
297
344
wrapper . findActiveDrawerCloseButton ( ) ! . click ( ) ;
298
345
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
299
346
expect ( onChange ) . toHaveBeenCalledWith ( { activeDrawerId : null } ) ;
300
347
} ) ;
301
348
302
- test ( 'Renders aria-expanded only on toggle' , ( ) => {
349
+ test ( 'Renders aria-expanded only on toggle' , async ( ) => {
303
350
const { wrapper } = renderComponent ( < AppLayout drawers = { [ testDrawer ] } /> ) ;
304
351
352
+ await waitFor ( ( ) => {
353
+ expect ( wrapper . findDrawerTriggerById ( 'security' ) ) . toBeTruthy ( ) ;
354
+ } ) ;
355
+
305
356
const drawerTrigger = wrapper . findDrawerTriggerById ( 'security' ) ! ;
306
357
expect ( drawerTrigger . getElement ( ) ) . toHaveAttribute ( 'aria-expanded' , 'false' ) ;
307
358
expect ( drawerTrigger . getElement ( ) ) . toHaveAttribute ( 'aria-haspopup' , 'true' ) ;
@@ -312,30 +363,42 @@ describeEachAppLayout(({ theme, size }) => {
312
363
expect ( wrapper . findActiveDrawerCloseButton ( ) ! . getElement ( ) ) . not . toHaveAttribute ( 'aria-haspopup' ) ;
313
364
} ) ;
314
365
315
- test ( 'Close button does have a label if it is defined' , ( ) => {
366
+ test ( 'Close button does have a label if it is defined' , async ( ) => {
316
367
const { wrapper } = renderComponent (
317
368
< AppLayout activeDrawerId = { testDrawer . id } drawers = { [ testDrawer ] } onDrawerChange = { ( ) => { } } />
318
369
) ;
319
370
371
+ await waitFor ( ( ) => {
372
+ expect ( wrapper . findActiveDrawerCloseButton ( ) ) . toBeTruthy ( ) ;
373
+ } ) ;
374
+
320
375
expect ( wrapper . findActiveDrawerCloseButton ( ) ! . getElement ( ) ) . toHaveAttribute (
321
376
'aria-label' ,
322
377
'Security close button'
323
378
) ;
324
379
} ) ;
325
380
326
- test ( 'Close button does not render a label if is not defined' , ( ) => {
381
+ test ( 'Close button does not render a label if is not defined' , async ( ) => {
327
382
const { wrapper } = renderComponent (
328
383
< AppLayout activeDrawerId = { testDrawerWithoutLabels . id } drawers = { [ testDrawerWithoutLabels ] } />
329
384
) ;
330
385
386
+ await waitFor ( ( ) => {
387
+ expect ( wrapper . findActiveDrawerCloseButton ( ) ) . toBeTruthy ( ) ;
388
+ } ) ;
389
+
331
390
expect ( wrapper . findActiveDrawerCloseButton ( ) ! . getElement ( ) ) . not . toHaveAttribute ( 'aria-label' ) ;
332
391
} ) ;
333
392
334
- test ( 'Opens and closes drawer in uncontrolled mode' , ( ) => {
393
+ test ( 'Opens and closes drawer in uncontrolled mode' , async ( ) => {
335
394
// use content type with initial closed state for all drawers
336
395
const { wrapper } = renderComponent ( < AppLayout drawers = { [ testDrawer ] } /> ) ;
337
396
expect ( wrapper . findActiveDrawer ( ) ) . toBeNull ( ) ;
338
397
398
+ await waitFor ( ( ) => {
399
+ expect ( wrapper . findDrawerTriggerById ( 'security' ) ) . toBeTruthy ( ) ;
400
+ } ) ;
401
+
339
402
wrapper . findDrawerTriggerById ( 'security' ) ! . find ( 'span' ) ! . click ( ) ;
340
403
expect ( wrapper . findActiveDrawer ( ) ) . not . toBeNull ( ) ;
341
404
0 commit comments