test: tests for error handling
This commit is contained in:
		
							parent
							
								
									d5684e1a9d
								
							
						
					
					
						commit
						be28f976af
					
				| @ -1,17 +1,331 @@ | ||||
| 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() | ||||
| 
 | ||||
|   test.todo('in onErrorCaptured') | ||||
|     const Comp = { | ||||
|       setup() { | ||||
|         onErrorCaptured((err, instance, info) => { | ||||
|           fn(err, info, 'root') | ||||
|           return true | ||||
|         }) | ||||
|         return () => h(Child) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   test.todo('in setup function') | ||||
|     const Child = { | ||||
|       setup() { | ||||
|         onErrorCaptured((err, instance, info) => { | ||||
|           fn(err, info, 'child') | ||||
|         }) | ||||
|         return () => h(GrandChild) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   test.todo('in render function') | ||||
|     const GrandChild = { | ||||
|       setup() { | ||||
|         onMounted(() => { | ||||
|           throw err | ||||
|         }) | ||||
|         return () => null | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   test.todo('in watch (simple usage)') | ||||
|     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.todo('in watch (with source)') | ||||
|   test('propagation stoppage', () => { | ||||
|     const err = new Error('foo') | ||||
|     const fn = jest.fn() | ||||
| 
 | ||||
|   test.todo('in component event handler') | ||||
|     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 | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     render(h(Comp), nodeOps.createElement('div')) | ||||
| 
 | ||||
|     count.value++ | ||||
|     await nextTick() | ||||
|     expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function') | ||||
|   }) | ||||
| 
 | ||||
|   test('in component event handler', () => { | ||||
|     const err = new Error('foo') | ||||
|     const fn = jest.fn() | ||||
| 
 | ||||
|     const Comp = { | ||||
|       setup() { | ||||
|         onErrorCaptured((err, instance, info) => { | ||||
|           fn(err, info) | ||||
|           return true | ||||
|         }) | ||||
|         return () => | ||||
|           h(Child, { | ||||
|             onFoo: () => { | ||||
|               throw err | ||||
|             } | ||||
|           }) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     const Child = { | ||||
|       setup(props: any, { emit }: any) { | ||||
|         emit('foo') | ||||
|         return () => null | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     render(h(Comp), nodeOps.createElement('div')) | ||||
|     expect(fn).toHaveBeenCalledWith(err, 'component event handler') | ||||
|   }) | ||||
| 
 | ||||
|   // native event handler handling should be tested in respective renderers
 | ||||
| }) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -443,6 +443,5 @@ function hasPropsChanged(prevProps: Data, nextProps: Data): boolean { | ||||
|       return true | ||||
|     } | ||||
|   } | ||||
|   console.log(111) | ||||
|   return false | ||||
| } | ||||
|  | ||||
| @ -88,7 +88,7 @@ export function handleError( | ||||
|           errorCapturedHooks[i]( | ||||
|             err, | ||||
|             instance && instance.renderProxy, | ||||
|             contextVNode | ||||
|             ErrorTypeStrings[type] | ||||
|           ) | ||||
|         ) { | ||||
|           return | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user