functional.spec.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import Vue from 'vue'
  2. describe('Options functional', () => {
  3. it('should work', done => {
  4. const vm = new Vue({
  5. data: { test: 'foo' },
  6. template: '<div><wrap :msg="test">bar</wrap></div>',
  7. components: {
  8. wrap: {
  9. functional: true,
  10. props: ['msg'],
  11. render (h, { props, children }) {
  12. return h('div', null, [props.msg, ' '].concat(children))
  13. }
  14. }
  15. }
  16. }).$mount()
  17. expect(vm.$el.innerHTML).toBe('<div>foo bar</div>')
  18. vm.test = 'qux'
  19. waitForUpdate(() => {
  20. expect(vm.$el.innerHTML).toBe('<div>qux bar</div>')
  21. }).then(done)
  22. })
  23. it('should expose all props when not declared', done => {
  24. const fn = {
  25. functional: true,
  26. render (h, { props }) {
  27. return h('div', `${props.msg} ${props.kebabMsg}`)
  28. }
  29. }
  30. const vm = new Vue({
  31. data: { test: 'foo' },
  32. render (h) {
  33. return h('div', [
  34. h(fn, {
  35. props: { msg: this.test },
  36. attrs: { 'kebab-msg': 'bar' }
  37. })
  38. ])
  39. }
  40. }).$mount()
  41. expect(vm.$el.innerHTML).toBe('<div>foo bar</div>')
  42. vm.test = 'qux'
  43. waitForUpdate(() => {
  44. expect(vm.$el.innerHTML).toBe('<div>qux bar</div>')
  45. }).then(done)
  46. })
  47. it('should expose data.on as listeners', () => {
  48. const foo = jasmine.createSpy('foo')
  49. const bar = jasmine.createSpy('bar')
  50. const vm = new Vue({
  51. template: '<div><wrap @click="foo" @test="bar"/></div>',
  52. methods: { foo, bar },
  53. components: {
  54. wrap: {
  55. functional: true,
  56. render (h, { listeners }) {
  57. return h('div', {
  58. on: {
  59. click: [listeners.click, () => listeners.test('bar')]
  60. }
  61. })
  62. }
  63. }
  64. }
  65. }).$mount()
  66. triggerEvent(vm.$el.children[0], 'click')
  67. expect(foo).toHaveBeenCalled()
  68. expect(foo.calls.argsFor(0)[0].type).toBe('click') // should have click event
  69. triggerEvent(vm.$el.children[0], 'mousedown')
  70. expect(bar).toHaveBeenCalledWith('bar')
  71. })
  72. it('should support returning more than one root node', () => {
  73. const vm = new Vue({
  74. template: `<div><test></test></div>`,
  75. components: {
  76. test: {
  77. functional: true,
  78. render (h) {
  79. return [h('span', 'foo'), h('span', 'bar')]
  80. }
  81. }
  82. }
  83. }).$mount()
  84. expect(vm.$el.innerHTML).toBe('<span>foo</span><span>bar</span>')
  85. })
  86. it('should support slots', () => {
  87. const vm = new Vue({
  88. data: { test: 'foo' },
  89. template: '<div><wrap><div slot="a">foo</div><div slot="b">bar</div></wrap></div>',
  90. components: {
  91. wrap: {
  92. functional: true,
  93. props: ['msg'],
  94. render (h, { slots }) {
  95. slots = slots()
  96. return h('div', null, [slots.b, slots.a])
  97. }
  98. }
  99. }
  100. }).$mount()
  101. expect(vm.$el.innerHTML).toBe('<div><div>bar</div><div>foo</div></div>')
  102. })
  103. it('should let vnode raw data pass through', done => {
  104. const onValid = jasmine.createSpy('valid')
  105. const vm = new Vue({
  106. data: { msg: 'hello' },
  107. template: `<div>
  108. <validate field="field1" @valid="onValid">
  109. <input type="text" v-model="msg">
  110. </validate>
  111. </div>`,
  112. components: {
  113. validate: {
  114. functional: true,
  115. props: ['field'],
  116. render (h, { props, children, data: { on }}) {
  117. props.child = children[0]
  118. return h('validate-control', { props, on })
  119. }
  120. },
  121. 'validate-control': {
  122. props: ['field', 'child'],
  123. render () {
  124. return this.child
  125. },
  126. mounted () {
  127. this.$el.addEventListener('input', this.onInput)
  128. },
  129. destroyed () {
  130. this.$el.removeEventListener('input', this.onInput)
  131. },
  132. methods: {
  133. onInput (e) {
  134. const value = e.target.value
  135. if (this.validate(value)) {
  136. this.$emit('valid', this)
  137. }
  138. },
  139. // something validation logic here
  140. validate (val) {
  141. return val.length > 0
  142. }
  143. }
  144. }
  145. },
  146. methods: { onValid }
  147. }).$mount()
  148. document.body.appendChild(vm.$el)
  149. const input = vm.$el.querySelector('input')
  150. expect(onValid).not.toHaveBeenCalled()
  151. waitForUpdate(() => {
  152. input.value = 'foo'
  153. triggerEvent(input, 'input')
  154. }).then(() => {
  155. expect(onValid).toHaveBeenCalled()
  156. }).then(() => {
  157. document.body.removeChild(vm.$el)
  158. vm.$destroy()
  159. }).then(done)
  160. })
  161. })