From 684f0152e90607e9ed460b8b906615071cb4ef5e Mon Sep 17 00:00:00 2001 From: ygj6 Date: Sat, 20 Nov 2021 11:47:10 +0800 Subject: [PATCH 1/3] fix(runtime-core): return hook() in wrappedHook to handle the async call in KeepAliveHook. --- packages/runtime-core/src/components/KeepAlive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 30ad4400da6..223a7c602f5 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -381,7 +381,7 @@ function registerKeepAliveHook( } current = current.parent } - hook() + return hook() }) injectHook(type, wrappedHook, target) // In addition to registering it on the target instance, we walk up the parent From cb1214700748004142978ee5a27660bb26b182ef Mon Sep 17 00:00:00 2001 From: ygj6 Date: Sat, 20 Nov 2021 15:39:45 +0800 Subject: [PATCH 2/3] fix(runtime-core): add test case. --- .../__tests__/errorHandling.spec.ts | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/runtime-core/__tests__/errorHandling.spec.ts b/packages/runtime-core/__tests__/errorHandling.spec.ts index d1d6969104e..a161119ee56 100644 --- a/packages/runtime-core/__tests__/errorHandling.spec.ts +++ b/packages/runtime-core/__tests__/errorHandling.spec.ts @@ -9,6 +9,8 @@ import { nextTick, defineComponent, watchEffect, + KeepAlive, + onActivated, createApp } from '@vue/runtime-test' @@ -53,6 +55,7 @@ describe('error handling', () => { test('propagation stoppage', () => { const err = new Error('foo') + const err2 = new Error('bar') const fn = jest.fn() const Comp = { @@ -71,7 +74,7 @@ describe('error handling', () => { fn(err, info, 'child') return false }) - return () => h(GrandChild) + return () => h(KeepAlive, null, () => h(GrandChild)) } } @@ -80,17 +83,22 @@ describe('error handling', () => { onMounted(() => { throw err }) + onActivated(() => { + throw err2 + }) return () => null } } render(h(Comp), nodeOps.createElement('div')) - expect(fn).toHaveBeenCalledTimes(1) + expect(fn).toHaveBeenCalledTimes(2) expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child') + expect(fn).toHaveBeenCalledWith(err2, 'activated hook', 'child') }) - test('async error handling', async () => { + test.only('async error handling', async () => { const err = new Error('foo') + const err2 = new Error('bar') const fn = jest.fn() const Comp = { @@ -99,7 +107,7 @@ describe('error handling', () => { fn(err, info) return false }) - return () => h(Child) + return () => h(KeepAlive, null, () => h(Child)) } } @@ -108,6 +116,9 @@ describe('error handling', () => { onMounted(async () => { throw err }) + onActivated(async () => { + throw err2 + }) }, render() {} } @@ -115,7 +126,9 @@ describe('error handling', () => { render(h(Comp), nodeOps.createElement('div')) expect(fn).not.toHaveBeenCalled() await new Promise(r => setTimeout(r)) + expect(fn).toHaveBeenCalledTimes(2) expect(fn).toHaveBeenCalledWith(err, 'mounted hook') + expect(fn).toHaveBeenCalledWith(err2, 'activated hook') }) test('error thrown in onErrorCaptured', () => { From d4de592357861b14dc92d83ab8c067ddf2ec0e3b Mon Sep 17 00:00:00 2001 From: ygj6 Date: Mon, 22 Nov 2021 10:47:00 +0800 Subject: [PATCH 3/3] fix(runtime-core): Move test case to KeepAlive.spec.ts --- .../__tests__/components/KeepAlive.spec.ts | 31 ++++++++++++++++++- .../__tests__/errorHandling.spec.ts | 21 +++---------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 4dce5d144cf..b60931e1ffb 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -16,7 +16,9 @@ import { cloneVNode, provide, defineAsyncComponent, - Component + Component, + createApp, + onActivated } from '@vue/runtime-test' import { KeepAliveProps } from '../../src/components/KeepAlive' @@ -874,4 +876,31 @@ describe('KeepAlive', () => { await nextTick() expect(serializeInner(root)).toBe('

1

') }) + + // #4976 + test('handle error in async onActivated', async () => { + const err = new Error('foo') + const handler = jest.fn() + + const app = createApp({ + setup() { + return () => h(KeepAlive, null, () => h(Child)) + } + }) + + const Child = { + setup() { + onActivated(async () => { + throw err + }) + }, + render() {} + } + + app.config.errorHandler = handler + app.mount(nodeOps.createElement('div')) + + await nextTick() + expect(handler).toHaveBeenCalledWith(err, {}, 'activated hook') + }) }) diff --git a/packages/runtime-core/__tests__/errorHandling.spec.ts b/packages/runtime-core/__tests__/errorHandling.spec.ts index a161119ee56..d1d6969104e 100644 --- a/packages/runtime-core/__tests__/errorHandling.spec.ts +++ b/packages/runtime-core/__tests__/errorHandling.spec.ts @@ -9,8 +9,6 @@ import { nextTick, defineComponent, watchEffect, - KeepAlive, - onActivated, createApp } from '@vue/runtime-test' @@ -55,7 +53,6 @@ describe('error handling', () => { test('propagation stoppage', () => { const err = new Error('foo') - const err2 = new Error('bar') const fn = jest.fn() const Comp = { @@ -74,7 +71,7 @@ describe('error handling', () => { fn(err, info, 'child') return false }) - return () => h(KeepAlive, null, () => h(GrandChild)) + return () => h(GrandChild) } } @@ -83,22 +80,17 @@ describe('error handling', () => { onMounted(() => { throw err }) - onActivated(() => { - throw err2 - }) return () => null } } render(h(Comp), nodeOps.createElement('div')) - expect(fn).toHaveBeenCalledTimes(2) + expect(fn).toHaveBeenCalledTimes(1) expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child') - expect(fn).toHaveBeenCalledWith(err2, 'activated hook', 'child') }) - test.only('async error handling', async () => { + test('async error handling', async () => { const err = new Error('foo') - const err2 = new Error('bar') const fn = jest.fn() const Comp = { @@ -107,7 +99,7 @@ describe('error handling', () => { fn(err, info) return false }) - return () => h(KeepAlive, null, () => h(Child)) + return () => h(Child) } } @@ -116,9 +108,6 @@ describe('error handling', () => { onMounted(async () => { throw err }) - onActivated(async () => { - throw err2 - }) }, render() {} } @@ -126,9 +115,7 @@ describe('error handling', () => { render(h(Comp), nodeOps.createElement('div')) expect(fn).not.toHaveBeenCalled() await new Promise(r => setTimeout(r)) - expect(fn).toHaveBeenCalledTimes(2) expect(fn).toHaveBeenCalledWith(err, 'mounted hook') - expect(fn).toHaveBeenCalledWith(err2, 'activated hook') }) test('error thrown in onErrorCaptured', () => {