test: add tests
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details

This commit is contained in:
daiwei 2025-05-29 21:45:00 +08:00
parent dde7076120
commit a952b03358
6 changed files with 190 additions and 8 deletions

View File

@ -103,6 +103,97 @@ export function render(_ctx) {
}"
`;
exports[`compiler: transform slot > forwarded slots > <slot w/ nested component> 1`] = `
"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _createForwardedSlot = _forwardedSlotCreator()
const _component_Comp = _resolveComponent("Comp")
const n2 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n1 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n0 = _createForwardedSlot("default", null)
return n0
}
})
return n1
}
}, true)
return n2
}"
`;
exports[`compiler: transform slot > forwarded slots > <slot> tag only 1`] = `
"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _createForwardedSlot = _forwardedSlotCreator()
const _component_Comp = _resolveComponent("Comp")
const n1 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n0 = _createForwardedSlot("default", null)
return n0
}
}, true)
return n1
}"
`;
exports[`compiler: transform slot > forwarded slots > <slot> tag w/ template 1`] = `
"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _createForwardedSlot = _forwardedSlotCreator()
const _component_Comp = _resolveComponent("Comp")
const n2 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n0 = _createForwardedSlot("default", null)
return n0
}
}, true)
return n2
}"
`;
exports[`compiler: transform slot > forwarded slots > <slot> tag w/ v-for 1`] = `
"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createFor as _createFor, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _createForwardedSlot = _forwardedSlotCreator()
const _component_Comp = _resolveComponent("Comp")
const n3 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n0 = _createFor(() => (_ctx.b), (_for_item0) => {
const n2 = _createForwardedSlot("default", null)
return n2
})
return n0
}
}, true)
return n3
}"
`;
exports[`compiler: transform slot > forwarded slots > <slot> tag w/ v-if 1`] = `
"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createIf as _createIf, createComponentWithFallback as _createComponentWithFallback } from 'vue';
export function render(_ctx) {
const _createForwardedSlot = _forwardedSlotCreator()
const _component_Comp = _resolveComponent("Comp")
const n3 = _createComponentWithFallback(_component_Comp, null, {
"default": () => {
const n0 = _createIf(() => (_ctx.ok), () => {
const n2 = _createForwardedSlot("default", null)
return n2
})
return n0
}
}, true)
return n3
}"
`;
exports[`compiler: transform slot > implicit default slot 1`] = `
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
const t0 = _template("<div></div>")

View File

@ -409,6 +409,35 @@ describe('compiler: transform slot', () => {
})
})
describe('forwarded slots', () => {
test('<slot> tag only', () => {
const { code } = compileWithSlots(`<Comp><slot/></Comp>`)
expect(code).toMatchSnapshot()
})
test('<slot> tag w/ v-if', () => {
const { code } = compileWithSlots(`<Comp><slot v-if="ok"/></Comp>`)
expect(code).toMatchSnapshot()
})
test('<slot> tag w/ v-for', () => {
const { code } = compileWithSlots(`<Comp><slot v-for="a in b"/></Comp>`)
expect(code).toMatchSnapshot()
})
test('<slot> tag w/ template', () => {
const { code } = compileWithSlots(
`<Comp><template #default><slot/></template></Comp>`,
)
expect(code).toMatchSnapshot()
})
test('<slot w/ nested component>', () => {
const { code } = compileWithSlots(`<Comp><Comp><slot/></Comp></Comp>`)
expect(code).toMatchSnapshot()
})
})
describe('errors', () => {
test('error on extraneous children w/ named default slot', () => {
const onError = vi.fn()

View File

@ -76,6 +76,7 @@ export class TransformContext<T extends AllNode = AllNode> {
inVOnce: boolean = false
inVFor: number = 0
inSlot: number = 0
comment: CommentNode[] = []
component: Set<string> = this.ir.component

View File

@ -100,11 +100,14 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
}
return () => {
let forwarded = false
const slotNode = context.block.node
if (slotNode.type === NodeTypes.ELEMENT) {
forwarded = hasForwardedSlots(slotNode.children)
}
const {
block: { node: slotNode },
inSlot,
} = context
const forwarded =
inSlot !== 0 &&
slotNode.type === NodeTypes.ELEMENT &&
hasForwardedSlots(slotNode.children)
if (forwarded) context.ir.hasForwardedSlot = true
exitBlock && exitBlock()
@ -141,7 +144,6 @@ function createFallback(
return [fallback, exitBlock]
}
// TODO
function hasForwardedSlots(children: TemplateChildNode[]): boolean {
for (let i = 0; i < children.length; i++) {
const child = children[i]

View File

@ -237,7 +237,14 @@ function createSlotBlock(
const block: SlotBlockIRNode = newBlock(slotNode)
block.props = dir && dir.exp
const exitBlock = context.enterBlock(block)
return [block, exitBlock]
context.inSlot++
return [
block,
() => {
context.inSlot--
exitBlock()
},
]
}
function isNonWhitespaceContent(node: TemplateChildNode): boolean {

View File

@ -7,6 +7,7 @@ import {
createSlot,
createVaporApp,
defineVaporComponent,
forwardedSlotCreator,
insert,
prepend,
renderEffect,
@ -15,7 +16,7 @@ import {
import { currentInstance, nextTick, ref } from '@vue/runtime-dom'
import { makeRender } from './_utils'
import type { DynamicSlot } from '../src/componentSlots'
import { setElementText } from '../src/dom/prop'
import { setElementText, setText } from '../src/dom/prop'
const define = makeRender<any>()
@ -503,4 +504,55 @@ describe('component: slots', () => {
expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
})
})
describe('forwarded slot', () => {
test('should work', async () => {
const Child = defineVaporComponent({
setup() {
return createSlot('foo', null)
},
})
const Parent = defineVaporComponent({
setup() {
const createForwardedSlot = forwardedSlotCreator()
const n2 = createComponent(
Child,
null,
{
foo: () => {
return createForwardedSlot('foo', null)
},
},
true,
)
return n2
},
})
const foo = ref('foo')
const { host } = define({
setup() {
const n2 = createComponent(
Parent,
null,
{
foo: () => {
const n0 = template(' ')() as any
renderEffect(() => setText(n0, foo.value))
return n0
},
},
true,
)
return n2
},
}).render()
expect(host.innerHTML).toBe('foo<!--slot--><!--slot-->')
foo.value = 'bar'
await nextTick()
expect(host.innerHTML).toBe('bar<!--slot--><!--slot-->')
})
})
})