]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: more comprehesive combined suspense test
authorEvan You <yyx990803@gmail.com>
Thu, 12 Sep 2019 14:31:56 +0000 (10:31 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 12 Sep 2019 14:31:56 +0000 (10:31 -0400)
packages/runtime-core/__tests__/rendererSuspense.spec.ts
packages/runtime-core/src/createRenderer.ts

index b81d3844b7a52ef4642674cbf8245cc7604d1550..5470d56a0d2309a4648838dd4ca037365692e384 100644 (file)
@@ -35,51 +35,6 @@ describe('renderer: suspense', () => {
     }
   }
 
-  it('basic usage (nested + multiple deps)', async () => {
-    const msg = ref('hello')
-
-    const AsyncChild = createAsyncComponent({
-      setup(props: { msg: string }) {
-        return () => h('div', props.msg)
-      }
-    })
-
-    const AsyncChild2 = createAsyncComponent(
-      {
-        setup(props: { msg: string }) {
-          return () => h('div', props.msg)
-        }
-      },
-      10
-    )
-
-    const Mid = {
-      setup() {
-        return () =>
-          h(AsyncChild, {
-            msg: msg.value
-          })
-      }
-    }
-
-    const Comp = {
-      setup() {
-        return () =>
-          h(Suspense, [msg.value, h(Mid), h(AsyncChild2, { msg: 'child 2' })])
-      }
-    }
-
-    const root = nodeOps.createElement('div')
-    render(h(Comp), root)
-    expect(serializeInner(root)).toBe(`<!---->`)
-
-    await Promise.all(deps)
-    await nextTick()
-    expect(serializeInner(root)).toBe(
-      `<!---->hello<div>hello</div><div>child 2</div><!---->`
-    )
-  })
-
   test('fallback content', async () => {
     const Async = createAsyncComponent({
       render() {
@@ -578,6 +533,104 @@ describe('renderer: suspense', () => {
     expect(serializeInner(root)).toBe(`<div>oops</div>`)
   })
 
+  it('combined usage (nested async + nested suspense + multiple deps)', async () => {
+    const msg = ref('nested msg')
+
+    const AsyncChildWithSuspense = createAsyncComponent({
+      setup(props: { msg: string }) {
+        return () =>
+          h(Suspense, null, {
+            default: h(AsyncInsideNestedSuspense, { msg: props.msg }),
+            fallback: h('div', 'nested fallback')
+          })
+      }
+    })
+
+    const AsyncInsideNestedSuspense = createAsyncComponent(
+      {
+        setup(props: { msg: string }) {
+          return () => h('div', props.msg)
+        }
+      },
+      20
+    )
+
+    const AsyncChildParent = createAsyncComponent({
+      setup(props: { msg: string }) {
+        return () => h(NestedAsyncChild, { msg: props.msg })
+      }
+    })
+
+    const NestedAsyncChild = createAsyncComponent(
+      {
+        setup(props: { msg: string }) {
+          return () => h('div', props.msg)
+        }
+      },
+      10
+    )
+
+    const MiddleComponent = {
+      setup() {
+        return () =>
+          h(AsyncChildWithSuspense, {
+            msg: msg.value
+          })
+      }
+    }
+
+    const Comp = {
+      setup() {
+        return () =>
+          h(Suspense, null, {
+            default: [
+              h(MiddleComponent),
+              h(AsyncChildParent, {
+                msg: 'root async'
+              })
+            ],
+            fallback: h('div', 'root fallback')
+          })
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(`<div>root fallback</div>`)
+
+    /**
+     * <Root>
+     *   <Suspense>
+     *     <MiddleComponent>
+     *       <AsyncChildWithSuspense> (0)
+     *         <Suspense>
+     *           <AsyncInsideNestedSuspense> (2)
+     *     <AsyncChildParent> (1)
+     *       <NestedAsyncChild> (3)
+     */
+
+    // both top level async deps resolved, but there is another nested dep
+    // so should still be in fallback state
+    await Promise.all([deps[0], deps[1]])
+    await nextTick()
+    expect(serializeInner(root)).toBe(`<div>root fallback</div>`)
+
+    // root suspense all deps resolved. should show root content now
+    // with nested suspense showing fallback content
+    await deps[3]
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<!----><div>nested fallback</div><div>root async</div><!---->`
+    )
+
+    // all deps resolved, nested suspense should resolve now
+    await Promise.all(deps)
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<!----><div>nested msg</div><div>root async</div><!---->`
+    )
+  })
+
   test.todo('new async dep after resolve should cause suspense to restart')
 
   test.todo('portal inside suspense')
index 43040e7a87067c23506137f5170eb2351b08b23f..73488df337696c667b081f0a84361922de253b69 100644 (file)
@@ -846,11 +846,16 @@ export function createRenderer<
       effects,
       vnode,
       parentComponent,
-      container,
-      anchor
+      container
     } = suspense
+
+    // this is initial anchor on mount
+    let { anchor } = suspense
     // unmount fallback tree
     if (fallbackTree.el) {
+      // if the fallback tree was mounted, it may have been moved
+      // as part of a parent suspense. get the latest anchor for insertion
+      anchor = getNextHostNode(fallbackTree)
       unmount(fallbackTree as HostVNode, parentComponent, suspense, true)
     }
     // move content from off-dom container to actual container