class.spec.ts 6.1 KB

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