model-select.spec.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import Vue from 'vue'
  2. import { looseEqual } from 'shared/util'
  3. /**
  4. * setting <select>'s value in IE9 doesn't work
  5. * we have to manually loop through the options
  6. */
  7. function updateSelect (el, value) {
  8. var options = el.options
  9. var i = options.length
  10. while (i--) {
  11. if (looseEqual(getValue(options[i]), value)) {
  12. options[i].selected = true
  13. break
  14. }
  15. }
  16. }
  17. function getValue (option) {
  18. return '_value' in option
  19. ? option._value
  20. : option.value || option.text
  21. }
  22. describe('Directive v-model select', () => {
  23. it('should work', done => {
  24. const vm = new Vue({
  25. data: {
  26. test: 'b'
  27. },
  28. template:
  29. '<select v-model="test">' +
  30. '<option>a</option>' +
  31. '<option>b</option>' +
  32. '<option>c</option>' +
  33. '</select>'
  34. }).$mount()
  35. document.body.appendChild(vm.$el)
  36. expect(vm.test).toBe('b')
  37. expect(vm.$el.value).toBe('b')
  38. expect(vm.$el.childNodes[1].selected).toBe(true)
  39. vm.test = 'c'
  40. waitForUpdate(function () {
  41. expect(vm.$el.value).toBe('c')
  42. expect(vm.$el.childNodes[2].selected).toBe(true)
  43. updateSelect(vm.$el, 'a')
  44. triggerEvent(vm.$el, 'change')
  45. expect(vm.test).toBe('a')
  46. }).then(done)
  47. })
  48. it('should work with value bindings', done => {
  49. const vm = new Vue({
  50. data: {
  51. test: 2
  52. },
  53. template:
  54. '<select v-model="test">' +
  55. '<option value="1">a</option>' +
  56. '<option :value="2">b</option>' +
  57. '<option :value="3">c</option>' +
  58. '</select>'
  59. }).$mount()
  60. document.body.appendChild(vm.$el)
  61. expect(vm.$el.value).toBe('2')
  62. expect(vm.$el.childNodes[1].selected).toBe(true)
  63. vm.test = 3
  64. waitForUpdate(function () {
  65. expect(vm.$el.value).toBe('3')
  66. expect(vm.$el.childNodes[2].selected).toBe(true)
  67. updateSelect(vm.$el, '1')
  68. triggerEvent(vm.$el, 'change')
  69. expect(vm.test).toBe('1')
  70. }).then(done)
  71. })
  72. it('should work with value bindings (object loose equal)', done => {
  73. const vm = new Vue({
  74. data: {
  75. test: { a: 2 }
  76. },
  77. template:
  78. '<select v-model="test">' +
  79. '<option value="1">a</option>' +
  80. '<option :value="{ a: 2 }">b</option>' +
  81. '<option :value="{ a: 3 }">c</option>' +
  82. '</select>'
  83. }).$mount()
  84. document.body.appendChild(vm.$el)
  85. expect(vm.$el.childNodes[1].selected).toBe(true)
  86. vm.test = { a: 3 }
  87. waitForUpdate(function () {
  88. expect(vm.$el.childNodes[2].selected).toBe(true)
  89. updateSelect(vm.$el, '1')
  90. triggerEvent(vm.$el, 'change')
  91. expect(vm.test).toBe('1')
  92. updateSelect(vm.$el, { a: 2 })
  93. triggerEvent(vm.$el, 'change')
  94. expect(vm.test).toEqual({ a: 2 })
  95. }).then(done)
  96. })
  97. it('should work with v-for', done => {
  98. const vm = new Vue({
  99. data: {
  100. test: 'b',
  101. opts: ['a', 'b', 'c']
  102. },
  103. template:
  104. '<select v-model="test">' +
  105. '<option v-for="o in opts">{{ o }}</option>' +
  106. '</select>'
  107. }).$mount()
  108. document.body.appendChild(vm.$el)
  109. expect(vm.test).toBe('b')
  110. expect(vm.$el.value).toBe('b')
  111. expect(vm.$el.childNodes[1].selected).toBe(true)
  112. vm.test = 'c'
  113. waitForUpdate(function () {
  114. expect(vm.$el.value).toBe('c')
  115. expect(vm.$el.childNodes[2].selected).toBe(true)
  116. updateSelect(vm.$el, 'a')
  117. triggerEvent(vm.$el, 'change')
  118. expect(vm.test).toBe('a')
  119. // update v-for opts
  120. vm.opts = ['d', 'a']
  121. }).then(() => {
  122. expect(vm.$el.childNodes[0].selected).toBe(false)
  123. expect(vm.$el.childNodes[1].selected).toBe(true)
  124. }).then(done)
  125. })
  126. it('should work with v-for & value bindings', done => {
  127. const vm = new Vue({
  128. data: {
  129. test: 2,
  130. opts: [1, 2, 3]
  131. },
  132. template:
  133. '<select v-model="test">' +
  134. '<option v-for="o in opts" :value="o">optio {{ o }}</option>' +
  135. '</select>'
  136. }).$mount()
  137. document.body.appendChild(vm.$el)
  138. expect(vm.$el.value).toBe('2')
  139. expect(vm.$el.childNodes[1].selected).toBe(true)
  140. vm.test = 3
  141. waitForUpdate(function () {
  142. expect(vm.$el.value).toBe('3')
  143. expect(vm.$el.childNodes[2].selected).toBe(true)
  144. updateSelect(vm.$el, 1)
  145. triggerEvent(vm.$el, 'change')
  146. expect(vm.test).toBe(1)
  147. // update v-for opts
  148. vm.opts = [0, 1]
  149. }).then(() => {
  150. expect(vm.$el.childNodes[0].selected).toBe(false)
  151. expect(vm.$el.childNodes[1].selected).toBe(true)
  152. }).then(done)
  153. })
  154. it('multiple', done => {
  155. const vm = new Vue({
  156. data: {
  157. test: ['b']
  158. },
  159. template:
  160. '<select v-model="test" multiple>' +
  161. '<option>a</option>' +
  162. '<option>b</option>' +
  163. '<option>c</option>' +
  164. '</select>'
  165. }).$mount()
  166. var opts = vm.$el.options
  167. expect(opts[0].selected).toBe(false)
  168. expect(opts[1].selected).toBe(true)
  169. expect(opts[2].selected).toBe(false)
  170. vm.test = ['a', 'c']
  171. waitForUpdate(() => {
  172. expect(opts[0].selected).toBe(true)
  173. expect(opts[1].selected).toBe(false)
  174. expect(opts[2].selected).toBe(true)
  175. opts[0].selected = false
  176. opts[1].selected = true
  177. triggerEvent(vm.$el, 'change')
  178. expect(vm.test).toEqual(['b', 'c'])
  179. }).then(done)
  180. })
  181. it('multiple with static template', () => {
  182. const vm = new Vue({
  183. template:
  184. '<select multiple>' +
  185. '<option selected>a</option>' +
  186. '<option selected>b</option>' +
  187. '<option selected>c</option>' +
  188. '</select>'
  189. }).$mount()
  190. var opts = vm.$el.options
  191. expect(opts[0].selected).toBe(true)
  192. expect(opts[1].selected).toBe(true)
  193. expect(opts[2].selected).toBe(true)
  194. })
  195. it('multiple + v-for', done => {
  196. const vm = new Vue({
  197. data: {
  198. test: ['b'],
  199. opts: ['a', 'b', 'c']
  200. },
  201. template:
  202. '<select v-model="test" multiple>' +
  203. '<option v-for="o in opts">{{ o }}</option>' +
  204. '</select>'
  205. }).$mount()
  206. var opts = vm.$el.options
  207. expect(opts[0].selected).toBe(false)
  208. expect(opts[1].selected).toBe(true)
  209. expect(opts[2].selected).toBe(false)
  210. vm.test = ['a', 'c']
  211. waitForUpdate(() => {
  212. expect(opts[0].selected).toBe(true)
  213. expect(opts[1].selected).toBe(false)
  214. expect(opts[2].selected).toBe(true)
  215. opts[0].selected = false
  216. opts[1].selected = true
  217. triggerEvent(vm.$el, 'change')
  218. expect(vm.test).toEqual(['b', 'c'])
  219. // update v-for opts
  220. vm.opts = ['c', 'd']
  221. }).then(() => {
  222. expect(opts[0].selected).toBe(true)
  223. expect(opts[1].selected).toBe(false)
  224. expect(vm.test).toEqual(['c']) // should remove 'd' which no longer has a matching option
  225. }).then(done)
  226. })
  227. it('should warn inline selected', () => {
  228. const vm = new Vue({
  229. data: {
  230. test: null
  231. },
  232. template:
  233. '<select v-model="test">' +
  234. '<option selected>a</option>' +
  235. '</select>'
  236. }).$mount()
  237. expect(vm.$el.selectedIndex).toBe(-1)
  238. expect('inline selected attributes on <option> will be ignored when using v-model')
  239. .toHaveBeenWarned()
  240. })
  241. it('should warn multiple with non-Array value', () => {
  242. new Vue({
  243. data: {
  244. test: 'meh'
  245. },
  246. template:
  247. '<select v-model="test" multiple></select>'
  248. }).$mount()
  249. expect('<select multiple v-model="test"> expects an Array value for its binding, but got String')
  250. .toHaveBeenWarned()
  251. })
  252. })