model_spec.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  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('checkbox', function (done) {
  101. var vm = new Vue({
  102. el: el,
  103. data: {
  104. test: true
  105. },
  106. template: '<input type="checkbox" v-model="test">'
  107. })
  108. expect(el.firstChild.checked).toBe(true)
  109. vm.test = false
  110. _.nextTick(function () {
  111. expect(el.firstChild.checked).toBe(false)
  112. expect(vm.test).toBe(false)
  113. el.firstChild.click()
  114. expect(el.firstChild.checked).toBe(true)
  115. expect(vm.test).toBe(true)
  116. vm._directives[0]._teardown()
  117. el.firstChild.click()
  118. expect(el.firstChild.checked).toBe(false)
  119. expect(vm.test).toBe(true)
  120. done()
  121. })
  122. })
  123. it('checkbox default value', function () {
  124. var vm = new Vue({
  125. el: el,
  126. data: {},
  127. template: '<input type="checkbox" checked v-model="test">'
  128. })
  129. expect(vm.test).toBe(true)
  130. })
  131. it('checkbox expression', function (done) {
  132. var vm = new Vue({
  133. el: el,
  134. data: {
  135. test: '',
  136. expression1: 'aTrueValue',
  137. expression2: 'aFalseValue'
  138. },
  139. template: '<input type="checkbox" v-model="test" true-exp="expression1" false-exp="expression2">'
  140. })
  141. expect(vm.test).toBe('')
  142. el.firstChild.click()
  143. expect(vm.test).toBe('aTrueValue')
  144. expect(el.firstChild.checked).toBe(true)
  145. el.firstChild.click()
  146. expect(vm.test).toBe('aFalseValue')
  147. expect(el.firstChild.checked).toBe(false)
  148. _.nextTick(function () {
  149. vm.test = 'aTrueValue'
  150. _.nextTick(function () {
  151. expect(el.firstChild.checked).toBe(true)
  152. done()
  153. })
  154. })
  155. })
  156. it('select', function (done) {
  157. var vm = new Vue({
  158. el: el,
  159. data: {
  160. test: 'b'
  161. },
  162. template:
  163. '<select v-model="test">' +
  164. '<option>a</option>' +
  165. '<option>b</option>' +
  166. '<option>c</option>' +
  167. '</select>'
  168. })
  169. expect(vm.test).toBe('b')
  170. expect(el.firstChild.value).toBe('b')
  171. expect(el.firstChild.childNodes[1].selected).toBe(true)
  172. vm.test = 'c'
  173. _.nextTick(function () {
  174. expect(el.firstChild.value).toBe('c')
  175. expect(el.firstChild.childNodes[2].selected).toBe(true)
  176. updateSelect(el.firstChild, 'a')
  177. trigger(el.firstChild, 'change')
  178. expect(vm.test).toBe('a')
  179. done()
  180. })
  181. })
  182. it('select persist non-selected on append', function () {
  183. var vm = new Vue({
  184. el: el,
  185. data: {
  186. test: null
  187. },
  188. replace: true,
  189. template:
  190. '<select v-model="test">' +
  191. '<option>a</option>' +
  192. '<option>b</option>' +
  193. '<option>c</option>' +
  194. '</select>'
  195. })
  196. expect(vm.$el.value).toBe('')
  197. expect(vm.$el.selectedIndex).toBe(-1)
  198. vm.$remove()
  199. vm.$appendTo(document.body)
  200. expect(vm.$el.value).toBe('')
  201. expect(vm.$el.selectedIndex).toBe(-1)
  202. })
  203. it('select template default value', function () {
  204. var vm = new Vue({
  205. el: el,
  206. data: {
  207. test: 'a'
  208. },
  209. template:
  210. '<select v-model="test">' +
  211. '<option>a</option>' +
  212. '<option selected>b</option>' +
  213. '</select>'
  214. })
  215. expect(vm.test).toBe('b')
  216. expect(el.firstChild.value).toBe('b')
  217. expect(el.firstChild.childNodes[1].selected).toBe(true)
  218. })
  219. it('select + empty default value', function () {
  220. var vm = new Vue({
  221. el: el,
  222. template: '<select v-model="test"><option value="" selected>null</option><<option value="1">1</option></select>'
  223. })
  224. expect(vm.test).toBe('')
  225. trigger(vm.$el.firstChild, 'change')
  226. expect(vm.test).toBe('')
  227. })
  228. it('select + multiple', function (done) {
  229. var vm = new Vue({
  230. el: el,
  231. data: {
  232. test: [2] // test number soft equal
  233. },
  234. template:
  235. '<select v-model="test" multiple>' +
  236. '<option>1</option>' +
  237. '<option>2</option>' +
  238. '<option>3</option>' +
  239. '</select>'
  240. })
  241. var opts = el.firstChild.options
  242. expect(opts[0].selected).toBe(false)
  243. expect(opts[1].selected).toBe(true)
  244. expect(opts[2].selected).toBe(false)
  245. vm.test = [1, '3'] // mix of number/string
  246. _.nextTick(function () {
  247. expect(opts[0].selected).toBe(true)
  248. expect(opts[1].selected).toBe(false)
  249. expect(opts[2].selected).toBe(true)
  250. opts[0].selected = false
  251. opts[1].selected = true
  252. trigger(el.firstChild, 'change')
  253. expect(vm.test[0]).toBe('2')
  254. expect(vm.test[1]).toBe('3')
  255. done()
  256. })
  257. })
  258. it('select + multiple default value', function () {
  259. var vm = new Vue({
  260. el: el,
  261. data: {},
  262. template:
  263. '<select v-model="test" multiple>' +
  264. '<option>a</option>' +
  265. '<option selected>b</option>' +
  266. '<option selected>c</option>' +
  267. '</select>'
  268. })
  269. expect(vm.test[0]).toBe('b')
  270. expect(vm.test[1]).toBe('c')
  271. })
  272. it('select + options', function (done) {
  273. var vm = new Vue({
  274. el: el,
  275. data: {
  276. test: 'b',
  277. opts: ['a', 'b', 'c']
  278. },
  279. template: '<select v-model="test" options="opts"></select>'
  280. })
  281. var opts = el.firstChild.options
  282. expect(opts.length).toBe(3)
  283. expect(opts[0].selected).toBe(false)
  284. expect(opts[1].selected).toBe(true)
  285. expect(opts[2].selected).toBe(false)
  286. vm.opts = ['b', 'c']
  287. _.nextTick(function () {
  288. expect(opts.length).toBe(2)
  289. expect(opts[0].selected).toBe(true)
  290. expect(opts[1].selected).toBe(false)
  291. // should teardown option watcher when unbind
  292. expect(vm._watchers.length).toBe(2)
  293. vm._directives[0]._teardown()
  294. expect(vm._watchers.length).toBe(0)
  295. done()
  296. })
  297. })
  298. it('select + options + text', function () {
  299. new Vue({
  300. el: el,
  301. data: {
  302. test: 'b',
  303. opts: [
  304. { text: 'Select an option', value: null, disabled: true },
  305. { text: 'A', value: 'a' },
  306. { text: 'B', value: 'b' }
  307. ]
  308. },
  309. template: '<select v-model="test" options="opts"></select>'
  310. })
  311. expect(el.firstChild.innerHTML).toBe(
  312. '<option disabled="">Select an option</option>' +
  313. '<option value="a">A</option>' +
  314. '<option value="b">B</option>'
  315. )
  316. var opts = el.firstChild.options
  317. expect(opts[0].disabled).toBe(true)
  318. expect(opts[0].selected).toBe(false)
  319. expect(opts[1].selected).toBe(false)
  320. expect(opts[2].selected).toBe(true)
  321. })
  322. it('select + options + optgroup', function (done) {
  323. var vm = new Vue({
  324. el: el,
  325. data: {
  326. test: 'b',
  327. opts: [
  328. { label: 'A', options: ['a', 'b'] },
  329. { label: 'B', options: ['c'] }
  330. ]
  331. },
  332. template: '<select v-model="test" options="opts"></select>'
  333. })
  334. expect(el.firstChild.innerHTML).toBe(
  335. '<optgroup label="A">' +
  336. '<option value="a">a</option><option value="b">b</option>' +
  337. '</optgroup>' +
  338. '<optgroup label="B">' +
  339. '<option value="c">c</option>' +
  340. '</optgroup>'
  341. )
  342. var opts = el.firstChild.options
  343. expect(opts[0].selected).toBe(false)
  344. expect(opts[1].selected).toBe(true)
  345. expect(opts[2].selected).toBe(false)
  346. vm.opts = [
  347. { label: 'X', options: ['x', 'y'] },
  348. { label: 'Y', options: ['z'] }
  349. ]
  350. vm.test = 'y'
  351. _.nextTick(function () {
  352. expect(el.firstChild.innerHTML).toBe(
  353. '<optgroup label="X">' +
  354. '<option value="x">x</option><option value="y">y</option>' +
  355. '</optgroup>' +
  356. '<optgroup label="Y">' +
  357. '<option value="z">z</option>' +
  358. '</optgroup>'
  359. )
  360. var opts = el.firstChild.options
  361. expect(opts[0].selected).toBe(false)
  362. expect(opts[1].selected).toBe(true)
  363. expect(opts[2].selected).toBe(false)
  364. done()
  365. })
  366. })
  367. it('select + options with Object value', function (done) {
  368. var vm = new Vue({
  369. el: el,
  370. data: {
  371. test: { msg: 'A' },
  372. opts: [
  373. { text: 'a', value: { msg: 'A' }},
  374. { text: 'b', value: { msg: 'B' }}
  375. ]
  376. },
  377. template: '<select v-model="test" options="opts"></select>'
  378. })
  379. var select = el.firstChild
  380. var opts = select.options
  381. expect(opts[0].selected).toBe(true)
  382. expect(opts[1].selected).toBe(false)
  383. expect(vm.test.msg).toBe('A')
  384. opts[1].selected = true
  385. trigger(select, 'change')
  386. _.nextTick(function () {
  387. expect(opts[0].selected).toBe(false)
  388. expect(opts[1].selected).toBe(true)
  389. expect(vm.test.msg).toBe('B')
  390. vm.test = { msg: 'A' }
  391. _.nextTick(function () {
  392. expect(opts[0].selected).toBe(true)
  393. expect(opts[1].selected).toBe(false)
  394. done()
  395. })
  396. })
  397. })
  398. it('select + options + multiple + Object value', function (done) {
  399. var vm = new Vue({
  400. el: el,
  401. data: {
  402. test: [{ msg: 'A' }, { msg: 'B'}],
  403. opts: [
  404. { text: 'a', value: { msg: 'A' }},
  405. { text: 'b', value: { msg: 'B' }},
  406. { text: 'c', value: { msg: 'C' }}
  407. ]
  408. },
  409. template: '<select v-model="test" options="opts" multiple></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(true)
  415. expect(opts[2].selected).toBe(false)
  416. vm.test = [{ msg: 'C' }]
  417. _.nextTick(function () {
  418. expect(opts[0].selected).toBe(false)
  419. expect(opts[1].selected).toBe(false)
  420. expect(opts[2].selected).toBe(true)
  421. opts[1].selected = true
  422. opts[2].selected = false
  423. trigger(select, 'change')
  424. _.nextTick(function () {
  425. expect(vm.test.length).toBe(1)
  426. expect(vm.test[0].msg).toBe('B')
  427. done()
  428. })
  429. })
  430. })
  431. it('select + number', function () {
  432. var vm = new Vue({
  433. el: el,
  434. data: {
  435. test: '1'
  436. },
  437. template: '<select v-model="test" number><option value="1">1</option></select>'
  438. })
  439. expect(vm.test).toBe('1')
  440. trigger(vm.$el.firstChild, 'change')
  441. expect(vm.test).toBe(1)
  442. })
  443. it('select + number + multiple', function () {
  444. var vm = new Vue({
  445. el: el,
  446. data: {
  447. test: []
  448. },
  449. template: '<select v-model="test" multiple number><option>1</option><option>2</option></select>'
  450. })
  451. ;[].forEach.call(el.querySelectorAll('option'), function (o) {
  452. o.selected = true
  453. })
  454. trigger(el.firstChild, 'change')
  455. expect(vm.test[0]).toBe(1)
  456. expect(vm.test[1]).toBe(2)
  457. })
  458. it('select + number initial value', function () {
  459. var vm = new Vue({
  460. el: el,
  461. data: {
  462. test: '1'
  463. },
  464. template: '<select v-model="test" number><option value="1" selected>1</option></select>'
  465. })
  466. expect(vm.test).toBe(1)
  467. })
  468. it('select + options + filter', function () {
  469. new Vue({
  470. el: el,
  471. data: {
  472. opts: ['a', 'b']
  473. },
  474. filters: {
  475. aFilter: function (opts) {
  476. return opts.map(function (val, i) {
  477. return val + i
  478. })
  479. }
  480. },
  481. template: '<select v-model="test" options="opts | aFilter"></select>'
  482. })
  483. expect(el.firstChild.innerHTML).toBe(
  484. '<option value="a0">a0</option>' +
  485. '<option value="b1">b1</option>'
  486. )
  487. })
  488. it('select + options + static option', function (done) {
  489. var vm = new Vue({
  490. el: el,
  491. data: {
  492. opts: ['a', 'b']
  493. },
  494. template:
  495. '<select v-model="test" options="opts">' +
  496. '<option value="">default...</option>' +
  497. '</select>'
  498. })
  499. expect(el.firstChild.innerHTML).toBe(
  500. '<option value="">default...</option>' +
  501. '<option value="a">a</option>' +
  502. '<option value="b">b</option>'
  503. )
  504. expect(el.firstChild.options[0].selected).toBe(true)
  505. vm.opts = ['c']
  506. _.nextTick(function () {
  507. expect(el.firstChild.innerHTML).toBe(
  508. '<option value="">default...</option>' +
  509. '<option value="c">c</option>'
  510. )
  511. expect(el.firstChild.options[0].selected).toBe(true)
  512. done()
  513. })
  514. })
  515. it('text', function (done) {
  516. var vm = new Vue({
  517. el: el,
  518. data: {
  519. test: 'b'
  520. },
  521. template: '<input v-model="test">'
  522. })
  523. expect(el.firstChild.value).toBe('b')
  524. vm.test = 'a'
  525. _.nextTick(function () {
  526. expect(el.firstChild.value).toBe('a')
  527. el.firstChild.value = 'c'
  528. trigger(el.firstChild, 'input')
  529. expect(vm.test).toBe('c')
  530. vm._directives[0]._teardown()
  531. el.firstChild.value = 'd'
  532. trigger(el.firstChild, 'input')
  533. expect(vm.test).toBe('c')
  534. done()
  535. })
  536. })
  537. it('text default value', function () {
  538. var vm = new Vue({
  539. el: el,
  540. data: {
  541. test: 'b'
  542. },
  543. template: '<input v-model="test | test" value="a">',
  544. filters: {
  545. test: {
  546. read: function (v) {
  547. return v.slice(0, -1)
  548. },
  549. write: function (v) {
  550. return v + 'c'
  551. }
  552. }
  553. }
  554. })
  555. expect(vm.test).toBe('ac')
  556. expect(el.firstChild.value).toBe('a')
  557. })
  558. it('text lazy', function () {
  559. var vm = new Vue({
  560. el: el,
  561. data: {
  562. test: 'b'
  563. },
  564. template: '<input v-model="test" lazy>'
  565. })
  566. expect(el.firstChild.value).toBe('b')
  567. expect(vm.test).toBe('b')
  568. el.firstChild.value = 'c'
  569. trigger(el.firstChild, 'input')
  570. expect(vm.test).toBe('b')
  571. trigger(el.firstChild, 'change')
  572. expect(vm.test).toBe('c')
  573. })
  574. it('text with filters', function (done) {
  575. var vm = new Vue({
  576. el: el,
  577. data: {
  578. test: 'b'
  579. },
  580. filters: {
  581. test: {
  582. write: function (val) {
  583. return val.toLowerCase()
  584. }
  585. }
  586. },
  587. template: '<input v-model="test | uppercase | test">'
  588. })
  589. expect(el.firstChild.value).toBe('B')
  590. trigger(el.firstChild, 'focus')
  591. el.firstChild.value = 'cc'
  592. trigger(el.firstChild, 'input')
  593. _.nextTick(function () {
  594. expect(el.firstChild.value).toBe('cc')
  595. expect(vm.test).toBe('cc')
  596. trigger(el.firstChild, 'blur')
  597. _.nextTick(function () {
  598. expect(el.firstChild.value).toBe('CC')
  599. expect(vm.test).toBe('cc')
  600. done()
  601. })
  602. })
  603. })
  604. it('text with only write filter', function (done) {
  605. var vm = new Vue({
  606. el: el,
  607. data: {
  608. test: 'b'
  609. },
  610. filters: {
  611. test: {
  612. write: function (val) {
  613. return val.toUpperCase()
  614. }
  615. }
  616. },
  617. template: '<input v-model="test | test">'
  618. })
  619. trigger(el.firstChild, 'focus')
  620. el.firstChild.value = 'cc'
  621. trigger(el.firstChild, 'input')
  622. _.nextTick(function () {
  623. expect(el.firstChild.value).toBe('cc')
  624. expect(vm.test).toBe('CC')
  625. trigger(el.firstChild, 'blur')
  626. _.nextTick(function () {
  627. expect(el.firstChild.value).toBe('CC')
  628. expect(vm.test).toBe('CC')
  629. done()
  630. })
  631. })
  632. })
  633. it('number', function () {
  634. var vm = new Vue({
  635. el: el,
  636. data: {
  637. test: 1
  638. },
  639. template: '<input v-model="test" value="2" number>'
  640. })
  641. expect(vm.test).toBe(2)
  642. el.firstChild.value = 3
  643. trigger(el.firstChild, 'input')
  644. expect(vm.test).toBe(3)
  645. })
  646. it('IE9 cut and delete', function (done) {
  647. var ie9 = _.isIE9
  648. _.isIE9 = true
  649. var vm = new Vue({
  650. el: el,
  651. data: {
  652. test: 'aaa'
  653. },
  654. template: '<input v-model="test">'
  655. })
  656. var input = el.firstChild
  657. input.value = 'aa'
  658. trigger(input, 'cut')
  659. _.nextTick(function () {
  660. expect(vm.test).toBe('aa')
  661. input.value = 'a'
  662. trigger(input, 'keyup', function (e) {
  663. e.keyCode = 8
  664. })
  665. expect(vm.test).toBe('a')
  666. // teardown
  667. vm._directives[0]._teardown()
  668. input.value = 'bbb'
  669. trigger(input, 'keyup', function (e) {
  670. e.keyCode = 8
  671. })
  672. expect(vm.test).toBe('a')
  673. _.isIE9 = ie9
  674. done()
  675. })
  676. })
  677. if (!_.isAndroid) {
  678. it('text + compositionevents', function (done) {
  679. var vm = new Vue({
  680. el: el,
  681. data: {
  682. test: 'aaa',
  683. test2: 'bbb'
  684. },
  685. template: '<input v-model="test"><input v-model="test2 | uppercase">'
  686. })
  687. var input = el.firstChild
  688. var input2 = el.childNodes[1]
  689. trigger(input, 'compositionstart')
  690. trigger(input2, 'compositionstart')
  691. input.value = input2.value = 'ccc'
  692. // input before composition unlock should not call set
  693. trigger(input, 'input')
  694. trigger(input2, 'input')
  695. expect(vm.test).toBe('aaa')
  696. expect(vm.test2).toBe('bbb')
  697. // after composition unlock it should work
  698. trigger(input, 'compositionend')
  699. trigger(input2, 'compositionend')
  700. trigger(input, 'input')
  701. trigger(input2, 'input')
  702. expect(vm.test).toBe('ccc')
  703. expect(vm.test2).toBe('ccc')
  704. // IE complains about "unspecified error" when calling
  705. // setSelectionRange() on an input element that's been
  706. // removed from the DOM, so we wait until the
  707. // selection range callback has fired to end this test.
  708. _.nextTick(done)
  709. })
  710. }
  711. it('textarea', function () {
  712. var vm = new Vue({
  713. el: el,
  714. data: {
  715. test: 'b',
  716. b: 'BB'
  717. },
  718. template: '<textarea v-model="test">a {{b}} c</textarea>'
  719. })
  720. expect(vm.test).toBe('a BB c')
  721. expect(el.firstChild.value).toBe('a BB c')
  722. })
  723. it('warn invalid tag', function () {
  724. new Vue({
  725. el: el,
  726. template: '<div v-model="test"></div>'
  727. })
  728. expect(hasWarned(_, 'does not support element type')).toBe(true)
  729. })
  730. it('warn invalid option value', function () {
  731. new Vue({
  732. el: el,
  733. data: { a: 123 },
  734. template: '<select v-model="test" options="a"></select>'
  735. })
  736. expect(hasWarned(_, 'Invalid options value')).toBe(true)
  737. })
  738. it('warn read-only filters', function () {
  739. new Vue({
  740. el: el,
  741. template: '<input v-model="abc | test">',
  742. filters: {
  743. test: function (v) {
  744. return v
  745. }
  746. }
  747. })
  748. expect(hasWarned(_, 'read-only filter')).toBe(true)
  749. })
  750. it('support jQuery change event', function (done) {
  751. // restore jQuery
  752. jQuery = $
  753. var vm = new Vue({
  754. el: el,
  755. data: {
  756. test: 'b'
  757. },
  758. template: '<input v-model="test">'
  759. })
  760. expect(el.firstChild.value).toBe('b')
  761. vm.test = 'a'
  762. _.nextTick(function () {
  763. expect(el.firstChild.value).toBe('a')
  764. el.firstChild.value = 'c'
  765. jQuery(el.firstChild).trigger('change')
  766. expect(vm.test).toBe('c')
  767. vm._directives[0]._teardown()
  768. el.firstChild.value = 'd'
  769. jQuery(el.firstChild).trigger('change')
  770. expect(vm.test).toBe('c')
  771. // unset jQuery
  772. jQuery = null
  773. done()
  774. })
  775. })
  776. it('support debounce', function (done) {
  777. var spy = jasmine.createSpy()
  778. var vm = new Vue({
  779. el: el,
  780. data: {
  781. test: 'a'
  782. },
  783. watch: {
  784. test: spy
  785. },
  786. template: '<input v-model="test" debounce="100">'
  787. })
  788. el.firstChild.value = 'b'
  789. trigger(el.firstChild, 'input')
  790. setTimeout(function () {
  791. el.firstChild.value = 'c'
  792. trigger(el.firstChild, 'input')
  793. }, 10)
  794. setTimeout(function () {
  795. el.firstChild.value = 'd'
  796. trigger(el.firstChild, 'input')
  797. }, 20)
  798. setTimeout(function () {
  799. expect(spy.calls.count()).toBe(0)
  800. expect(vm.test).toBe('a')
  801. }, 30)
  802. setTimeout(function () {
  803. expect(spy.calls.count()).toBe(1)
  804. expect(vm.test).toBe('d')
  805. done()
  806. }, 200)
  807. })
  808. })
  809. }