@@ -16,7 +16,8 @@ import {
16
16
watchEffect ,
17
17
onUnmounted ,
18
18
onErrorCaptured ,
19
- shallowRef
19
+ shallowRef ,
20
+ Fragment
20
21
} from '@vue/runtime-test'
21
22
import { createApp } from 'vue'
22
23
@@ -1257,4 +1258,146 @@ describe('Suspense', () => {
1257
1258
`A component with async setup() must be nested in a <Suspense>`
1258
1259
) . toHaveBeenWarned ( )
1259
1260
} )
1261
+
1262
+ test ( 'nested suspense with suspensible' , async ( ) => {
1263
+ const calls : string [ ] = [ ]
1264
+ let expected = ''
1265
+
1266
+ const InnerA = defineAsyncComponent (
1267
+ {
1268
+ setup : ( ) => {
1269
+ calls . push ( 'innerA created' )
1270
+ onMounted ( ( ) => {
1271
+ calls . push ( 'innerA mounted' )
1272
+ } )
1273
+ return ( ) => h ( 'div' , 'innerA' )
1274
+ }
1275
+ } ,
1276
+ 10
1277
+ )
1278
+
1279
+ const InnerB = defineAsyncComponent (
1280
+ {
1281
+ setup : ( ) => {
1282
+ calls . push ( 'innerB created' )
1283
+ onMounted ( ( ) => {
1284
+ calls . push ( 'innerB mounted' )
1285
+ } )
1286
+ return ( ) => h ( 'div' , 'innerB' )
1287
+ }
1288
+ } ,
1289
+ 10
1290
+ )
1291
+
1292
+ const OuterA = defineAsyncComponent (
1293
+ {
1294
+ setup : ( _ , { slots } : any ) => {
1295
+ calls . push ( 'outerA created' )
1296
+ onMounted ( ( ) => {
1297
+ calls . push ( 'outerA mounted' )
1298
+ } )
1299
+ return ( ) =>
1300
+ h ( Fragment , null , [ h ( 'div' , 'outerA' ) , slots . default ?.( ) ] )
1301
+ }
1302
+ } ,
1303
+ 5
1304
+ )
1305
+
1306
+ const OuterB = defineAsyncComponent (
1307
+ {
1308
+ setup : ( _ , { slots } : any ) => {
1309
+ calls . push ( 'outerB created' )
1310
+ onMounted ( ( ) => {
1311
+ calls . push ( 'outerB mounted' )
1312
+ } )
1313
+ return ( ) =>
1314
+ h ( Fragment , null , [ h ( 'div' , 'outerB' ) , slots . default ?.( ) ] )
1315
+ }
1316
+ } ,
1317
+ 5
1318
+ )
1319
+
1320
+ const outerToggle = ref ( false )
1321
+ const innerToggle = ref ( false )
1322
+
1323
+ /**
1324
+ * <Suspense>
1325
+ * <component :is="outerToggle ? outerB : outerA">
1326
+ * <Suspense suspensible>
1327
+ * <component :is="innerToggle ? innerB : innerA" />
1328
+ * </Suspense>
1329
+ * </component>
1330
+ * </Suspense>
1331
+ */
1332
+ const Comp = {
1333
+ setup ( ) {
1334
+ return ( ) =>
1335
+ h ( Suspense , null , {
1336
+ default : [
1337
+ h ( outerToggle . value ? OuterB : OuterA , null , {
1338
+ default : ( ) => h ( Suspense , { suspensible : true } , {
1339
+ default : h ( innerToggle . value ? InnerB : InnerA )
1340
+ } )
1341
+ } )
1342
+ ] ,
1343
+ fallback : h ( 'div' , 'fallback outer' )
1344
+ } )
1345
+ }
1346
+ }
1347
+
1348
+ expected = `<div>fallback outer</div>`
1349
+ const root = nodeOps . createElement ( 'div' )
1350
+ render ( h ( Comp ) , root )
1351
+ expect ( serializeInner ( root ) ) . toBe ( expected )
1352
+
1353
+ // mount outer component
1354
+ await Promise . all ( deps )
1355
+ await nextTick ( )
1356
+
1357
+ expect ( serializeInner ( root ) ) . toBe ( expected )
1358
+ expect ( calls ) . toEqual ( [ `outerA created` ] )
1359
+
1360
+ // mount inner component
1361
+ await Promise . all ( deps )
1362
+ await nextTick ( )
1363
+ expected = `<div>outerA</div><div>innerA</div>`
1364
+ expect ( serializeInner ( root ) ) . toBe ( expected )
1365
+
1366
+ expect ( calls ) . toEqual ( [
1367
+ 'outerA created' ,
1368
+ 'innerA created' ,
1369
+ 'outerA mounted' ,
1370
+ 'innerA mounted'
1371
+ ] )
1372
+
1373
+ // toggle outer component
1374
+ calls . length = 0
1375
+ deps . length = 0
1376
+ outerToggle . value = true
1377
+ await nextTick ( )
1378
+
1379
+ await Promise . all ( deps )
1380
+ await nextTick ( )
1381
+ expect ( serializeInner ( root ) ) . toBe ( expected ) // expect not change
1382
+
1383
+ await Promise . all ( deps )
1384
+ await nextTick ( )
1385
+ expected = `<div>outerB</div><div>innerA</div>`
1386
+ expect ( serializeInner ( root ) ) . toBe ( expected )
1387
+ expect ( calls ) . toContain ( 'outerB mounted' )
1388
+ expect ( calls ) . toContain ( 'innerA mounted' )
1389
+
1390
+ // toggle inner component
1391
+ calls . length = 0
1392
+ deps . length = 0
1393
+ innerToggle . value = true
1394
+ await nextTick ( )
1395
+ expect ( serializeInner ( root ) ) . toBe ( expected ) // expect not change
1396
+
1397
+ await Promise . all ( deps )
1398
+ await nextTick ( )
1399
+ expected = `<div>outerB</div><div>innerB</div>`
1400
+ expect ( serializeInner ( root ) ) . toBe ( expected )
1401
+ expect ( calls ) . toContain ( 'innerB mounted' )
1402
+ } )
1260
1403
} )
0 commit comments