class.spec.ts 5.8 KB

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