-import type { Component } from '../src/_old/component'
-import { type RefEl, setRef } from '../src/dom/templateRef'
-import { onErrorCaptured, onMounted } from '../src/_old/apiLifecycle'
-import { createComponent } from '../src/_old/apiCreateComponent'
+import {
+ nextTick,
+ onErrorCaptured,
+ onMounted,
+ ref,
+ watch,
+ watchEffect,
+} from '@vue/runtime-dom'
+import { createComponent, setRef, template } from '../src'
import { makeRender } from './_utils'
-import { template } from '../src/dom/template'
-import { watch, watchEffect } from '../src/_old/apiWatch'
-import { nextTick } from '../src/_old/scheduler'
-import { ref } from '@vue/reactivity'
+import type { VaporComponent } from '../src/component'
+import type { RefEl } from '../src/dom/templateRef'
const define = makeRender()
const err = new Error('foo')
const fn = vi.fn()
- const Comp: Component = {
+ const Comp: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info, 'root')
},
}
- const Child: Component = {
+ const Child: VaporComponent = {
name: 'Child',
setup() {
onErrorCaptured((err, instance, info) => {
},
}
- const GrandChild: Component = {
+ const GrandChild: VaporComponent = {
setup() {
onMounted(() => {
throw err
})
+ return []
},
}
const err = new Error('foo')
const fn = vi.fn()
- const Comp = {
+ const Comp: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info, 'root')
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info, 'child')
},
}
- const GrandChild = {
+ const GrandChild: VaporComponent = {
setup() {
onMounted(() => {
throw err
})
+ return []
},
}
const err = new Error('foo')
const fn = vi.fn()
- const Comp = {
+ const Comp: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info)
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
onMounted(async () => {
throw err
})
+ return []
},
}
const err2 = new Error('bar')
const fn = vi.fn()
- const Comp = {
+ const Comp: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info)
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
onErrorCaptured(() => {
throw err2
},
}
- const GrandChild = {
+ const GrandChild: VaporComponent = {
setup() {
onMounted(() => {
throw err
})
+ return []
},
}
define(Comp).render()
expect(fn).toHaveBeenCalledWith(err, 'setup function')
+ expect(`returned non-block value`).toHaveBeenWarned()
})
test('in render function', () => {
expect(fn).toHaveBeenCalledWith(err, 'render function')
})
- test('in function ref', () => {
+ test.todo('in function ref', () => {
const err = new Error('foo')
const ref = () => {
throw err
const err = new Error('foo')
const fn = vi.fn()
- const Comp = {
+ const Comp: VaporComponent = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info)
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
watchEffect(() => {
throw err
})
+ return []
},
}
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
watch(
() => {
},
() => {},
)
+ return []
},
}
}
const count = ref(0)
- const Child = {
+ const Child: VaporComponent = {
setup() {
watch(
() => count.value,
throw err
},
)
+ return []
},
}
},
}
- const Child = {
+ const Child: VaporComponent = {
setup() {
watchEffect(onCleanup => {
count.value
throw err
})
})
+ return []
},
}
return false
})
return createComponent(Child, {
- onFoo: () => {
+ onFoo: () => () => {
throw err
},
})
},
}
- const Child = {
+ const Child: VaporComponent = {
setup(props: any, { emit }: any) {
emit('foo')
+ return []
},
}
define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'setup function')
+ expect(fn).toHaveBeenCalledWith(err, 'component event handler')
})
- test.todo('in component event handler via emit (async)', async () => {
+ test('in component event handler via emit (async)', async () => {
const err = new Error('foo')
const fn = vi.fn()
return false
})
return createComponent(Child, {
- async onFoo() {
+ onFoo: () => async () => {
throw err
},
})
},
}
- const Child = {
+ const Child: VaporComponent = {
props: ['onFoo'],
setup(props: any, { emit }: any) {
emit('foo')
+ return []
},
}
define(Comp).render()
await nextTick()
- expect(fn).toHaveBeenCalledWith(err, 'setup function')
+ expect(fn).toHaveBeenCalledWith(err, 'component event handler')
})
- test.todo('in component event handler via emit (async + array)', async () => {
+ test('in component event handler via emit (async + array)', async () => {
const err = new Error('foo')
const fn = vi.fn()
return p
}
+ const handlers = [
+ createAsyncHandler(Promise.reject(err)),
+ createAsyncHandler(Promise.resolve(1)),
+ ]
+
const Comp = {
setup() {
onErrorCaptured((err, instance, info) => {
fn(err, info)
return false
})
- return createComponent(Child, [
- {
- onFoo: () => {
- createAsyncHandler(Promise.reject(err))
- createAsyncHandler(Promise.resolve(1))
- },
- },
- ])
+ return createComponent(Child, {
+ onFoo: () => handlers,
+ })
},
}
- const Child = {
+ const Child: VaporComponent = {
setup(props: any, { emit }: any) {
emit('foo')
+ return []
},
}
define(Comp).render()
- try {
- await Promise.all(res)
- } catch (e: any) {
- expect(e).toBe(err)
- }
+ await expect(() => Promise.all(res)).rejects.toThrowError()
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
})
watchEffect(async () => {
throw error4
})
+ return []
},
}).create()
+++ /dev/null
-import { makeRender } from './_utils'
-import { template } from '../src/dom/template'
-
-const define = makeRender()
-
-describe('renderer: element', () => {
- it('should create an element', () => {
- const { html } = define({
- render() {
- return template(`<div>`)()
- },
- }).render()
-
- expect(html()).toBe('<div></div>')
- })
-
- it('should create an element with props', () => {
- const { html } = define({
- render() {
- return template(`<div id="foo" class="bar">`)()
- },
- }).render()
-
- expect(html()).toBe('<div id="foo" class="bar"></div>')
- })
-
- it('should create an element with direct text children', () => {
- const { html } = define({
- render() {
- return template(`<div>foo bar`)()
- },
- }).render()
-
- expect(html()).toBe('<div>foo bar</div>')
- })
-
- it('should create an element with direct text children and props', () => {
- const { html } = define({
- render() {
- return template(`<div id="foo">bar`)()
- },
- }).render()
-
- expect(html()).toBe('<div id="foo">bar</div>')
- })
-
- it.fails('should update an element tag which is already mounted', () => {
- const { html } = define({
- render() {
- return template(`<div>foo`)()
- },
- }).render()
- expect(html()).toBe('<div>foo</div>')
-
- define({
- render() {
- return template(`<span>foo`)()
- },
- }).render()
- expect(html()).toBe('<span>foo</span>')
- })
-
- it.fails('should update element props which is already mounted', () => {
- const { html } = define({
- render() {
- return template(`<div id="baz">foo`)()
- },
- }).render()
- expect(html()).toBe('<div id="baz">foo</div>')
-
- define({
- render() {
- return template(`<div id="baz" class="bar">foo`)()
- },
- }).render()
- expect(html()).toBe('<div id="baz" class="bar">foo</div>')
- })
-})
EffectScope,
type EmitFn,
type EmitsOptions,
+ ErrorCodes,
type GenericAppContext,
type GenericComponentInstance,
type LifecycleHook,
type NormalizedPropsOptions,
type ObjectEmitsOptions,
type SuspenseBoundary,
+ callWithErrorHandling,
currentInstance,
nextUid,
popWarningContext,
}
const setupFn = isFunction(component) ? component : component.setup
+ const setupContext = (instance.setupContext =
+ setupFn && setupFn.length > 1 ? new SetupContext(instance) : null)
const setupResult = setupFn
- ? setupFn(
+ ? callWithErrorHandling(setupFn, instance, ErrorCodes.SETUP_FUNCTION, [
instance.props,
- // @ts-expect-error
- setupFn.length > 1 ? new SetupContext(instance) : null,
- ) || EMPTY_OBJ
+ setupContext,
+ ]) || EMPTY_OBJ
: EMPTY_OBJ
if (__DEV__ && !isBlock(setupResult)) {
* dev only
*/
export function devRender(instance: VaporComponentInstance): void {
- instance.block = instance.type.render!.call(
- null,
- instance.setupState,
- instance.props,
- instance.emit,
- instance.attrs,
- instance.slots,
- )
+ instance.block =
+ callWithErrorHandling(
+ instance.type.render!,
+ instance,
+ ErrorCodes.RENDER_FUNCTION,
+ [
+ instance.setupState,
+ instance.props,
+ instance.emit,
+ instance.attrs,
+ instance.slots,
+ ],
+ ) || []
}
const emptyContext: GenericAppContext = {
ec?: LifecycleHook // LifecycleHooks.ERROR_CAPTURED
sp?: LifecycleHook<() => Promise<unknown>> // LifecycleHooks.SERVER_PREFETCH
+ setupContext?: SetupContext | null
+
// dev only
setupState?: Record<string, any>
devtoolsRawSetupState?: any