test(vapor): componentEmits

This commit is contained in:
Evan You 2024-12-10 19:37:55 +08:00
parent a1276f7577
commit 5648dda0c0
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
5 changed files with 45 additions and 79 deletions

View File

@ -175,7 +175,8 @@ export function baseEmit(
// for v-model update:xxx events, apply modifiers on args
// it's ok to use static get because modelModifiers can only be in the static
// part of the props
const modifiers = isModelListener && getModelModifiers(props, event.slice(7))
const modifiers =
isModelListener && getModelModifiers(props, event.slice(7), getter)
if (modifiers) {
if (modifiers.trim) {
args = rawArgs.map(a => (isString(a) ? a.trim() : a))
@ -230,7 +231,7 @@ export function baseEmit(
)
}
const onceHandler = props[handlerName + `Once`]
const onceHandler = getter(props, handlerName + `Once`)
if (onceHandler) {
if (!instance.emitted) {
instance.emitted = {}
@ -239,7 +240,7 @@ export function baseEmit(
}
instance.emitted[handlerName] = true
callWithAsyncErrorHandling(
onceHandler,
onceHandler as Function | Function[],
instance,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args,
@ -256,7 +257,10 @@ export function baseEmit(
}
}
function defaultPropGetter(props: Record<string, any>, key: string): unknown {
export function defaultPropGetter(
props: Record<string, any>,
key: string,
): unknown {
return props[key]
}

View File

@ -5,6 +5,7 @@ import { getCurrentInstance } from '../component'
import { warn } from '../warning'
import type { NormalizedProps } from '../componentProps'
import { watchSyncEffect } from '../apiWatch'
import { defaultPropGetter } from '../componentEmits'
export function useModel<
M extends PropertyKey,
@ -35,7 +36,7 @@ export function useModel(
}
const hyphenatedName = hyphenate(name)
const modifiers = getModelModifiers(props, camelizedName)
const modifiers = getModelModifiers(props, camelizedName, defaultPropGetter)
const res = customRef((track, trigger) => {
let localValue: any
@ -120,10 +121,11 @@ export function useModel(
export const getModelModifiers = (
props: Record<string, any>,
modelName: string,
getter: (props: Record<string, any>, key: string) => any,
): Record<string, boolean> | undefined => {
return modelName === 'modelValue' || modelName === 'model-value'
? props.modelModifiers
: props[`${modelName}Modifiers`] ||
props[`${camelize(modelName)}Modifiers`] ||
props[`${hyphenate(modelName)}Modifiers`]
? getter(props, 'modelModifiers')
: getter(props, `${modelName}Modifiers`) ||
getter(props, `${camelize(modelName)}Modifiers`) ||
getter(props, `${hyphenate(modelName)}Modifiers`)
}

View File

@ -4,6 +4,8 @@ import { makeRender } from './_utils'
const define = makeRender<any>()
// TODO: port more tests from rendererAttrsFallthrough.spec.ts
describe('attribute fallthrough', () => {
it('should allow attrs to fallthrough', async () => {
const t0 = template('<div>')

View File

@ -3,25 +3,25 @@
// Note: emits and listener fallthrough is tested in
// ./rendererAttrsFallthrough.spec.ts.
import { toHandlers } from '@vue/runtime-core'
import {
createComponent,
defineComponent,
isEmitListener,
nextTick,
onBeforeUnmount,
} from '../src'
import { isEmitListener } from '../src/componentEmits'
toHandlers,
} from '@vue/runtime-dom'
import { createComponent, defineVaporComponent } from '../src'
import { makeRender } from './_utils'
const define = makeRender()
describe.todo('component: emit', () => {
describe('component: emit', () => {
test('trigger handlers', () => {
const { render } = define({
setup(_, { emit }) {
emit('foo')
emit('bar')
emit('!baz')
return []
},
})
const onFoo = vi.fn()
@ -44,16 +44,17 @@ describe.todo('component: emit', () => {
emit('foo')
emit('bar')
emit('!baz')
return []
},
})
const onFoo = vi.fn()
const onBar = vi.fn()
const onBaz = vi.fn()
render(() => ({
onfoo: onFoo,
onBar,
['on!baz']: onBaz,
}))
render({
onfoo: () => onFoo,
onBar: () => onBar,
['on!baz']: () => onBaz,
})
expect(onFoo).not.toHaveBeenCalled()
expect(onBar).toHaveBeenCalled()
@ -64,6 +65,7 @@ describe.todo('component: emit', () => {
const { render } = define({
setup(_, { emit }) {
emit('test-event')
return []
},
})
@ -76,6 +78,7 @@ describe.todo('component: emit', () => {
const { render } = define({
setup(_, { emit }) {
emit('test-event')
return []
},
})
@ -90,6 +93,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('test-event')
emit('testEvent')
return []
},
})
@ -111,6 +115,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('update:fooProp')
emit('update:barProp')
return []
},
})
@ -129,6 +134,7 @@ describe.todo('component: emit', () => {
const { render } = define({
setup(_, { emit }) {
emit('foo', 1)
return []
},
})
@ -148,6 +154,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('bar')
return []
},
})
render()
@ -164,6 +171,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('bar')
return []
},
})
render()
@ -179,6 +187,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('foo')
return []
},
}).render()
expect(
@ -190,15 +199,6 @@ describe.todo('component: emit', () => {
// TODO: warning validator
})
// NOTE: not supported mixins
// test.todo('merging from mixins', () => {})
// #2651
// test.todo(
// 'should not attach normalized object when mixins do not contain emits',
// () => {},
// )
test('.once', () => {
const { render } = define({
emits: {
@ -210,6 +210,7 @@ describe.todo('component: emit', () => {
emit('foo')
emit('bar')
emit('bar')
return []
},
})
const fn = vi.fn()
@ -230,6 +231,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('foo')
emit('foo')
return []
},
})
const onFoo = vi.fn()
@ -247,6 +249,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('update:modelValue', '1')
emit('update:foo', '2')
return []
},
})
const fn1 = vi.fn()
@ -270,6 +273,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('update:modelValue', ' one ')
emit('update:foo', ' two ')
return []
},
})
const fn1 = vi.fn()
@ -305,6 +309,7 @@ describe.todo('component: emit', () => {
setup(_, { emit }) {
emit('update:modelValue', ' +01.2 ')
emit('update:foo', ' 1 ')
return []
},
})
const fn1 = vi.fn()
@ -339,6 +344,7 @@ describe.todo('component: emit', () => {
const { render } = define({
setup(_, { emit }) {
emit('update:modelValue', ' foo ', { bar: ' bar ' })
return []
},
})
const fn = vi.fn()
@ -389,13 +395,14 @@ describe.todo('component: emit', () => {
test('does not emit after unmount', async () => {
const fn = vi.fn()
const Foo = defineComponent({
const Foo = defineVaporComponent({
emits: ['closing'],
setup(_, { emit }) {
onBeforeUnmount(async () => {
await nextTick()
emit('closing', true)
})
return []
},
})

View File

@ -1,49 +0,0 @@
import { describe, expect } from 'vitest'
import { makeRender } from './_utils'
import { type Ref, ref } from '@vue/reactivity'
const define = makeRender()
describe.todo('component expose', () => {
test('should work', async () => {
const expxosedObj = { foo: 1 }
const { render } = define({
setup(_, { expose }) {
expose(expxosedObj)
},
})
const { instance } = render()
expect(instance?.exposed).toEqual(expxosedObj)
})
test('should warn when called multiple times', async () => {
const { render } = define({
setup(_, { expose }) {
expose()
expose()
},
})
render()
expect(
'expose() should be called only once per setup().',
).toHaveBeenWarned()
})
test('should warn when passed non-object', async () => {
const exposedRef = ref<number[] | Ref>([1, 2, 3])
const { render } = define({
setup(_, { expose }) {
expose(exposedRef.value)
},
})
render()
expect(
'expose() should be passed a plain object, received array.',
).toHaveBeenWarned()
exposedRef.value = ref(1)
render()
expect(
'expose() should be passed a plain object, received ref.',
).toHaveBeenWarned()
})
})