h.spec.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { h, transformHArgs, resetTransformHArgs } from '../src/h'
  2. import { createVNode } from '../src/vnode'
  3. import { ComponentInternalInstance } from '@vue/runtime-core'
  4. import { createApp } from '@vue/runtime-dom'
  5. // Since h is a thin layer on top of createVNode, we are only testing its
  6. // own logic here. Details of vnode creation is tested in vnode.spec.ts.
  7. const testH = () => {
  8. test('type only', () => {
  9. expect(h('div')).toMatchObject(createVNode('div'))
  10. })
  11. test('type + props', () => {
  12. expect(h('div', { id: 'foo' })).toMatchObject(
  13. createVNode('div', { id: 'foo' })
  14. )
  15. })
  16. test('type + omit props', () => {
  17. // array
  18. expect(h('div', ['foo'])).toMatchObject(createVNode('div', null, ['foo']))
  19. // default slot
  20. const Component = { template: '<br />' }
  21. const slot = () => {}
  22. expect(h(Component, slot)).toMatchObject(createVNode(Component, null, slot))
  23. // single vnode
  24. const vnode = h('div')
  25. expect(h('div', vnode)).toMatchObject(createVNode('div', null, [vnode]))
  26. // text
  27. expect(h('div', 'foo')).toMatchObject(createVNode('div', null, 'foo'))
  28. })
  29. test('type + props + children', () => {
  30. // array
  31. expect(h('div', {}, ['foo'])).toMatchObject(createVNode('div', {}, ['foo']))
  32. // default slot
  33. const Component = { template: '<br />' }
  34. const slot = () => {}
  35. expect(h(Component, {}, slot)).toMatchObject(
  36. createVNode(Component, {}, slot)
  37. )
  38. // single vnode
  39. const vnode = h('div')
  40. expect(h('div', {}, vnode)).toMatchObject(createVNode('div', {}, [vnode]))
  41. // text
  42. expect(h('div', {}, 'foo')).toMatchObject(createVNode('div', {}, 'foo'))
  43. })
  44. test('named slots with null props', () => {
  45. const Component = { template: '<br />' }
  46. const slot = () => {}
  47. expect(
  48. h(Component, null, {
  49. foo: slot
  50. })
  51. ).toMatchObject(
  52. createVNode(Component, null, {
  53. foo: slot
  54. })
  55. )
  56. })
  57. }
  58. describe('renderer: h', testH)
  59. describe('renderer: transformHArgs', () => {
  60. describe('no-op pass-through', () => {
  61. beforeAll(() => {
  62. transformHArgs((hArgs: unknown[]) => hArgs)
  63. })
  64. afterAll(resetTransformHArgs)
  65. testH()
  66. })
  67. describe('args is used directly, without merging', () => {
  68. beforeAll(() => {
  69. transformHArgs(() => ['h1', 'Hello World'])
  70. })
  71. afterAll(resetTransformHArgs)
  72. test('nodes become an h1 with text inside', () => {
  73. expect(h('div')).toMatchObject(createVNode('h1', null, 'Hello World'))
  74. })
  75. test('resetting transformHArgs turns things back to normal', () => {
  76. expect(h('div')).toMatchObject(createVNode('h1', null, 'Hello World'))
  77. resetTransformHArgs()
  78. expect(h('div')).toMatchObject(createVNode('div'))
  79. })
  80. })
  81. test('receives component instance as the 2nd arg', () => {
  82. transformHArgs((_: unknown[], instance: ComponentInternalInstance) => {
  83. return ['h1', instance.type.name] // <h1>{{ name }}</h1>
  84. })
  85. const vm = createApp({
  86. // this will be the name of the component in the h1
  87. name: 'Root Component',
  88. render() {
  89. return h({
  90. // this code will never execute,
  91. // because it is overridden by the transformHArgs method
  92. render() {
  93. return h('h2', 'Stub Text')
  94. }
  95. })
  96. }
  97. })
  98. // we need to mount everything so that the instance passed to
  99. // transformHArgs isn't null
  100. vm.mount('body')
  101. expect(document.body.outerHTML).toContain('<h1>Root Component</h1>')
  102. })
  103. })