@@ -16,7 +16,8 @@ import {
1616 watchEffect ,
1717 onUnmounted ,
1818 onErrorCaptured ,
19- shallowRef
19+ shallowRef ,
20+ Fragment
2021} from '@vue/runtime-test'
2122import { createApp } from 'vue'
2223
@@ -1257,4 +1258,146 @@ describe('Suspense', () => {
12571258 `A component with async setup() must be nested in a <Suspense>`
12581259 ) . toHaveBeenWarned ( )
12591260 } )
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+ } )
12601403} )
0 commit comments