]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(suspense): display current branch if no fallback is provided
authorEduardo San Martin Morote <posva13@gmail.com>
Tue, 22 Jun 2021 16:31:36 +0000 (18:31 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 22 Jun 2021 16:39:02 +0000 (18:39 +0200)
Fix #3986

packages/runtime-core/__tests__/components/Suspense.spec.ts
packages/runtime-core/src/components/Suspense.ts

index 421bc0a8e963b00ef04fda3c032a413174952519..c6d7be849fcb09fa52811beddb6971dd7d4fc0cd 100644 (file)
@@ -69,6 +69,32 @@ describe('Suspense', () => {
     expect(serializeInner(root)).toBe(`<div>async</div>`)
   })
 
+  test('fallback content', async () => {
+    const Async = defineAsyncComponent({
+      render() {
+        return h('div', 'async')
+      }
+    })
+
+    const Comp = {
+      setup() {
+        return () =>
+          h(Suspense, null, {
+            default: h(Async),
+            fallback: h('div', 'fallback')
+          })
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(`<div>fallback</div>`)
+
+    await Promise.all(deps)
+    await nextTick()
+    expect(serializeInner(root)).toBe(`<div>async</div>`)
+  })
+
   test('emits events', async () => {
     const Async = defineAsyncComponent({
       render() {
@@ -709,7 +735,7 @@ describe('Suspense', () => {
       <div v-if="errorMessage">{{ errorMessage }}</div>
       <Suspense v-else>
         <div>
-          <Async />     
+          <Async />
         </div>
         <template #fallback>
           <div>fallback</div>
@@ -983,6 +1009,66 @@ describe('Suspense', () => {
     expect(serializeInner(root)).toBe(`<div>foo<div>foo nested</div></div>`)
   })
 
+  test('display previous branch when timeout + no fallback slot is provided', async () => {
+    const toggle = ref(false)
+    let resolve = () => {}
+    let promise: Promise<void>
+    function createPromise() {
+      promise = new Promise<void>(r => {
+        resolve = r
+      })
+
+      return promise
+    }
+
+    const Foo = {
+      async setup() {
+        await createPromise()
+        return () => h('div', ['foo'])
+      }
+    }
+
+    const onPending = jest.fn()
+    const onFallback = jest.fn()
+    const onResolve = jest.fn()
+
+    const Comp = {
+      setup() {
+        return () =>
+          h(
+            Suspense,
+            { timeout: 0, onPending, onFallback, onResolve },
+            {
+              default: toggle.value ? h(Foo) : 'other'
+            }
+          )
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(`other`)
+    expect(onPending).toHaveBeenCalledTimes(0)
+    expect(onFallback).toHaveBeenCalledTimes(0)
+    expect(onResolve).toHaveBeenCalledTimes(1)
+
+    toggle.value = true
+    await nextTick()
+    expect(serializeInner(root)).toBe(`other`)
+    expect(onPending).toHaveBeenCalledTimes(1)
+    expect(onFallback).toHaveBeenCalledTimes(0)
+    expect(onResolve).toHaveBeenCalledTimes(1)
+
+    resolve()
+    await promise!
+    await nextTick()
+    await nextTick()
+    expect(serializeInner(root)).toBe(`<div>foo</div>`)
+    expect(onPending).toHaveBeenCalledTimes(1)
+    expect(onFallback).toHaveBeenCalledTimes(0)
+    expect(onResolve).toHaveBeenCalledTimes(2)
+  })
+
   test('branch switch to 3rd branch before resolve', async () => {
     const calls: string[] = []
 
index 85a2d1755bdd9a1a054b20019fb6a4ce68c3e766..b004a6ace5a460b380ba9082d1170922cb84e4f0 100644 (file)
@@ -4,6 +4,7 @@ import {
   VNodeProps,
   isSameVNodeType,
   openBlock,
+  Comment,
   closeBlock,
   currentBlock,
   createVNode
@@ -516,7 +517,8 @@ function createSuspenseBoundary(
     },
 
     fallback(fallbackVNode) {
-      if (!suspense.pendingBranch) {
+      // avoid displaying the fallback/emitting node if there isn't any
+      if (!suspense.pendingBranch || fallbackVNode.type === Comment) {
         return
       }