vue3-yuanma/packages/runtime-core/__tests__/scopeId.spec.ts
Evan You 02cbbb718c perf: support only attaching slot scope ids when necessary
This is done by adding the `slotted: false` option to:

- compiler-dom
- compiler-ssr
- compiler-sfc (forwarded to template compiler)

At runtime, only slotted component will render slot fragments with
slot scope Ids. For SSR, only slotted component will add slot scope Ids
to rendered slot content. This should improve both runtime performance
and reduce SSR rendered markup size.

Note: requires SFC tooling (e.g. `vue-loader` and `vite`) to pass on
the `slotted` option from the SFC descriptoer to the `compileTemplate`
call.
2021-03-05 18:28:12 -05:00

181 lines
4.4 KiB
TypeScript

import {
h,
render,
nodeOps,
serializeInner,
renderSlot
} from '@vue/runtime-test'
import { setScopeId, withCtx } from '../src/componentRenderContext'
describe('scopeId runtime support', () => {
test('should attach scopeId', () => {
const App = {
__scopeId: 'parent',
render: () => h('div', [h('div')])
}
const root = nodeOps.createElement('div')
render(h(App), root)
expect(serializeInner(root)).toBe(`<div parent><div parent></div></div>`)
})
test('should attach scopeId to components in parent component', () => {
const Child = {
__scopeId: 'child',
render: () => h('div')
}
const App = {
__scopeId: 'parent',
render: () => h('div', [h(Child)])
}
const root = nodeOps.createElement('div')
render(h(App), root)
expect(serializeInner(root)).toBe(
`<div parent><div child parent></div></div>`
)
})
// :slotted basic
test('should work on slots', () => {
const Child = {
__scopeId: 'child',
render(this: any) {
return h('div', renderSlot(this.$slots, 'default', {}, undefined, true))
}
}
const Child2 = {
__scopeId: 'child2',
render: () => h('span')
}
const App = {
__scopeId: 'parent',
render: () => {
return h(
Child,
withCtx(() => {
return [h('div'), h(Child2)]
})
)
}
}
const root = nodeOps.createElement('div')
render(h(App), root)
// slot content should have:
// - scopeId from parent
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
expect(serializeInner(root)).toBe(
`<div child parent>` +
`<div parent child-s></div>` +
// component inside slot should have:
// - scopeId from template context
// - slotted scopeId from slot owner
// - its own scopeId
`<span child2 parent child-s></span>` +
`</div>`
)
})
// #2892
test(':slotted on forwarded slots', async () => {
const Wrapper = {
__scopeId: 'wrapper',
render(this: any) {
// <div class="wrapper"><slot/></div>
return h('div', { class: 'wrapper' }, [
renderSlot(this.$slots, 'default')
])
}
}
const Slotted = {
__scopeId: 'slotted',
render(this: any) {
// <Wrapper><slot/></Wrapper>
return h(Wrapper, null, {
default: withCtx(() => [
renderSlot(this.$slots, 'default', {}, undefined, true)
])
})
}
}
// simulate hoisted node
setScopeId('root')
const hoisted = h('div', 'hoisted')
setScopeId(null)
const Root = {
__scopeId: 'root',
render(this: any) {
// <Slotted><div>hoisted</div><div>{{ dynamic }}</div></Slotted>
return h(Slotted, null, {
default: withCtx(() => {
return [hoisted, h('div', 'dynamic')]
})
})
}
}
const root = nodeOps.createElement('div')
render(h(Root), root)
expect(serializeInner(root)).toBe(
`<div class="wrapper" wrapper slotted root>` +
`<div root slotted-s>hoisted</div>` +
`<div root slotted-s>dynamic</div>` +
`</div>`
)
const Root2 = {
__scopeId: 'root',
render(this: any) {
// <Slotted>
// <Wrapper>
// <div>hoisted</div><div>{{ dynamic }}</div>
// </Wrapper>
// </Slotted>
return h(Slotted, null, {
default: withCtx(() => [
h(Wrapper, null, {
default: withCtx(() => [hoisted, h('div', 'dynamic')])
})
])
})
}
}
const root2 = nodeOps.createElement('div')
render(h(Root2), root2)
expect(serializeInner(root2)).toBe(
`<div class="wrapper" wrapper slotted root>` +
`<div class="wrapper" wrapper root slotted-s>` +
`<div root>hoisted</div>` +
`<div root>dynamic</div>` +
`</div>` +
`</div>`
)
})
// #1988
test('should inherit scopeId through nested HOCs with inheritAttrs: false', () => {
const App = {
__scopeId: 'parent',
render: () => {
return h(Child)
}
}
function Child() {
return h(Child2, { class: 'foo' })
}
function Child2() {
return h('div')
}
Child2.inheritAttrs = false
const root = nodeOps.createElement('div')
render(h(App), root)
expect(serializeInner(root)).toBe(`<div parent></div>`)
})
})