model-select.spec.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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('should work with select which has no default selected options', (done) => {
  155. const spy = jasmine.createSpy()
  156. const vm = new Vue({
  157. data: {
  158. id: 4,
  159. list: [1, 2, 3],
  160. testChange: 5
  161. },
  162. template:
  163. '<div>' +
  164. '<select @change="test" v-model="id">' +
  165. '<option v-for="item in list" :value="item">{{item}}</option>' +
  166. '</select>' +
  167. '{{testChange}}' +
  168. '</div>',
  169. methods: {
  170. test: spy
  171. }
  172. }).$mount()
  173. document.body.appendChild(vm.$el)
  174. vm.testChange = 10
  175. waitForUpdate(() => {
  176. expect(spy.calls.count()).toBe(0)
  177. }).then(done)
  178. })
  179. it('multiple', done => {
  180. const vm = new Vue({
  181. data: {
  182. test: ['b']
  183. },
  184. template:
  185. '<select v-model="test" multiple>' +
  186. '<option>a</option>' +
  187. '<option>b</option>' +
  188. '<option>c</option>' +
  189. '</select>'
  190. }).$mount()
  191. var opts = vm.$el.options
  192. expect(opts[0].selected).toBe(false)
  193. expect(opts[1].selected).toBe(true)
  194. expect(opts[2].selected).toBe(false)
  195. vm.test = ['a', 'c']
  196. waitForUpdate(() => {
  197. expect(opts[0].selected).toBe(true)
  198. expect(opts[1].selected).toBe(false)
  199. expect(opts[2].selected).toBe(true)
  200. opts[0].selected = false
  201. opts[1].selected = true
  202. triggerEvent(vm.$el, 'change')
  203. expect(vm.test).toEqual(['b', 'c'])
  204. }).then(done)
  205. })
  206. it('multiple with static template', () => {
  207. const vm = new Vue({
  208. template:
  209. '<select multiple>' +
  210. '<option selected>a</option>' +
  211. '<option selected>b</option>' +
  212. '<option selected>c</option>' +
  213. '</select>'
  214. }).$mount()
  215. var opts = vm.$el.options
  216. expect(opts[0].selected).toBe(true)
  217. expect(opts[1].selected).toBe(true)
  218. expect(opts[2].selected).toBe(true)
  219. })
  220. it('multiple + v-for', done => {
  221. const vm = new Vue({
  222. data: {
  223. test: ['b'],
  224. opts: ['a', 'b', 'c']
  225. },
  226. template:
  227. '<select v-model="test" multiple>' +
  228. '<option v-for="o in opts">{{ o }}</option>' +
  229. '</select>'
  230. }).$mount()
  231. var opts = vm.$el.options
  232. expect(opts[0].selected).toBe(false)
  233. expect(opts[1].selected).toBe(true)
  234. expect(opts[2].selected).toBe(false)
  235. vm.test = ['a', 'c']
  236. waitForUpdate(() => {
  237. expect(opts[0].selected).toBe(true)
  238. expect(opts[1].selected).toBe(false)
  239. expect(opts[2].selected).toBe(true)
  240. opts[0].selected = false
  241. opts[1].selected = true
  242. triggerEvent(vm.$el, 'change')
  243. expect(vm.test).toEqual(['b', 'c'])
  244. // update v-for opts
  245. vm.opts = ['c', 'd']
  246. }).then(() => {
  247. expect(opts[0].selected).toBe(true)
  248. expect(opts[1].selected).toBe(false)
  249. expect(vm.test).toEqual(['c']) // should remove 'd' which no longer has a matching option
  250. }).then(done)
  251. })
  252. it('should warn inline selected', () => {
  253. const vm = new Vue({
  254. data: {
  255. test: null
  256. },
  257. template:
  258. '<select v-model="test">' +
  259. '<option selected>a</option>' +
  260. '</select>'
  261. }).$mount()
  262. expect(vm.$el.selectedIndex).toBe(-1)
  263. expect('inline selected attributes on <option> will be ignored when using v-model')
  264. .toHaveBeenWarned()
  265. })
  266. it('should warn multiple with non-Array value', () => {
  267. new Vue({
  268. data: {
  269. test: 'meh'
  270. },
  271. template:
  272. '<select v-model="test" multiple></select>'
  273. }).$mount()
  274. expect('<select multiple v-model="test"> expects an Array value for its binding, but got String')
  275. .toHaveBeenWarned()
  276. })
  277. })