]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: more coverage for error handling
authorEvan You <yyx990803@gmail.com>
Fri, 30 Aug 2019 20:20:32 +0000 (16:20 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 30 Aug 2019 20:20:32 +0000 (16:20 -0400)
packages/runtime-core/__tests__/errorHandling.spec.ts
packages/runtime-core/src/component.ts

index fb752a6bf7b4c60d2209f2b9c2f50a813fd21dea..9756692fcb1f54add531cfc948c03eddfae530ac 100644 (file)
@@ -6,10 +6,13 @@ import {
   nodeOps,
   watch,
   ref,
-  nextTick
+  nextTick,
+  mockWarn
 } from '@vue/runtime-test'
 
 describe('error handling', () => {
+  mockWarn()
+
   test('propagtaion', () => {
     const err = new Error('foo')
     const fn = jest.fn()
@@ -86,6 +89,35 @@ describe('error handling', () => {
     expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
   })
 
+  test('async error handling', async () => {
+    const err = new Error('foo')
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+          return true
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        onMounted(async () => {
+          throw err
+        })
+      },
+      render() {}
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).not.toHaveBeenCalled()
+    await new Promise(r => setTimeout(r))
+    expect(fn).toHaveBeenCalledWith(err, 'mounted hook')
+  })
+
   test('error thrown in onErrorCaptured', () => {
     const err = new Error('foo')
     const err2 = new Error('bar')
@@ -327,5 +359,36 @@ describe('error handling', () => {
     expect(fn).toHaveBeenCalledWith(err, 'component event handler')
   })
 
+  it('should warn unhandled', () => {
+    const onError = jest.spyOn(console, 'error')
+    onError.mockImplementation(() => {})
+    const err = new Error('foo')
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        throw err
+      },
+      render() {}
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'setup function')
+    expect(
+      `Unhandled error during execution of setup function`
+    ).toHaveBeenWarned()
+    expect(onError).toHaveBeenCalledWith(err)
+    onError.mockRestore()
+  })
+
   // native event handler handling should be tested in respective renderers
 })
index 67803d5ba267a8638cf56de631468ebc199ba9e7..396313490aaf095abae38c22386d28ddac4d91ef 100644 (file)
@@ -296,15 +296,24 @@ export function setupStatefulComponent(instance: ComponentInstance) {
       // setup returned an inline render function
       instance.render = setupResult
     } else {
+      if (__DEV__) {
+        if (!Component.render) {
+          warn(
+            `Component is missing render function. Either provide a template or ` +
+              `return a render function from setup().`
+          )
+        }
+        if (
+          setupResult &&
+          typeof setupResult.then === 'function' &&
+          typeof setupResult.catch === 'function'
+        ) {
+          warn(`setup() returned a Promise. setup() cannot be async.`)
+        }
+      }
       // setup returned bindings.
       // assuming a render function compiled from template is present.
       instance.data = reactive(setupResult || {})
-      if (__DEV__ && !Component.render) {
-        warn(
-          `Component is missing render function. Either provide a template or ` +
-            `return a render function from setup().`
-        )
-      }
       instance.render = (Component.render || NOOP) as RenderFunction
     }
   } else {