import { ShapeFlags } from '@vue/shared' import Vue from '@vue/compat' import { createComponentInstance } from '../../runtime-core/src/component' import { setCurrentRenderingInstance } from '../../runtime-core/src/componentRenderContext' import type { DirectiveBinding } from '../../runtime-core/src/directives' import { createVNode } from '../../runtime-core/src/vnode' import { DeprecationTypes, deprecationData, toggleDeprecationWarning, } from '../../runtime-core/src/compat/compatConfig' import { compatH as h } from '../../runtime-core/src/compat/renderFn' beforeEach(() => { toggleDeprecationWarning(false) Vue.configureCompat({ MODE: 2, GLOBAL_MOUNT: 'suppress-warning', }) }) afterEach(() => { toggleDeprecationWarning(false) Vue.configureCompat({ MODE: 3 }) }) describe('compat: render function', () => { const mockDir = {} const mockChildComp = {} const mockComponent = { directives: { mockDir, }, components: { foo: mockChildComp, }, } const mockInstance = createComponentInstance( createVNode(mockComponent), null, null, ) beforeEach(() => { setCurrentRenderingInstance(mockInstance) }) afterEach(() => { setCurrentRenderingInstance(null) }) test('string component lookup', () => { expect(h('foo')).toMatchObject({ type: mockChildComp, }) }) test('class / style / attrs / domProps / props', () => { expect( h('div', { class: 'foo', style: { color: 'red' }, attrs: { id: 'foo', }, domProps: { innerHTML: 'hi', }, props: { myProp: 'foo', }, }), ).toMatchObject({ props: { class: 'foo', style: { color: 'red' }, id: 'foo', innerHTML: 'hi', myProp: 'foo', }, }) }) test('staticClass + class', () => { expect( h('div', { class: { foo: true }, staticClass: 'bar', }), ).toMatchObject({ props: { class: 'bar foo', }, }) }) test('staticStyle + style', () => { expect( h('div', { style: { color: 'red' }, staticStyle: { fontSize: '14px' }, }), ).toMatchObject({ props: { style: { color: 'red', fontSize: '14px', }, }, }) }) test('on / nativeOn', () => { const fn = () => {} expect( h('div', { on: { click: fn, fooBar: fn, }, nativeOn: { click: fn, 'bar-baz': fn, }, }), ).toMatchObject({ props: { onClick: fn, onClickNative: fn, onFooBar: fn, 'onBar-bazNative': fn, }, }) }) test('v2 legacy event prefixes', () => { const fn = () => {} expect( h('div', { on: { '&click': fn, '~keyup': fn, '!touchend': fn, }, }), ).toMatchObject({ props: { onClickPassive: fn, onKeyupOnce: fn, onTouchendCapture: fn, }, }) }) test('directives', () => { expect( h('div', { directives: [ { name: 'mock-dir', value: '2', // expression: '1 + 1', arg: 'foo', modifiers: { bar: true, }, }, ], }), ).toMatchObject({ dirs: [ { dir: mockDir, instance: mockInstance.proxy, value: '2', oldValue: void 0, arg: 'foo', modifiers: { bar: true, }, }, ] as DirectiveBinding[], }) }) test('scopedSlots', () => { const scopedSlots = { default() {}, } const vnode = h(mockComponent, { scopedSlots, }) expect(vnode).toMatchObject({ children: scopedSlots, }) expect('scopedSlots' in vnode.props!).toBe(false) expect(vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN).toBeTruthy() }) test('legacy named slot', () => { const vnode = h(mockComponent, [ 'text', h('div', { slot: 'foo' }, 'one'), h('div', { slot: 'bar' }, 'two'), h('div', { slot: 'foo' }, 'three'), h('div', 'four'), ]) expect(vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN).toBeTruthy() const slots = vnode.children as any // default expect(slots.default()).toMatchObject(['text', { children: 'four' }]) expect(slots.foo()).toMatchObject([ { children: 'one' }, { children: 'three' }, ]) expect(slots.bar()).toMatchObject([{ children: 'two' }]) }) test('in component usage', () => { toggleDeprecationWarning(true) const vm = new Vue({ render(h: any) { return h( 'div', { class: 'foo', attrs: { id: 'bar' }, }, 'hello', ) }, }).$mount() expect(vm.$el).toBeInstanceOf(HTMLDivElement) expect(vm.$el.outerHTML).toBe(`