expect(serializeInner(root)).toBe(`<div>oops</div>`)
})
+ // #3857
+ test('error handling w/ template optimization', async () => {
+ const Async = {
+ async setup() {
+ throw new Error('oops')
+ }
+ }
+
+ const Comp = {
+ template: `
+ <div v-if="errorMessage">{{ errorMessage }}</div>
+ <Suspense v-else>
+ <div>
+ <Async />
+ </div>
+ <template #fallback>
+ <div>fallback</div>
+ </template>
+ </Suspense>
+ `,
+ components: { Async },
+ setup() {
+ const errorMessage = ref<string | null>(null)
+ onErrorCaptured(err => {
+ errorMessage.value =
+ err instanceof Error
+ ? err.message
+ : `A non-Error value thrown: ${err}`
+ return false
+ })
+ return { errorMessage }
+ }
+ }
+
+ 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>oops</div>`)
+ })
+
it('combined usage (nested async + nested suspense + multiple deps)', async () => {
const msg = ref('nested msg')
const calls: number[] = []
const newVNode = newChildren[i]
// Determine the container (parent element) for the patch.
const container =
+ // oldVNode may be an errored async setup() component inside Suspense
+ // which will not have a mounted element
+ oldVNode.el &&
// - In the case of a Fragment, we need to provide the actual parent
// of the Fragment itself so it can move its children.
- oldVNode.type === Fragment ||
- // - In the case of different nodes, there is going to be a replacement
- // which also requires the correct parent container
- !isSameVNodeType(oldVNode, newVNode) ||
- // - In the case of a component, it could contain anything.
- oldVNode.shapeFlag & ShapeFlags.COMPONENT ||
- oldVNode.shapeFlag & ShapeFlags.TELEPORT
- ? hostParentNode(oldVNode.el!)!
+ (oldVNode.type === Fragment ||
+ // - In the case of different nodes, there is going to be a replacement
+ // which also requires the correct parent container
+ !isSameVNodeType(oldVNode, newVNode) ||
+ // - In the case of a component, it could contain anything.
+ oldVNode.shapeFlag & ShapeFlags.COMPONENT ||
+ oldVNode.shapeFlag & ShapeFlags.TELEPORT)
+ ? hostParentNode(oldVNode.el)!
: // In other cases, the parent container is not actually used so we
// just pass the block element here to avoid a DOM parentNode call.
fallbackContainer