class.spec.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import Vue from 'vue'
  2. function assertClass (assertions, done) {
  3. const vm = new Vue({
  4. template: '<div class="foo" :class="value"></div>',
  5. data: { value: '' }
  6. }).$mount()
  7. const chain = waitForUpdate()
  8. assertions.forEach(([value, expected], i) => {
  9. chain.then(() => {
  10. if (typeof value === 'function') {
  11. value(vm.value)
  12. } else {
  13. vm.value = value
  14. }
  15. }).then(() => {
  16. expect(vm.$el.className).toBe(expected)
  17. if (i >= assertions.length - 1) {
  18. done()
  19. }
  20. })
  21. })
  22. chain.then(done)
  23. }
  24. describe('Directive v-bind:class', () => {
  25. it('plain string', done => {
  26. assertClass([
  27. ['bar', 'foo bar'],
  28. ['baz qux', 'foo baz qux'],
  29. ['qux', 'foo qux'],
  30. [undefined, 'foo']
  31. ], done)
  32. })
  33. it('object value', done => {
  34. assertClass([
  35. [{ bar: true, baz: false }, 'foo bar'],
  36. [{ baz: true }, 'foo baz'],
  37. [null, 'foo'],
  38. [{ 'bar baz': true, qux: false }, 'foo bar baz'],
  39. [{ qux: true }, 'foo qux']
  40. ], done)
  41. })
  42. it('array value', done => {
  43. assertClass([
  44. [['bar', 'baz'], 'foo bar baz'],
  45. [['qux', 'baz'], 'foo qux baz'],
  46. [['w', 'x y z'], 'foo w x y z'],
  47. [undefined, 'foo'],
  48. [['bar'], 'foo bar'],
  49. [val => val.push('baz'), 'foo bar baz']
  50. ], done)
  51. })
  52. it('array of mixed values', done => {
  53. assertClass([
  54. [['x', { y: true, z: true }], 'foo x y z'],
  55. [['x', { y: true, z: false }], 'foo x y'],
  56. [['f', { z: true }], 'foo f z'],
  57. [['l', 'f', { n: true, z: true }], 'foo l f n z'],
  58. [['x', {}], 'foo x'],
  59. [undefined, 'foo']
  60. ], done)
  61. })
  62. it('class merge between parent and child', done => {
  63. const vm = new Vue({
  64. template: '<child class="a" :class="value"></child>',
  65. data: { value: 'b' },
  66. components: {
  67. child: {
  68. template: '<div class="c" :class="value"></div>',
  69. data: () => ({ value: 'd' })
  70. }
  71. }
  72. }).$mount()
  73. const child = vm.$children[0]
  74. expect(vm.$el.className).toBe('c a d b')
  75. vm.value = 'e'
  76. waitForUpdate(() => {
  77. expect(vm.$el.className).toBe('c a d e')
  78. }).then(() => {
  79. child.value = 'f'
  80. }).then(() => {
  81. expect(vm.$el.className).toBe('c a f e')
  82. }).then(() => {
  83. vm.value = { foo: true }
  84. child.value = ['bar', 'baz']
  85. }).then(() => {
  86. expect(vm.$el.className).toBe('c a bar baz foo')
  87. }).then(done)
  88. })
  89. it('class merge between multiple nested components sharing same element', done => {
  90. const vm = new Vue({
  91. template: `
  92. <component1 :class="componentClass1">
  93. <component2 :class="componentClass2">
  94. <component3 :class="componentClass3">
  95. some text
  96. </component3>
  97. </component2>
  98. </component1>
  99. `,
  100. data: {
  101. componentClass1: 'componentClass1',
  102. componentClass2: 'componentClass2',
  103. componentClass3: 'componentClass3'
  104. },
  105. components: {
  106. component1: {
  107. render () {
  108. return this.$slots.default[0]
  109. }
  110. },
  111. component2: {
  112. render () {
  113. return this.$slots.default[0]
  114. }
  115. },
  116. component3: {
  117. template: '<div class="staticClass"><slot></slot></div>'
  118. }
  119. }
  120. }).$mount()
  121. expect(vm.$el.className).toBe('staticClass componentClass3 componentClass2 componentClass1')
  122. vm.componentClass1 = 'c1'
  123. waitForUpdate(() => {
  124. expect(vm.$el.className).toBe('staticClass componentClass3 componentClass2 c1')
  125. vm.componentClass2 = 'c2'
  126. }).then(() => {
  127. expect(vm.$el.className).toBe('staticClass componentClass3 c2 c1')
  128. vm.componentClass3 = 'c3'
  129. }).then(() => {
  130. expect(vm.$el.className).toBe('staticClass c3 c2 c1')
  131. }).then(done)
  132. })
  133. it('deep update', done => {
  134. const vm = new Vue({
  135. template: '<div :class="test"></div>',
  136. data: {
  137. test: { a: true, b: false }
  138. }
  139. }).$mount()
  140. expect(vm.$el.className).toBe('a')
  141. vm.test.b = true
  142. waitForUpdate(() => {
  143. expect(vm.$el.className).toBe('a b')
  144. }).then(done)
  145. })
  146. // css static classes should only contain a single space in between,
  147. // as all the text inside of classes is shipped as a JS string
  148. // and this could lead to useless spacing in static classes
  149. it('condenses whitespace in staticClass', done => {
  150. const vm = new Vue({
  151. template: '<div class=" test1\ntest2\ttest3 test4 test5 \n \n \ntest6\t"></div>',
  152. }).$mount()
  153. expect(vm.$el.className).toBe('test1 test2 test3 test4 test5 test6')
  154. done()
  155. })
  156. it('condenses whitespace in staticClass merge in a component', done => {
  157. const vm = new Vue({
  158. template: `
  159. <component1 class="\n\t staticClass \t\n" :class="componentClass1">
  160. </component1>
  161. `,
  162. data: {
  163. componentClass1: 'componentClass1',
  164. },
  165. components: {
  166. component1: {
  167. template: '<div class="\n\t test \t\n"></div>'
  168. },
  169. }
  170. }).$mount()
  171. expect(vm.$el.className).toBe('test staticClass componentClass1')
  172. vm.componentClass1 = 'c1'
  173. waitForUpdate(() => {
  174. expect(vm.$el.className).toBe('test staticClass c1')
  175. }).then(done)
  176. })
  177. // a vdom patch edge case where the user has several un-keyed elements of the
  178. // same tag next to each other, and toggling them.
  179. it('properly remove staticClass for toggling un-keyed children', done => {
  180. const vm = new Vue({
  181. template: `
  182. <div>
  183. <div v-if="ok" class="a"></div>
  184. <div v-if="!ok"></div>
  185. </div>
  186. `,
  187. data: {
  188. ok: true
  189. }
  190. }).$mount()
  191. expect(vm.$el.children[0].className).toBe('a')
  192. vm.ok = false
  193. waitForUpdate(() => {
  194. expect(vm.$el.children[0].className).toBe('')
  195. }).then(done)
  196. })
  197. })