Skip to content

Commit

Permalink
fix: change test for component
Browse files Browse the repository at this point in the history
  • Loading branch information
Procrustes5 committed Aug 25, 2024
1 parent afeda80 commit e46dfdd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 117 deletions.
169 changes: 55 additions & 114 deletions packages-private/dts-test/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,19 @@ import {
type ComponentOptions,
type ComponentPublicInstance,
type PropType,
type Ref,
type SetupContext,
type Slots,
type SlotsType,
type VNode,
createApp,
defineComponent,
h,
nextTick,
reactive,
ref,
render as vueRender,
withKeys,
withModifiers,
} from 'vue'
import { type IsAny, type IsUnion, describe, expectType } from './utils'
import {
type TestElement,
type TestNode,
nodeOps,
serializeInner,
triggerEvent,
} from '@vue/runtime-test'

describe('with object props', () => {
interface ExpectedProps {
Expand Down Expand Up @@ -2038,118 +2028,69 @@ expectString(instance.actionText)
// @ts-expect-error
expectString(instance.$props.actionText)

// Helper function to safely cast TestNode to TestElement
function getFirstElementChild(node: TestNode): TestElement {
if ('children' in node) {
return node.children[0] as TestElement
}
throw new Error('Expected an element with children')
}
describe('generic components in defineComponent', () => {
const GenericComp = defineComponent(
<T extends { name: string }>(props: { msg: string; list: T[] }) => {
return () => (
<div>
{props.msg}
{props.list.map(item => item.name).join(', ')}
</div>
)
},
)

// Custom render function with correct typing for TestElement
function render(vnode: any, root: TestElement) {
return vueRender(vnode, root as any)
}
const GenericCompUser = defineComponent(() => {
const list = ref([{ name: 'Tom' }, { name: 'Jack' }])

describe('defineComponent with generics', () => {
test('defineComponent with generic', async () => {
const Comp = defineComponent({
props: {
msg: String,
list: Array as PropType<{ name: string }[]>,
},
setup(props) {
const count = ref(0)
const increment = () => {
count.value++
}
return () => {
return (
<div>
<GenericComp<{ name: string }> msg="hello" list={list.value} />
</div>
)
}
})

return () =>
h('div', { onClick: increment }, [
h('h2', props.msg),
h('p', count.value),
...(props.list || []).map((item: { name: string }) =>
h('p', item.name),
),
])
},
})
// Test correct usage
expectType<JSX.Element>(<GenericCompUser />)

const list: Ref<{ name: string }[]> = ref([
{ name: 'Tom' },
{ name: 'Jerry' },
])
// Test GenericComp directly with correct props
expectType<JSX.Element>(
<GenericComp<{ name: string }> msg="hello" list={[{ name: 'Alice' }]} />,
)

const root = nodeOps.createElement('div')
render(h(Comp, { msg: 'Hello', list: list.value }), root)

expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>0</p><p>Tom</p><p>Jerry</p></div>`,
)

const firstChild = getFirstElementChild(root)
triggerEvent(firstChild, 'click')
await nextTick()
expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>1</p><p>Tom</p><p>Jerry</p></div>`,
)

list.value.push({ name: 'Spike' })
await nextTick()
expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>1</p><p>Tom</p><p>Jerry</p><p>Spike</p></div>`,
)
})
// Test with missing required prop
expectType<JSX.Element>(
// @ts-expect-error
<GenericComp<{ name: string }> list={[{ name: 'Bob' }]} />,
)

test('defineComponent with generic in render function', async () => {
const Comp = defineComponent({
props: {
msg: String,
list: Array as PropType<{ name: string }[]>,
},
setup(props) {
const count = ref(0)
const increment = () => {
count.value++
}
// Test with extended type
interface Person {
name: string
age: number
}

return () =>
h('div', { onClick: increment }, [
h('h2', props.msg),
h('p', count.value),
...(props.list || []).map((item: { name: string }) =>
h('p', item.name),
),
])
},
})
const ExtendedGenericCompUser = defineComponent(() => {
const people = ref<Person[]>([
{ name: 'Tom', age: 25 },
{ name: 'Jack', age: 30 },
])

const list = ref([{ name: 'Tom' }, { name: 'Jerry' }])
return () => {
return (
<div>
<GenericComp<Person> msg="people" list={people.value} />
</div>
)
}
})

const App = defineComponent({
setup() {
return () => h(Comp, { msg: 'Hello', list: list.value })
},
})
expectType<JSX.Element>(<ExtendedGenericCompUser />)

const root = nodeOps.createElement('div')
render(h(App), root)

expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>0</p><p>Tom</p><p>Jerry</p></div>`,
)

const firstChild = getFirstElementChild(root)
triggerEvent(firstChild, 'click')
await nextTick()
expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>1</p><p>Tom</p><p>Jerry</p></div>`,
)

list.value.push({ name: 'Spike' })
await nextTick()
expect(serializeInner(root)).toBe(
`<div><h2>Hello</h2><p>1</p><p>Tom</p><p>Jerry</p><p>Spike</p></div>`,
)
})
// Test GenericComp directly with extended type
expectType<JSX.Element>(
<GenericComp<Person> msg="people" list={[{ name: 'Alice', age: 28 }]} />,
)
})
4 changes: 1 addition & 3 deletions packages/runtime-core/src/apiDefineComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ export type DefineComponentWithGeneric<
S
> &
PP & {
<T extends Record<string, any> = Generic>(
props: Props & { ref?: Ref<any> },
): VNode
<T extends Generic>(props: Props & { ref?: Ref<any> } & T): VNode
}

// defineComponent is a utility that is primarily used for type inference
Expand Down

0 comments on commit e46dfdd

Please sign in to comment.