model_spec.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. var _ = require('../../../../src/util')
  2. var Vue = require('../../../../src/vue')
  3. // unset jQuery to bypass jQuery check for normal test cases
  4. jQuery = null
  5. /**
  6. * Mock event helper
  7. */
  8. function trigger (target, event, process) {
  9. var e = document.createEvent('HTMLEvents')
  10. e.initEvent(event, true, true)
  11. if (process) process(e)
  12. target.dispatchEvent(e)
  13. }
  14. /**
  15. * setting <select>'s value in IE9 doesn't work
  16. * we have to manually loop through the options
  17. */
  18. function updateSelect (el, value) {
  19. var options = el.options
  20. var i = options.length
  21. while (i--) {
  22. /* eslint-disable eqeqeq */
  23. if (options[i].value == value) {
  24. /* eslint-enable eqeqeq */
  25. options[i].selected = true
  26. break
  27. }
  28. }
  29. }
  30. if (_.inBrowser) {
  31. describe('v-model', function () {
  32. var el
  33. beforeEach(function () {
  34. el = document.createElement('div')
  35. el.style.display = 'none'
  36. document.body.appendChild(el)
  37. spyOn(_, 'warn')
  38. })
  39. it('radio buttons', function (done) {
  40. var vm = new Vue({
  41. el: el,
  42. data: {
  43. test: '1'
  44. },
  45. template:
  46. '<input type="radio" value="1" v-model="test" name="test" number>' +
  47. '<input type="radio" value="2" v-model="test" name="test">'
  48. })
  49. expect(el.childNodes[0].checked).toBe(true)
  50. expect(el.childNodes[1].checked).toBe(false)
  51. vm.test = '2'
  52. _.nextTick(function () {
  53. expect(el.childNodes[0].checked).toBe(false)
  54. expect(el.childNodes[1].checked).toBe(true)
  55. el.childNodes[0].click()
  56. expect(el.childNodes[0].checked).toBe(true)
  57. expect(el.childNodes[1].checked).toBe(false)
  58. expect(vm.test).toBe(1)
  59. vm._directives[1]._teardown()
  60. el.childNodes[1].click()
  61. expect(vm.test).toBe(1)
  62. done()
  63. })
  64. })
  65. it('radio default value', function () {
  66. var vm = new Vue({
  67. el: el,
  68. data: {},
  69. template: '<input type="radio" checked value="a" v-model="test">'
  70. })
  71. expect(vm.test).toBe('a')
  72. })
  73. it('radio expression', function (done) {
  74. var vm = new Vue({
  75. el: el,
  76. data: {
  77. test: false,
  78. test2: 'string1',
  79. expression1: 'string1',
  80. expression2: 'string2'
  81. },
  82. template:
  83. '<input type="radio" value="1" v-model="test" name="test" exp="true">' +
  84. '<input type="radio" value="0" v-model="test" name="test" exp="false">' +
  85. '<input type="radio" value="1" v-model="test2" name="test2" exp="expression1">' +
  86. '<input type="radio" value="0" v-model="test2" name="test2" exp="expression2">'
  87. })
  88. expect(el.childNodes[0].checked).toBe(false)
  89. expect(el.childNodes[1].checked).toBe(true)
  90. expect(el.childNodes[2].checked).toBe(true)
  91. expect(el.childNodes[3].checked).toBe(false)
  92. _.nextTick(function () {
  93. el.childNodes[0].click()
  94. expect(vm.test).toBe(true)
  95. el.childNodes[3].click()
  96. expect(vm.test2).toBe('string2')
  97. done()
  98. })
  99. })
  100. it('radio expression (new syntax)', function (done) {
  101. var vm = new Vue({
  102. el: el,
  103. data: {
  104. test: false,
  105. test2: 'string1',
  106. expression1: 'string1',
  107. expression2: 'string2'
  108. },
  109. template:
  110. '<input type="radio" value="1" v-model="test" name="test" bind-value="true">' +
  111. '<input type="radio" value="0" v-model="test" name="test" bind-value="false">' +
  112. '<input type="radio" value="1" v-model="test2" name="test2" bind-value="expression1">' +
  113. '<input type="radio" value="0" v-model="test2" name="test2" bind-value="expression2">'
  114. })
  115. expect(el.childNodes[0].checked).toBe(false)
  116. expect(el.childNodes[1].checked).toBe(true)
  117. expect(el.childNodes[2].checked).toBe(true)
  118. expect(el.childNodes[3].checked).toBe(false)
  119. _.nextTick(function () {
  120. el.childNodes[0].click()
  121. expect(vm.test).toBe(true)
  122. el.childNodes[3].click()
  123. expect(vm.test2).toBe('string2')
  124. done()
  125. })
  126. })
  127. it('checkbox', function (done) {
  128. var vm = new Vue({
  129. el: el,
  130. data: {
  131. test: true
  132. },
  133. template: '<input type="checkbox" v-model="test">'
  134. })
  135. expect(el.firstChild.checked).toBe(true)
  136. vm.test = false
  137. _.nextTick(function () {
  138. expect(el.firstChild.checked).toBe(false)
  139. expect(vm.test).toBe(false)
  140. el.firstChild.click()
  141. expect(el.firstChild.checked).toBe(true)
  142. expect(vm.test).toBe(true)
  143. vm._directives[0]._teardown()
  144. el.firstChild.click()
  145. expect(el.firstChild.checked).toBe(false)
  146. expect(vm.test).toBe(true)
  147. done()
  148. })
  149. })
  150. it('checkbox default value', function () {
  151. var vm = new Vue({
  152. el: el,
  153. data: {},
  154. template: '<input type="checkbox" checked v-model="test">'
  155. })
  156. expect(vm.test).toBe(true)
  157. })
  158. it('checkbox expression', function (done) {
  159. var vm = new Vue({
  160. el: el,
  161. data: {
  162. test: '',
  163. expression1: 'aTrueValue',
  164. expression2: 'aFalseValue'
  165. },
  166. template: '<input type="checkbox" v-model="test" true-exp="expression1" false-exp="expression2">'
  167. })
  168. expect(vm.test).toBe('')
  169. el.firstChild.click()
  170. expect(vm.test).toBe('aTrueValue')
  171. expect(el.firstChild.checked).toBe(true)
  172. el.firstChild.click()
  173. expect(vm.test).toBe('aFalseValue')
  174. expect(el.firstChild.checked).toBe(false)
  175. _.nextTick(function () {
  176. vm.test = 'aTrueValue'
  177. _.nextTick(function () {
  178. expect(el.firstChild.checked).toBe(true)
  179. done()
  180. })
  181. })
  182. })
  183. it('checkbox expression (new syntax)', function (done) {
  184. var vm = new Vue({
  185. el: el,
  186. data: {
  187. test: '',
  188. expression1: 'aTrueValue',
  189. expression2: 'aFalseValue'
  190. },
  191. template: '<input type="checkbox" v-model="test" bind-true-value="expression1" bind-false-value="expression2">'
  192. })
  193. expect(vm.test).toBe('')
  194. el.firstChild.click()
  195. expect(vm.test).toBe('aTrueValue')
  196. expect(el.firstChild.checked).toBe(true)
  197. el.firstChild.click()
  198. expect(vm.test).toBe('aFalseValue')
  199. expect(el.firstChild.checked).toBe(false)
  200. _.nextTick(function () {
  201. vm.test = 'aTrueValue'
  202. _.nextTick(function () {
  203. expect(el.firstChild.checked).toBe(true)
  204. done()
  205. })
  206. })
  207. })
  208. it('select', function (done) {
  209. var vm = new Vue({
  210. el: el,
  211. data: {
  212. test: 'b'
  213. },
  214. template:
  215. '<select v-model="test">' +
  216. '<option>a</option>' +
  217. '<option>b</option>' +
  218. '<option>c</option>' +
  219. '</select>'
  220. })
  221. expect(vm.test).toBe('b')
  222. expect(el.firstChild.value).toBe('b')
  223. expect(el.firstChild.childNodes[1].selected).toBe(true)
  224. vm.test = 'c'
  225. _.nextTick(function () {
  226. expect(el.firstChild.value).toBe('c')
  227. expect(el.firstChild.childNodes[2].selected).toBe(true)
  228. updateSelect(el.firstChild, 'a')
  229. trigger(el.firstChild, 'change')
  230. expect(vm.test).toBe('a')
  231. done()
  232. })
  233. })
  234. it('select persist non-selected on append', function () {
  235. var vm = new Vue({
  236. el: el,
  237. data: {
  238. test: null
  239. },
  240. replace: true,
  241. template:
  242. '<select v-model="test">' +
  243. '<option>a</option>' +
  244. '<option>b</option>' +
  245. '<option>c</option>' +
  246. '</select>'
  247. })
  248. expect(vm.$el.value).toBe('')
  249. expect(vm.$el.selectedIndex).toBe(-1)
  250. vm.$remove()
  251. vm.$appendTo(document.body)
  252. expect(vm.$el.value).toBe('')
  253. expect(vm.$el.selectedIndex).toBe(-1)
  254. })
  255. it('select template default value', function () {
  256. var vm = new Vue({
  257. el: el,
  258. data: {
  259. test: 'a'
  260. },
  261. template:
  262. '<select v-model="test">' +
  263. '<option>a</option>' +
  264. '<option selected>b</option>' +
  265. '</select>'
  266. })
  267. expect(vm.test).toBe('b')
  268. expect(el.firstChild.value).toBe('b')
  269. expect(el.firstChild.childNodes[1].selected).toBe(true)
  270. })
  271. it('select + empty default value', function () {
  272. var vm = new Vue({
  273. el: el,
  274. template: '<select v-model="test"><option value="" selected>null</option><<option value="1">1</option></select>'
  275. })
  276. expect(vm.test).toBe('')
  277. trigger(vm.$el.firstChild, 'change')
  278. expect(vm.test).toBe('')
  279. })
  280. it('select + multiple', function (done) {
  281. var vm = new Vue({
  282. el: el,
  283. data: {
  284. test: [2] // test number soft equal
  285. },
  286. template:
  287. '<select v-model="test" multiple>' +
  288. '<option>1</option>' +
  289. '<option>2</option>' +
  290. '<option>3</option>' +
  291. '</select>'
  292. })
  293. var opts = el.firstChild.options
  294. expect(opts[0].selected).toBe(false)
  295. expect(opts[1].selected).toBe(true)
  296. expect(opts[2].selected).toBe(false)
  297. vm.test = [1, '3'] // mix of number/string
  298. _.nextTick(function () {
  299. expect(opts[0].selected).toBe(true)
  300. expect(opts[1].selected).toBe(false)
  301. expect(opts[2].selected).toBe(true)
  302. opts[0].selected = false
  303. opts[1].selected = true
  304. trigger(el.firstChild, 'change')
  305. expect(vm.test[0]).toBe('2')
  306. expect(vm.test[1]).toBe('3')
  307. done()
  308. })
  309. })
  310. it('select + multiple default value', function () {
  311. var vm = new Vue({
  312. el: el,
  313. data: {},
  314. template:
  315. '<select v-model="test" multiple>' +
  316. '<option>a</option>' +
  317. '<option selected>b</option>' +
  318. '<option selected>c</option>' +
  319. '</select>'
  320. })
  321. expect(vm.test[0]).toBe('b')
  322. expect(vm.test[1]).toBe('c')
  323. })
  324. it('select + options', function (done) {
  325. var vm = new Vue({
  326. el: el,
  327. data: {
  328. test: 'b',
  329. opts: ['a', 'b', 'c']
  330. },
  331. template: '<select v-model="test" options="opts"></select>'
  332. })
  333. var opts = el.firstChild.options
  334. expect(opts.length).toBe(3)
  335. expect(opts[0].selected).toBe(false)
  336. expect(opts[1].selected).toBe(true)
  337. expect(opts[2].selected).toBe(false)
  338. vm.opts = ['b', 'c']
  339. _.nextTick(function () {
  340. expect(opts.length).toBe(2)
  341. expect(opts[0].selected).toBe(true)
  342. expect(opts[1].selected).toBe(false)
  343. // should teardown option watcher when unbind
  344. expect(vm._watchers.length).toBe(2)
  345. vm._directives[0]._teardown()
  346. expect(vm._watchers.length).toBe(0)
  347. done()
  348. })
  349. })
  350. it('select + options + text', function () {
  351. new Vue({
  352. el: el,
  353. data: {
  354. test: 'b',
  355. opts: [
  356. { text: 'Select an option', value: null, disabled: true },
  357. { text: 'A', value: 'a' },
  358. { text: 'B', value: 'b' }
  359. ]
  360. },
  361. template: '<select v-model="test" options="opts"></select>'
  362. })
  363. expect(el.firstChild.innerHTML).toBe(
  364. '<option disabled="">Select an option</option>' +
  365. '<option value="a">A</option>' +
  366. '<option value="b">B</option>'
  367. )
  368. var opts = el.firstChild.options
  369. expect(opts[0].disabled).toBe(true)
  370. expect(opts[0].selected).toBe(false)
  371. expect(opts[1].selected).toBe(false)
  372. expect(opts[2].selected).toBe(true)
  373. })
  374. it('select + options + optgroup', function () {
  375. new Vue({
  376. el: el,
  377. data: {
  378. test: 'b',
  379. opts: [
  380. { label: 'A', options: ['a', 'b'] },
  381. { label: 'B', options: ['c'] }
  382. ]
  383. },
  384. template: '<select v-model="test" options="opts"></select>'
  385. })
  386. expect(el.firstChild.innerHTML).toBe(
  387. '<optgroup label="A">' +
  388. '<option value="a">a</option><option value="b">b</option>' +
  389. '</optgroup>' +
  390. '<optgroup label="B">' +
  391. '<option value="c">c</option>' +
  392. '</optgroup>'
  393. )
  394. var opts = el.firstChild.options
  395. expect(opts[0].selected).toBe(false)
  396. expect(opts[1].selected).toBe(true)
  397. expect(opts[2].selected).toBe(false)
  398. })
  399. it('select + options with Object value', function (done) {
  400. var vm = new Vue({
  401. el: el,
  402. data: {
  403. test: { msg: 'A' },
  404. opts: [
  405. { text: 'a', value: { msg: 'A' }},
  406. { text: 'b', value: { msg: 'B' }}
  407. ]
  408. },
  409. template: '<select v-model="test" options="opts"></select>'
  410. })
  411. var select = el.firstChild
  412. var opts = select.options
  413. expect(opts[0].selected).toBe(true)
  414. expect(opts[1].selected).toBe(false)
  415. expect(vm.test.msg).toBe('A')
  416. opts[1].selected = true
  417. trigger(select, 'change')
  418. _.nextTick(function () {
  419. expect(opts[0].selected).toBe(false)
  420. expect(opts[1].selected).toBe(true)
  421. expect(vm.test.msg).toBe('B')
  422. vm.test = { msg: 'A' }
  423. _.nextTick(function () {
  424. expect(opts[0].selected).toBe(true)
  425. expect(opts[1].selected).toBe(false)
  426. done()
  427. })
  428. })
  429. })
  430. it('select + options + multiple + Object value', function (done) {
  431. var vm = new Vue({
  432. el: el,
  433. data: {
  434. test: [{ msg: 'A' }, { msg: 'B'}],
  435. opts: [
  436. { text: 'a', value: { msg: 'A' }},
  437. { text: 'b', value: { msg: 'B' }},
  438. { text: 'c', value: { msg: 'C' }}
  439. ]
  440. },
  441. template: '<select v-model="test" options="opts" multiple></select>'
  442. })
  443. var select = el.firstChild
  444. var opts = select.options
  445. expect(opts[0].selected).toBe(true)
  446. expect(opts[1].selected).toBe(true)
  447. expect(opts[2].selected).toBe(false)
  448. vm.test = [{ msg: 'C' }]
  449. _.nextTick(function () {
  450. expect(opts[0].selected).toBe(false)
  451. expect(opts[1].selected).toBe(false)
  452. expect(opts[2].selected).toBe(true)
  453. opts[1].selected = true
  454. opts[2].selected = false
  455. trigger(select, 'change')
  456. _.nextTick(function () {
  457. expect(vm.test.length).toBe(1)
  458. expect(vm.test[0].msg).toBe('B')
  459. done()
  460. })
  461. })
  462. })
  463. it('select + number', function () {
  464. var vm = new Vue({
  465. el: el,
  466. data: {
  467. test: '1'
  468. },
  469. template: '<select v-model="test" number><option value="1">1</option></select>'
  470. })
  471. expect(vm.test).toBe('1')
  472. trigger(vm.$el.firstChild, 'change')
  473. expect(vm.test).toBe(1)
  474. })
  475. it('select + number + multiple', function () {
  476. var vm = new Vue({
  477. el: el,
  478. data: {
  479. test: []
  480. },
  481. template: '<select v-model="test" multiple number><option>1</option><option>2</option></select>'
  482. })
  483. ;[].forEach.call(el.querySelectorAll('option'), function (o) {
  484. o.selected = true
  485. })
  486. trigger(el.firstChild, 'change')
  487. expect(vm.test[0]).toBe(1)
  488. expect(vm.test[1]).toBe(2)
  489. })
  490. it('select + number initial value', function () {
  491. var vm = new Vue({
  492. el: el,
  493. data: {
  494. test: '1'
  495. },
  496. template: '<select v-model="test" number><option value="1" selected>1</option></select>'
  497. })
  498. expect(vm.test).toBe(1)
  499. })
  500. it('select + options + filter', function () {
  501. new Vue({
  502. el: el,
  503. data: {
  504. opts: ['a', 'b']
  505. },
  506. filters: {
  507. aFilter: function (opts) {
  508. return opts.map(function (val, i) {
  509. return val + i
  510. })
  511. }
  512. },
  513. template: '<select v-model="test" options="opts | aFilter"></select>'
  514. })
  515. expect(el.firstChild.innerHTML).toBe(
  516. '<option value="a0">a0</option>' +
  517. '<option value="b1">b1</option>'
  518. )
  519. })
  520. it('select + options + static option', function (done) {
  521. var vm = new Vue({
  522. el: el,
  523. data: {
  524. opts: ['a', 'b']
  525. },
  526. template:
  527. '<select v-model="test" options="opts">' +
  528. '<option value="">default...</option>' +
  529. '</select>'
  530. })
  531. expect(el.firstChild.innerHTML).toBe(
  532. '<option value="">default...</option>' +
  533. '<option value="a">a</option>' +
  534. '<option value="b">b</option>'
  535. )
  536. expect(el.firstChild.options[0].selected).toBe(true)
  537. vm.opts = ['c']
  538. _.nextTick(function () {
  539. expect(el.firstChild.innerHTML).toBe(
  540. '<option value="">default...</option>' +
  541. '<option value="c">c</option>'
  542. )
  543. expect(el.firstChild.options[0].selected).toBe(true)
  544. done()
  545. })
  546. })
  547. it('select + v-for (1.0.0)', function (done) {
  548. var vm = new Vue({
  549. el: el,
  550. data: {
  551. test: { msg: 'A' },
  552. opts: [
  553. { text: 'a', value: { msg: 'A' }},
  554. { text: 'b', value: { msg: 'B' }}
  555. ]
  556. },
  557. template:
  558. '<select v-model="test">' +
  559. '<option v-for="op in opts" bind-value="op.value">{{op.text}}</option>' +
  560. '</select>'
  561. })
  562. var select = el.firstChild
  563. var opts = select.options
  564. expect(opts[0].selected).toBe(true)
  565. expect(opts[1].selected).toBe(false)
  566. expect(vm.test.msg).toBe('A')
  567. opts[1].selected = true
  568. trigger(select, 'change')
  569. _.nextTick(function () {
  570. expect(opts[0].selected).toBe(false)
  571. expect(opts[1].selected).toBe(true)
  572. expect(vm.test.msg).toBe('B')
  573. vm.test = { msg: 'A' }
  574. _.nextTick(function () {
  575. expect(opts[0].selected).toBe(true)
  576. expect(opts[1].selected).toBe(false)
  577. vm.test = { msg: 'C' }
  578. vm.opts.push({text: 'c', value: vm.test})
  579. _.nextTick(function () {
  580. // updating the opts array should force the
  581. // v-model to update
  582. expect(opts[0].selected).toBe(false)
  583. expect(opts[1].selected).toBe(false)
  584. expect(opts[2].selected).toBe(true)
  585. done()
  586. })
  587. })
  588. })
  589. })
  590. it('text', function (done) {
  591. var vm = new Vue({
  592. el: el,
  593. data: {
  594. test: 'b'
  595. },
  596. template: '<input v-model="test">'
  597. })
  598. expect(el.firstChild.value).toBe('b')
  599. vm.test = 'a'
  600. _.nextTick(function () {
  601. expect(el.firstChild.value).toBe('a')
  602. el.firstChild.value = 'c'
  603. trigger(el.firstChild, 'input')
  604. expect(vm.test).toBe('c')
  605. vm._directives[0]._teardown()
  606. el.firstChild.value = 'd'
  607. trigger(el.firstChild, 'input')
  608. expect(vm.test).toBe('c')
  609. done()
  610. })
  611. })
  612. it('text default value', function () {
  613. var vm = new Vue({
  614. el: el,
  615. data: {
  616. test: 'b'
  617. },
  618. template: '<input v-model="test | test" value="a">',
  619. filters: {
  620. test: {
  621. read: function (v) {
  622. return v.slice(0, -1)
  623. },
  624. write: function (v) {
  625. return v + 'c'
  626. }
  627. }
  628. }
  629. })
  630. expect(vm.test).toBe('ac')
  631. expect(el.firstChild.value).toBe('a')
  632. })
  633. it('text lazy', function () {
  634. var vm = new Vue({
  635. el: el,
  636. data: {
  637. test: 'b'
  638. },
  639. template: '<input v-model="test" lazy>'
  640. })
  641. expect(el.firstChild.value).toBe('b')
  642. expect(vm.test).toBe('b')
  643. el.firstChild.value = 'c'
  644. trigger(el.firstChild, 'input')
  645. expect(vm.test).toBe('b')
  646. trigger(el.firstChild, 'change')
  647. expect(vm.test).toBe('c')
  648. })
  649. it('text with filters', function (done) {
  650. var vm = new Vue({
  651. el: el,
  652. data: {
  653. test: 'b'
  654. },
  655. filters: {
  656. test: {
  657. write: function (val) {
  658. return val.toLowerCase()
  659. }
  660. }
  661. },
  662. template: '<input v-model="test | uppercase | test">'
  663. })
  664. expect(el.firstChild.value).toBe('B')
  665. trigger(el.firstChild, 'focus')
  666. el.firstChild.value = 'cc'
  667. trigger(el.firstChild, 'input')
  668. _.nextTick(function () {
  669. expect(el.firstChild.value).toBe('cc')
  670. expect(vm.test).toBe('cc')
  671. trigger(el.firstChild, 'blur')
  672. _.nextTick(function () {
  673. expect(el.firstChild.value).toBe('CC')
  674. expect(vm.test).toBe('cc')
  675. done()
  676. })
  677. })
  678. })
  679. it('text with only write filter', function (done) {
  680. var vm = new Vue({
  681. el: el,
  682. data: {
  683. test: 'b'
  684. },
  685. filters: {
  686. test: {
  687. write: function (val) {
  688. return val.toUpperCase()
  689. }
  690. }
  691. },
  692. template: '<input v-model="test | test">'
  693. })
  694. trigger(el.firstChild, 'focus')
  695. el.firstChild.value = 'cc'
  696. trigger(el.firstChild, 'input')
  697. _.nextTick(function () {
  698. expect(el.firstChild.value).toBe('cc')
  699. expect(vm.test).toBe('CC')
  700. trigger(el.firstChild, 'blur')
  701. _.nextTick(function () {
  702. expect(el.firstChild.value).toBe('CC')
  703. expect(vm.test).toBe('CC')
  704. done()
  705. })
  706. })
  707. })
  708. it('number', function () {
  709. var vm = new Vue({
  710. el: el,
  711. data: {
  712. test: 1
  713. },
  714. template: '<input v-model="test" value="2" number>'
  715. })
  716. expect(vm.test).toBe(2)
  717. el.firstChild.value = 3
  718. trigger(el.firstChild, 'input')
  719. expect(vm.test).toBe(3)
  720. })
  721. it('IE9 cut and delete', function (done) {
  722. var ie9 = _.isIE9
  723. _.isIE9 = true
  724. var vm = new Vue({
  725. el: el,
  726. data: {
  727. test: 'aaa'
  728. },
  729. template: '<input v-model="test">'
  730. })
  731. var input = el.firstChild
  732. input.value = 'aa'
  733. trigger(input, 'cut')
  734. _.nextTick(function () {
  735. expect(vm.test).toBe('aa')
  736. input.value = 'a'
  737. trigger(input, 'keyup', function (e) {
  738. e.keyCode = 8
  739. })
  740. expect(vm.test).toBe('a')
  741. // teardown
  742. vm._directives[0]._teardown()
  743. input.value = 'bbb'
  744. trigger(input, 'keyup', function (e) {
  745. e.keyCode = 8
  746. })
  747. expect(vm.test).toBe('a')
  748. _.isIE9 = ie9
  749. done()
  750. })
  751. })
  752. if (!_.isAndroid) {
  753. it('text + compositionevents', function (done) {
  754. var vm = new Vue({
  755. el: el,
  756. data: {
  757. test: 'aaa',
  758. test2: 'bbb'
  759. },
  760. template: '<input v-model="test"><input v-model="test2 | uppercase">'
  761. })
  762. var input = el.firstChild
  763. var input2 = el.childNodes[1]
  764. trigger(input, 'compositionstart')
  765. trigger(input2, 'compositionstart')
  766. input.value = input2.value = 'ccc'
  767. // input before composition unlock should not call set
  768. trigger(input, 'input')
  769. trigger(input2, 'input')
  770. expect(vm.test).toBe('aaa')
  771. expect(vm.test2).toBe('bbb')
  772. // after composition unlock it should work
  773. trigger(input, 'compositionend')
  774. trigger(input2, 'compositionend')
  775. trigger(input, 'input')
  776. trigger(input2, 'input')
  777. expect(vm.test).toBe('ccc')
  778. expect(vm.test2).toBe('ccc')
  779. // IE complains about "unspecified error" when calling
  780. // setSelectionRange() on an input element that's been
  781. // removed from the DOM, so we wait until the
  782. // selection range callback has fired to end this test.
  783. _.nextTick(done)
  784. })
  785. }
  786. it('textarea', function () {
  787. var vm = new Vue({
  788. el: el,
  789. data: {
  790. test: 'b',
  791. b: 'BB'
  792. },
  793. template: '<textarea v-model="test">a {{b}} c</textarea>'
  794. })
  795. expect(vm.test).toBe('a BB c')
  796. expect(el.firstChild.value).toBe('a BB c')
  797. })
  798. it('warn invalid tag', function () {
  799. new Vue({
  800. el: el,
  801. template: '<div v-model="test"></div>'
  802. })
  803. expect(hasWarned(_, 'does not support element type')).toBe(true)
  804. })
  805. it('warn invalid option value', function () {
  806. new Vue({
  807. el: el,
  808. data: { a: 123 },
  809. template: '<select v-model="test" options="a"></select>'
  810. })
  811. expect(hasWarned(_, 'Invalid options value')).toBe(true)
  812. })
  813. it('warn read-only filters', function () {
  814. new Vue({
  815. el: el,
  816. template: '<input v-model="abc | test">',
  817. filters: {
  818. test: function (v) {
  819. return v
  820. }
  821. }
  822. })
  823. expect(hasWarned(_, 'read-only filter')).toBe(true)
  824. })
  825. it('support jQuery change event', function (done) {
  826. // restore jQuery
  827. jQuery = $
  828. var vm = new Vue({
  829. el: el,
  830. data: {
  831. test: 'b'
  832. },
  833. template: '<input v-model="test">'
  834. })
  835. expect(el.firstChild.value).toBe('b')
  836. vm.test = 'a'
  837. _.nextTick(function () {
  838. expect(el.firstChild.value).toBe('a')
  839. el.firstChild.value = 'c'
  840. jQuery(el.firstChild).trigger('change')
  841. expect(vm.test).toBe('c')
  842. vm._directives[0]._teardown()
  843. el.firstChild.value = 'd'
  844. jQuery(el.firstChild).trigger('change')
  845. expect(vm.test).toBe('c')
  846. // unset jQuery
  847. jQuery = null
  848. done()
  849. })
  850. })
  851. it('support debounce', function (done) {
  852. var spy = jasmine.createSpy()
  853. var vm = new Vue({
  854. el: el,
  855. data: {
  856. test: 'a'
  857. },
  858. watch: {
  859. test: spy
  860. },
  861. template: '<input v-model="test" debounce="100">'
  862. })
  863. el.firstChild.value = 'b'
  864. trigger(el.firstChild, 'input')
  865. setTimeout(function () {
  866. el.firstChild.value = 'c'
  867. trigger(el.firstChild, 'input')
  868. }, 10)
  869. setTimeout(function () {
  870. el.firstChild.value = 'd'
  871. trigger(el.firstChild, 'input')
  872. }, 20)
  873. setTimeout(function () {
  874. expect(spy.calls.count()).toBe(0)
  875. expect(vm.test).toBe('a')
  876. }, 30)
  877. setTimeout(function () {
  878. expect(spy.calls.count()).toBe(1)
  879. expect(vm.test).toBe('d')
  880. done()
  881. }, 200)
  882. })
  883. })
  884. }