ref.spec.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import Vue from 'vue'
  2. describe('ref', () => {
  3. type TestShape = {
  4. id: string,
  5. template: string,
  6. data?: any
  7. components?: any
  8. }
  9. type ComponentShape = {
  10. test: TestShape,
  11. test2: TestShape,
  12. test3: TestShape,
  13. }
  14. const components: ComponentShape = {
  15. test: {
  16. id: 'test',
  17. template: '<div>test</div>'
  18. },
  19. test2: {
  20. id: 'test2',
  21. template: '<div>test2</div>'
  22. },
  23. test3: {
  24. id: 'test3',
  25. template: '<div>test3</div>'
  26. }
  27. }
  28. it('should work', () => {
  29. const vm = new Vue({
  30. data: {
  31. value: 'bar'
  32. },
  33. template: `<div>
  34. <test ref="foo"></test>
  35. <test2 :ref="value"></test2>
  36. <test3 :ref="0"></test3>
  37. </div>`,
  38. components
  39. })
  40. vm.$mount()
  41. expect(vm.$refs.foo).toBeTruthy()
  42. expect(vm.$refs.foo.$options.id).toBe('test')
  43. expect(vm.$refs.bar).toBeTruthy()
  44. expect(vm.$refs.bar.$options.id).toBe('test2')
  45. expect(vm.$refs['0']).toBeTruthy()
  46. expect(vm.$refs['0'].$options.id).toBe('test3')
  47. })
  48. it('should dynamically update refs', done => {
  49. const vm = new Vue({
  50. data: {
  51. value: 'foo'
  52. },
  53. template: '<div :ref="value"></div>'
  54. }).$mount()
  55. expect(vm.$refs.foo).toBe(vm.$el)
  56. vm.value = 'bar'
  57. waitForUpdate(() => {
  58. expect(vm.$refs.foo).toBeUndefined()
  59. expect(vm.$refs.bar).toBe(vm.$el)
  60. }).then(done)
  61. })
  62. it('should work as a hyperscript prop', () => {
  63. const vm = new Vue({
  64. components,
  65. render (h) {
  66. return h('div', null, [
  67. h('test', { ref: 'test' })
  68. ])
  69. }
  70. })
  71. vm.$mount()
  72. expect(vm.$refs.test).toBeTruthy()
  73. expect(vm.$refs.test.$options.id).toBe('test')
  74. })
  75. it('should accept HOC component', () => {
  76. const vm = new Vue({
  77. template: '<test ref="test"></test>',
  78. components
  79. })
  80. vm.$mount()
  81. expect(vm.$refs.test).toBeTruthy()
  82. expect(vm.$refs.test.$options.id).toBe('test')
  83. })
  84. it('should accept dynamic component', done => {
  85. const vm = new Vue({
  86. template: `<div>
  87. <component :is="test" ref="test"></component>
  88. </div>`,
  89. components,
  90. data: { test: 'test' }
  91. })
  92. vm.$mount()
  93. expect(vm.$refs.test.$options.id).toBe('test')
  94. vm.test = 'test2'
  95. waitForUpdate(() => {
  96. expect(vm.$refs.test.$options.id).toBe('test2')
  97. vm.test = ''
  98. }).then(() => {
  99. expect(vm.$refs.test).toBeUndefined()
  100. }).then(done)
  101. })
  102. it('should register as Array when used with v-for', done => {
  103. const vm = new Vue({
  104. data: {
  105. items: [1, 2, 3]
  106. },
  107. template: `
  108. <div>
  109. <div v-for="n in items" ref="list">{{n}}</div>
  110. </div>
  111. `
  112. }).$mount()
  113. assertRefs()
  114. // updating
  115. vm.items.push(4)
  116. waitForUpdate(assertRefs)
  117. .then(() => { vm.items = [] })
  118. .then(assertRefs)
  119. .then(done)
  120. function assertRefs () {
  121. expect(Array.isArray(vm.$refs.list)).toBe(true)
  122. expect(vm.$refs.list.length).toBe(vm.items.length)
  123. expect(vm.$refs.list.every((item, i) => item.textContent === String(i + 1))).toBe(true)
  124. }
  125. })
  126. it('should register as Array when used with v-for (components)', done => {
  127. const vm = new Vue({
  128. data: {
  129. items: [1, 2, 3]
  130. },
  131. template: `
  132. <div>
  133. <test v-for="n in items" ref="list" :key="n" :n="n"></test>
  134. </div>
  135. `,
  136. components: {
  137. test: {
  138. props: ['n'],
  139. template: '<div>{{ n }}</div>'
  140. }
  141. }
  142. }).$mount()
  143. assertRefs()
  144. // updating
  145. vm.items.push(4)
  146. waitForUpdate(assertRefs)
  147. .then(() => { vm.items = [] })
  148. .then(assertRefs)
  149. .then(done)
  150. function assertRefs () {
  151. expect(Array.isArray(vm.$refs.list)).toBe(true)
  152. expect(vm.$refs.list.length).toBe(vm.items.length)
  153. expect(vm.$refs.list.every((comp, i) => comp.$el.textContent === String(i + 1))).toBe(true)
  154. }
  155. })
  156. it('should work with v-for on dynamic component', done => {
  157. components.test3 = {
  158. id: 'test3',
  159. template: `<test1 v-if="!normal"></test1><div v-else>test3</div>`,
  160. data () {
  161. return { normal: false }
  162. },
  163. components: { test1: components.test }
  164. }
  165. // a flag that representing whether to test component content or not
  166. let testContent = false
  167. const vm = new Vue({
  168. template: `
  169. <div>
  170. <component
  171. v-for="(item, index) in items"
  172. :key="index"
  173. :is="item"
  174. ref="children">
  175. </component>
  176. </div>
  177. `,
  178. data: {
  179. items: ['test2', 'test3']
  180. },
  181. components
  182. }).$mount()
  183. assertRefs()
  184. expect(vm.$refs.children[0].$el.textContent).toBe('test2')
  185. expect(vm.$refs.children[1].$el.textContent).toBe('test')
  186. // updating
  187. vm.$refs.children[1].normal = true
  188. testContent = true
  189. waitForUpdate(assertRefs)
  190. .then(() => { vm.items.push('test') })
  191. .then(assertRefs)
  192. .then(done)
  193. function assertRefs () {
  194. expect(Array.isArray(vm.$refs.children)).toBe(true)
  195. expect(vm.$refs.children.length).toBe(vm.items.length)
  196. if (testContent) {
  197. expect(
  198. vm.$refs.children.every((comp, i) => comp.$el.textContent === vm.items[i])
  199. ).toBe(true)
  200. }
  201. }
  202. })
  203. it('should register on component with empty roots', done => {
  204. const vm = new Vue({
  205. template: '<child ref="test"></child>',
  206. components: {
  207. child: {
  208. template: '<div v-if="show"></div>',
  209. data () {
  210. return { show: false }
  211. }
  212. }
  213. }
  214. }).$mount()
  215. expect(vm.$refs.test).toBe(vm.$children[0])
  216. vm.$refs.test.show = true
  217. waitForUpdate(() => {
  218. expect(vm.$refs.test).toBe(vm.$children[0])
  219. vm.$refs.test.show = false
  220. }).then(() => {
  221. expect(vm.$refs.test).toBe(vm.$children[0])
  222. }).then(done)
  223. })
  224. })