if.spec.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import Vue from 'vue'
  2. describe('Directive v-if', () => {
  3. it('should check if value is truthy', () => {
  4. const vm = new Vue({
  5. template: '<div><span v-if="foo">hello</span></div>',
  6. data: { foo: true }
  7. }).$mount()
  8. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  9. })
  10. it('should check if value is falsy', () => {
  11. const vm = new Vue({
  12. template: '<div><span v-if="foo">hello</span></div>',
  13. data: { foo: false }
  14. }).$mount()
  15. expect(vm.$el.innerHTML).toBe('<!---->')
  16. })
  17. it('should update if value changed', done => {
  18. const vm = new Vue({
  19. template: '<div><span v-if="foo">hello</span></div>',
  20. data: { foo: true }
  21. }).$mount()
  22. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  23. vm.foo = false
  24. waitForUpdate(() => {
  25. expect(vm.$el.innerHTML).toBe('<!---->')
  26. vm.foo = {}
  27. })
  28. .then(() => {
  29. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  30. vm.foo = 0
  31. })
  32. .then(() => {
  33. expect(vm.$el.innerHTML).toBe('<!---->')
  34. vm.foo = []
  35. })
  36. .then(() => {
  37. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  38. vm.foo = null
  39. })
  40. .then(() => {
  41. expect(vm.$el.innerHTML).toBe('<!---->')
  42. vm.foo = '0'
  43. })
  44. .then(() => {
  45. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  46. vm.foo = undefined
  47. })
  48. .then(() => {
  49. expect(vm.$el.innerHTML).toBe('<!---->')
  50. vm.foo = 1
  51. })
  52. .then(() => {
  53. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  54. })
  55. .then(done)
  56. })
  57. it('should work well with v-else', done => {
  58. const vm = new Vue({
  59. template: `
  60. <div>
  61. <span v-if="foo">hello</span>
  62. <span v-else>bye</span>
  63. </div>
  64. `,
  65. data: { foo: true }
  66. }).$mount()
  67. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  68. vm.foo = false
  69. waitForUpdate(() => {
  70. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  71. vm.foo = {}
  72. })
  73. .then(() => {
  74. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  75. vm.foo = 0
  76. })
  77. .then(() => {
  78. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  79. vm.foo = []
  80. })
  81. .then(() => {
  82. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  83. vm.foo = null
  84. })
  85. .then(() => {
  86. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  87. vm.foo = '0'
  88. })
  89. .then(() => {
  90. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  91. vm.foo = undefined
  92. })
  93. .then(() => {
  94. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  95. vm.foo = 1
  96. })
  97. .then(() => {
  98. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  99. })
  100. .then(done)
  101. })
  102. it('should work well with v-else-if', done => {
  103. const vm = new Vue({
  104. template: `
  105. <div>
  106. <span v-if="foo">hello</span>
  107. <span v-else-if="bar">elseif</span>
  108. <span v-else>bye</span>
  109. </div>
  110. `,
  111. data: { foo: true, bar: false }
  112. }).$mount()
  113. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  114. vm.foo = false
  115. waitForUpdate(() => {
  116. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  117. vm.bar = true
  118. })
  119. .then(() => {
  120. expect(vm.$el.innerHTML.trim()).toBe('<span>elseif</span>')
  121. vm.bar = false
  122. })
  123. .then(() => {
  124. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  125. vm.foo = true
  126. })
  127. .then(() => {
  128. expect(vm.$el.innerHTML.trim()).toBe('<span>hello</span>')
  129. vm.foo = false
  130. vm.bar = {}
  131. })
  132. .then(() => {
  133. expect(vm.$el.innerHTML.trim()).toBe('<span>elseif</span>')
  134. vm.bar = 0
  135. })
  136. .then(() => {
  137. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  138. vm.bar = []
  139. })
  140. .then(() => {
  141. expect(vm.$el.innerHTML.trim()).toBe('<span>elseif</span>')
  142. vm.bar = null
  143. })
  144. .then(() => {
  145. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  146. vm.bar = '0'
  147. })
  148. .then(() => {
  149. expect(vm.$el.innerHTML.trim()).toBe('<span>elseif</span>')
  150. vm.bar = undefined
  151. })
  152. .then(() => {
  153. expect(vm.$el.innerHTML.trim()).toBe('<span>bye</span>')
  154. vm.bar = 1
  155. })
  156. .then(() => {
  157. expect(vm.$el.innerHTML.trim()).toBe('<span>elseif</span>')
  158. })
  159. .then(done)
  160. })
  161. it('should work well with v-for', done => {
  162. const vm = new Vue({
  163. template: `
  164. <div>
  165. <span v-for="(item, i) in list" v-if="item.value">{{i}}</span>
  166. </div>
  167. `,
  168. data: {
  169. list: [{ value: true }, { value: false }, { value: true }]
  170. }
  171. }).$mount()
  172. expect(vm.$el.innerHTML).toBe('<span>0</span><!----><span>2</span>')
  173. vm.list[0].value = false
  174. waitForUpdate(() => {
  175. expect(vm.$el.innerHTML).toBe('<!----><!----><span>2</span>')
  176. vm.list.push({ value: true })
  177. })
  178. .then(() => {
  179. expect(vm.$el.innerHTML).toBe(
  180. '<!----><!----><span>2</span><span>3</span>'
  181. )
  182. vm.list.splice(1, 2)
  183. })
  184. .then(() => {
  185. expect(vm.$el.innerHTML).toBe('<!----><span>1</span>')
  186. })
  187. .then(done)
  188. })
  189. it('should work well with v-for and v-else', done => {
  190. const vm = new Vue({
  191. template: `
  192. <div>
  193. <span v-for="(item, i) in list" v-if="item.value">hello</span>
  194. <span v-else>bye</span>
  195. </div>
  196. `,
  197. data: {
  198. list: [{ value: true }, { value: false }, { value: true }]
  199. }
  200. }).$mount()
  201. expect(vm.$el.innerHTML.trim()).toBe(
  202. '<span>hello</span><span>bye</span><span>hello</span>'
  203. )
  204. vm.list[0].value = false
  205. waitForUpdate(() => {
  206. expect(vm.$el.innerHTML.trim()).toBe(
  207. '<span>bye</span><span>bye</span><span>hello</span>'
  208. )
  209. vm.list.push({ value: true })
  210. })
  211. .then(() => {
  212. expect(vm.$el.innerHTML.trim()).toBe(
  213. '<span>bye</span><span>bye</span><span>hello</span><span>hello</span>'
  214. )
  215. vm.list.splice(1, 2)
  216. })
  217. .then(() => {
  218. expect(vm.$el.innerHTML.trim()).toBe(
  219. '<span>bye</span><span>hello</span>'
  220. )
  221. })
  222. .then(done)
  223. })
  224. it('should work with v-for on v-else branch', done => {
  225. const vm = new Vue({
  226. template: `
  227. <div>
  228. <span v-if="false">hello</span>
  229. <span v-else v-for="item in list">{{ item }}</span>
  230. </div>
  231. `,
  232. data: {
  233. list: [1, 2, 3]
  234. }
  235. }).$mount()
  236. expect(vm.$el.textContent.trim()).toBe('123')
  237. vm.list.reverse()
  238. waitForUpdate(() => {
  239. expect(vm.$el.textContent.trim()).toBe('321')
  240. }).then(done)
  241. })
  242. it('should work properly on component root', done => {
  243. const vm = new Vue({
  244. template: `
  245. <div>
  246. <test class="test"></test>
  247. </div>
  248. `,
  249. components: {
  250. test: {
  251. data() {
  252. return { ok: true }
  253. },
  254. template: '<div v-if="ok" id="ok" class="inner">test</div>'
  255. }
  256. }
  257. }).$mount()
  258. expect(vm.$el.children[0].id).toBe('ok')
  259. expect(vm.$el.children[0].className).toBe('inner test')
  260. vm.$children[0].ok = false
  261. waitForUpdate(() => {
  262. // attrs / class modules should not attempt to patch the comment node
  263. expect(vm.$el.innerHTML).toBe('<!---->')
  264. vm.$children[0].ok = true
  265. })
  266. .then(() => {
  267. expect(vm.$el.children[0].id).toBe('ok')
  268. expect(vm.$el.children[0].className).toBe('inner test')
  269. })
  270. .then(done)
  271. })
  272. it('should maintain stable list to avoid unnecessary patches', done => {
  273. const created = vi.fn()
  274. const destroyed = vi.fn()
  275. const vm = new Vue({
  276. data: {
  277. ok: true
  278. },
  279. // when the first div is toggled, the second div should be reused
  280. // instead of re-created/destroyed
  281. template: `
  282. <div>
  283. <div v-if="ok"></div>
  284. <div><test></test></div>
  285. </div>
  286. `,
  287. components: {
  288. test: {
  289. template: '<div></div>',
  290. created,
  291. destroyed
  292. }
  293. }
  294. }).$mount()
  295. expect(created.mock.calls.length).toBe(1)
  296. vm.ok = false
  297. waitForUpdate(() => {
  298. expect(created.mock.calls.length).toBe(1)
  299. expect(destroyed).not.toHaveBeenCalled()
  300. }).then(done)
  301. })
  302. })