await nextTick()
expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
})
+
+ test('render fallback when slot content is not valid', async () => {
+ const Child = {
+ setup() {
+ return createSlot('default', null, () =>
+ document.createTextNode('fallback'),
+ )
+ },
+ }
+
+ const { html } = define({
+ setup() {
+ return createComponent(Child, null, {
+ default: () => {
+ return template('<!--comment-->')()
+ },
+ })
+ },
+ }).render()
+
+ expect(html()).toBe('fallback<!--slot-->')
+ })
+
+ test('render fallback when v-if condition is false', async () => {
+ const Child = {
+ setup() {
+ return createSlot('default', null, () =>
+ document.createTextNode('fallback'),
+ )
+ },
+ }
+
+ const toggle = ref(false)
+
+ const { html } = define({
+ setup() {
+ return createComponent(Child, null, {
+ default: () => {
+ return createIf(
+ () => toggle.value,
+ () => {
+ return document.createTextNode('content')
+ },
+ )
+ },
+ })
+ },
+ }).render()
+
+ expect(html()).toBe('fallback<!--if--><!--slot-->')
+
+ toggle.value = true
+ await nextTick()
+ expect(html()).toBe('content<!--if--><!--slot-->')
+
+ toggle.value = false
+ await nextTick()
+ expect(html()).toBe('fallback<!--if--><!--slot-->')
+ })
})
})
if (this.fallback && !isValidBlock(this.nodes)) {
parent && remove(this.nodes, parent)
- this.nodes =
- (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
- []
+ // if current nodes is a DynamicFragment, call its update with the fallback
+ // to handle nested dynamic fragment
+ if (this.nodes instanceof DynamicFragment) {
+ this.nodes.update(this.fallback)
+ } else {
+ this.nodes =
+ (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
+ []
+ }
parent && insert(this.nodes, parent, this.anchor)
}
const renderSlot = () => {
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
if (slot) {
+ fragment.fallback = fallback
// create and cache bound version of the slot to make it stable
// so that we avoid unnecessary updates if it resolves to the same slot
fragment.update(