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

index b91fdab8dd24c5401ac314aa2989067f189620a9..fb752a6bf7b4c60d2209f2b9c2f50a813fd21dea 100644 (file)
+import {
+  onMounted,
+  onErrorCaptured,
+  render,
+  h,
+  nodeOps,
+  watch,
+  ref,
+  nextTick
+} from '@vue/runtime-test'
+
 describe('error handling', () => {
-  test.todo('in lifecycle hooks')
+  test('propagtaion', () => {
+    const err = new Error('foo')
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info, 'root')
+          return true
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info, 'child')
+        })
+        return () => h(GrandChild)
+      }
+    }
+
+    const GrandChild = {
+      setup() {
+        onMounted(() => {
+          throw err
+        })
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledTimes(2)
+    expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'root')
+    expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
+  })
+
+  test('propagation stoppage', () => {
+    const err = new Error('foo')
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info, 'root')
+          return true
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info, 'child')
+          return true
+        })
+        return () => h(GrandChild)
+      }
+    }
+
+    const GrandChild = {
+      setup() {
+        onMounted(() => {
+          throw err
+        })
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledTimes(1)
+    expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
+  })
+
+  test('error thrown in onErrorCaptured', () => {
+    const err = new Error('foo')
+    const err2 = new Error('bar')
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+          return true
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        onErrorCaptured(() => {
+          throw err2
+        })
+        return () => h(GrandChild)
+      }
+    }
+
+    const GrandChild = {
+      setup() {
+        onMounted(() => {
+          throw err
+        })
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledTimes(2)
+    expect(fn).toHaveBeenCalledWith(err, 'mounted hook')
+    expect(fn).toHaveBeenCalledWith(err2, 'errorCaptured hook')
+  })
+
+  test('setup function', () => {
+    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() {
+        throw err
+      },
+      render() {}
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'setup function')
+  })
+
+  test('in render function', () => {
+    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() {
+        return () => {
+          throw err
+        }
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'render function')
+  })
+
+  test('in watch (simple usage)', () => {
+    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() {
+        watch(() => {
+          throw err
+        })
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
+  })
+
+  test('in watch getter', () => {
+    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() {
+        watch(
+          () => {
+            throw err
+          },
+          () => {}
+        )
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'watcher getter')
+  })
+
+  test('in watch callback', () => {
+    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() {
+        watch(
+          () => 1,
+          () => {
+            throw err
+          }
+        )
+        return () => null
+      }
+    }
+
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
+  })
+
+  test('in watch cleanup', async () => {
+    const err = new Error('foo')
+    const count = ref(0)
+    const fn = jest.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+          return true
+        })
+        return () => h(Child)
+      }
+    }
+
+    const Child = {
+      setup() {
+        watch(onCleanup => {
+          count.value
+          onCleanup(() => {
+            throw err
+          })
+        })
+        return () => null
+      }
+    }
 
-  test.todo('in onErrorCaptured')
+    render(h(Comp), nodeOps.createElement('div'))
 
-  test.todo('in setup function')
+    count.value++
+    await nextTick()
+    expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function')
+  })
 
-  test.todo('in render function')
+  test('in component event handler', () => {
+    const err = new Error('foo')
+    const fn = jest.fn()
 
-  test.todo('in watch (simple usage)')
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+          return true
+        })
+        return () =>
+          h(Child, {
+            onFoo: () => {
+              throw err
+            }
+          })
+      }
+    }
 
-  test.todo('in watch (with source)')
+    const Child = {
+      setup(props: any, { emit }: any) {
+        emit('foo')
+        return () => null
+      }
+    }
 
-  test.todo('in component event handler')
+    render(h(Comp), nodeOps.createElement('div'))
+    expect(fn).toHaveBeenCalledWith(err, 'component event handler')
+  })
 
   // native event handler handling should be tested in respective renderers
 })
index 4ffdd0e5e7080d739db29b1163cb96a7fbdd1816..cded357b65e85e7b20df4d48072865784f513495 100644 (file)
@@ -2,7 +2,8 @@ import {
   ComponentInstance,
   LifecycleHooks,
   currentInstance,
-  setCurrentInstance
+  setCurrentInstance,
+  ComponentRenderProxy
 } from './component'
 import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling'
 import { warn } from './warning'
@@ -92,7 +93,11 @@ export function onRenderTracked(
 }
 
 export function onErrorCaptured(
-  hook: Function,
+  hook: (
+    err: Error,
+    instance: ComponentRenderProxy | null,
+    info: string
+  ) => boolean | void,
   target: ComponentInstance | null = currentInstance
 ) {
   injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
index 82242d695a29c6cf52919caa55bff278d99f0df2..67803d5ba267a8638cf56de631468ebc199ba9e7 100644 (file)
@@ -443,6 +443,5 @@ function hasPropsChanged(prevProps: Data, nextProps: Data): boolean {
       return true
     }
   }
-  console.log(111)
   return false
 }
index d868c0018b05b2fbf8e46e5d2f8646fd7a45b089..0a01314575b71576a622be82aa487b7515f1ad7b 100644 (file)
@@ -88,7 +88,7 @@ export function handleError(
           errorCapturedHooks[i](
             err,
             instance && instance.renderProxy,
-            contextVNode
+            ErrorTypeStrings[type]
           )
         ) {
           return