import { h, render, nodeOps, serializeInner, renderSlot, withScopeId, pushScopeId, popScopeId } from '@vue/runtime-test' import { 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(`
`) }) 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( `
` ) }) // :slotted basic test('should work on slots', () => { const Child = { __scopeId: 'child', render(this: any) { return h('div', renderSlot(this.$slots, 'default')) } } 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( `
` + `
` + // component inside slot should have: // - scopeId from template context // - slotted scopeId from slot owner // - its own scopeId `` + `
` ) }) // #2892 test(':slotted on forwarded slots', async () => { const Wrapper = { __scopeId: 'wrapper', render(this: any) { //
return h('div', { class: 'wrapper' }, [ renderSlot( this.$slots, 'default', {}, undefined, true /* noSlotted */ ) ]) } } const Slotted = { __scopeId: 'slotted', render(this: any) { // return h(Wrapper, null, { default: withCtx(() => [renderSlot(this.$slots, 'default')]) }) } } // simulate hoisted node pushScopeId('root') const hoisted = h('div', 'hoisted') popScopeId() const Root = { __scopeId: 'root', render(this: any) { //
hoisted
{{ dynamic }}
return h(Slotted, null, { default: withCtx(() => { return [hoisted, h('div', 'dynamic')] }) }) } } const root = nodeOps.createElement('div') render(h(Root), root) expect(serializeInner(root)).toBe( `
` + `
hoisted
` + `
dynamic
` + `
` ) const Root2 = { __scopeId: 'root', render(this: any) { // // //
hoisted
{{ dynamic }}
//
//
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( `
` + `
` + `
hoisted
` + `
dynamic
` + `
` + `
` ) }) // #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(`
`) }) }) describe('backwards compat with <=3.0.7', () => { const withParentId = withScopeId('parent') const withChildId = withScopeId('child') test('should attach scopeId', () => { const App = { __scopeId: 'parent', render: withParentId(() => { return h('div', [h('div')]) }) } const root = nodeOps.createElement('div') render(h(App), root) expect(serializeInner(root)).toBe(`
`) }) test('should attach scopeId to components in parent component', () => { const Child = { __scopeId: 'child', render: withChildId(() => { return h('div') }) } const App = { __scopeId: 'parent', render: withParentId(() => { return h('div', [h(Child)]) }) } const root = nodeOps.createElement('div') render(h(App), root) expect(serializeInner(root)).toBe( `
` ) }) test('should work on slots', () => { const Child = { __scopeId: 'child', render: withChildId(function(this: any) { return h('div', renderSlot(this.$slots, 'default')) }) } const withChild2Id = withScopeId('child2') const Child2 = { __scopeId: 'child2', render: withChild2Id(() => h('span')) } const App = { __scopeId: 'parent', render: withParentId(() => { return h( Child, withParentId(() => { 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( `
` + `
` + // component inside slot should have: // - scopeId from template context // - slotted scopeId from slot owner // - its own scopeId `` + `
` ) }) // #1988 test('should inherit scopeId through nested HOCs with inheritAttrs: false', () => { const withParentId = withScopeId('parent') const App = { __scopeId: 'parent', render: withParentId(() => { 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(`
`) }) test('hoisted nodes', async () => { pushScopeId('foobar') const hoisted = h('div', 'hello') popScopeId() const App = { __scopeId: 'foobar', render: () => h('div', [hoisted]) } const root = nodeOps.createElement('div') render(h(App), root) expect(serializeInner(root)).toBe( `
hello
` ) }) })