model_spec.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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 () {
  323. 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. })
  347. it('select + options with Object value', function (done) {
  348. var vm = new Vue({
  349. el: el,
  350. data: {
  351. test: { msg: 'A' },
  352. opts: [
  353. { text: 'a', value: { msg: 'A' }},
  354. { text: 'b', value: { msg: 'B' }}
  355. ]
  356. },
  357. template: '<select v-model="test" options="opts"></select>'
  358. })
  359. var select = el.firstChild
  360. var opts = select.options
  361. expect(opts[0].selected).toBe(true)
  362. expect(opts[1].selected).toBe(false)
  363. expect(vm.test.msg).toBe('A')
  364. opts[1].selected = true
  365. trigger(select, 'change')
  366. _.nextTick(function () {
  367. expect(opts[0].selected).toBe(false)
  368. expect(opts[1].selected).toBe(true)
  369. expect(vm.test.msg).toBe('B')
  370. vm.test = { msg: 'A' }
  371. _.nextTick(function () {
  372. expect(opts[0].selected).toBe(true)
  373. expect(opts[1].selected).toBe(false)
  374. done()
  375. })
  376. })
  377. })
  378. it('select + options + multiple + Object value', function (done) {
  379. var vm = new Vue({
  380. el: el,
  381. data: {
  382. test: [{ msg: 'A' }, { msg: 'B'}],
  383. opts: [
  384. { text: 'a', value: { msg: 'A' }},
  385. { text: 'b', value: { msg: 'B' }},
  386. { text: 'c', value: { msg: 'C' }}
  387. ]
  388. },
  389. template: '<select v-model="test" options="opts" multiple></select>'
  390. })
  391. var select = el.firstChild
  392. var opts = select.options
  393. expect(opts[0].selected).toBe(true)
  394. expect(opts[1].selected).toBe(true)
  395. expect(opts[2].selected).toBe(false)
  396. vm.test = [{ msg: 'C' }]
  397. _.nextTick(function () {
  398. expect(opts[0].selected).toBe(false)
  399. expect(opts[1].selected).toBe(false)
  400. expect(opts[2].selected).toBe(true)
  401. opts[1].selected = true
  402. opts[2].selected = false
  403. trigger(select, 'change')
  404. _.nextTick(function () {
  405. expect(vm.test.length).toBe(1)
  406. expect(vm.test[0].msg).toBe('B')
  407. done()
  408. })
  409. })
  410. })
  411. it('select + number', function () {
  412. var vm = new Vue({
  413. el: el,
  414. data: {
  415. test: '1'
  416. },
  417. template: '<select v-model="test" number><option value="1">1</option></select>'
  418. })
  419. expect(vm.test).toBe('1')
  420. trigger(vm.$el.firstChild, 'change')
  421. expect(vm.test).toBe(1)
  422. })
  423. it('select + number + multiple', function () {
  424. var vm = new Vue({
  425. el: el,
  426. data: {
  427. test: []
  428. },
  429. template: '<select v-model="test" multiple number><option>1</option><option>2</option></select>'
  430. })
  431. ;[].forEach.call(el.querySelectorAll('option'), function (o) {
  432. o.selected = true
  433. })
  434. trigger(el.firstChild, 'change')
  435. expect(vm.test[0]).toBe(1)
  436. expect(vm.test[1]).toBe(2)
  437. })
  438. it('select + number initial value', function () {
  439. var vm = new Vue({
  440. el: el,
  441. data: {
  442. test: '1'
  443. },
  444. template: '<select v-model="test" number><option value="1" selected>1</option></select>'
  445. })
  446. expect(vm.test).toBe(1)
  447. })
  448. it('select + options + filter', function () {
  449. new Vue({
  450. el: el,
  451. data: {
  452. opts: ['a', 'b']
  453. },
  454. filters: {
  455. aFilter: function (opts) {
  456. return opts.map(function (val, i) {
  457. return val + i
  458. })
  459. }
  460. },
  461. template: '<select v-model="test" options="opts | aFilter"></select>'
  462. })
  463. expect(el.firstChild.innerHTML).toBe(
  464. '<option value="a0">a0</option>' +
  465. '<option value="b1">b1</option>'
  466. )
  467. })
  468. it('select + options + static option', function (done) {
  469. var vm = new Vue({
  470. el: el,
  471. data: {
  472. opts: ['a', 'b']
  473. },
  474. template:
  475. '<select v-model="test" options="opts">' +
  476. '<option value="">default...</option>' +
  477. '</select>'
  478. })
  479. expect(el.firstChild.innerHTML).toBe(
  480. '<option value="">default...</option>' +
  481. '<option value="a">a</option>' +
  482. '<option value="b">b</option>'
  483. )
  484. expect(el.firstChild.options[0].selected).toBe(true)
  485. vm.opts = ['c']
  486. _.nextTick(function () {
  487. expect(el.firstChild.innerHTML).toBe(
  488. '<option value="">default...</option>' +
  489. '<option value="c">c</option>'
  490. )
  491. expect(el.firstChild.options[0].selected).toBe(true)
  492. done()
  493. })
  494. })
  495. it('text', function (done) {
  496. var vm = new Vue({
  497. el: el,
  498. data: {
  499. test: 'b'
  500. },
  501. template: '<input v-model="test">'
  502. })
  503. expect(el.firstChild.value).toBe('b')
  504. vm.test = 'a'
  505. _.nextTick(function () {
  506. expect(el.firstChild.value).toBe('a')
  507. el.firstChild.value = 'c'
  508. trigger(el.firstChild, 'input')
  509. expect(vm.test).toBe('c')
  510. vm._directives[0]._teardown()
  511. el.firstChild.value = 'd'
  512. trigger(el.firstChild, 'input')
  513. expect(vm.test).toBe('c')
  514. done()
  515. })
  516. })
  517. it('text default value', function () {
  518. var vm = new Vue({
  519. el: el,
  520. data: {
  521. test: 'b'
  522. },
  523. template: '<input v-model="test | test" value="a">',
  524. filters: {
  525. test: {
  526. read: function (v) {
  527. return v.slice(0, -1)
  528. },
  529. write: function (v) {
  530. return v + 'c'
  531. }
  532. }
  533. }
  534. })
  535. expect(vm.test).toBe('ac')
  536. expect(el.firstChild.value).toBe('a')
  537. })
  538. it('text lazy', function () {
  539. var vm = new Vue({
  540. el: el,
  541. data: {
  542. test: 'b'
  543. },
  544. template: '<input v-model="test" lazy>'
  545. })
  546. expect(el.firstChild.value).toBe('b')
  547. expect(vm.test).toBe('b')
  548. el.firstChild.value = 'c'
  549. trigger(el.firstChild, 'input')
  550. expect(vm.test).toBe('b')
  551. trigger(el.firstChild, 'change')
  552. expect(vm.test).toBe('c')
  553. })
  554. it('text with filters', function (done) {
  555. var vm = new Vue({
  556. el: el,
  557. data: {
  558. test: 'b'
  559. },
  560. filters: {
  561. test: {
  562. write: function (val) {
  563. return val.toLowerCase()
  564. }
  565. }
  566. },
  567. template: '<input v-model="test | uppercase | test">'
  568. })
  569. expect(el.firstChild.value).toBe('B')
  570. trigger(el.firstChild, 'focus')
  571. el.firstChild.value = 'cc'
  572. trigger(el.firstChild, 'input')
  573. _.nextTick(function () {
  574. expect(el.firstChild.value).toBe('cc')
  575. expect(vm.test).toBe('cc')
  576. trigger(el.firstChild, 'blur')
  577. _.nextTick(function () {
  578. expect(el.firstChild.value).toBe('CC')
  579. expect(vm.test).toBe('cc')
  580. done()
  581. })
  582. })
  583. })
  584. it('text with only write filter', function (done) {
  585. var vm = new Vue({
  586. el: el,
  587. data: {
  588. test: 'b'
  589. },
  590. filters: {
  591. test: {
  592. write: function (val) {
  593. return val.toUpperCase()
  594. }
  595. }
  596. },
  597. template: '<input v-model="test | test">'
  598. })
  599. trigger(el.firstChild, 'focus')
  600. el.firstChild.value = 'cc'
  601. trigger(el.firstChild, 'input')
  602. _.nextTick(function () {
  603. expect(el.firstChild.value).toBe('cc')
  604. expect(vm.test).toBe('CC')
  605. trigger(el.firstChild, 'blur')
  606. _.nextTick(function () {
  607. expect(el.firstChild.value).toBe('CC')
  608. expect(vm.test).toBe('CC')
  609. done()
  610. })
  611. })
  612. })
  613. it('number', function () {
  614. var vm = new Vue({
  615. el: el,
  616. data: {
  617. test: 1
  618. },
  619. template: '<input v-model="test" value="2" number>'
  620. })
  621. expect(vm.test).toBe(2)
  622. el.firstChild.value = 3
  623. trigger(el.firstChild, 'input')
  624. expect(vm.test).toBe(3)
  625. })
  626. it('IE9 cut and delete', function (done) {
  627. var ie9 = _.isIE9
  628. _.isIE9 = true
  629. var vm = new Vue({
  630. el: el,
  631. data: {
  632. test: 'aaa'
  633. },
  634. template: '<input v-model="test">'
  635. })
  636. var input = el.firstChild
  637. input.value = 'aa'
  638. trigger(input, 'cut')
  639. _.nextTick(function () {
  640. expect(vm.test).toBe('aa')
  641. input.value = 'a'
  642. trigger(input, 'keyup', function (e) {
  643. e.keyCode = 8
  644. })
  645. expect(vm.test).toBe('a')
  646. // teardown
  647. vm._directives[0]._teardown()
  648. input.value = 'bbb'
  649. trigger(input, 'keyup', function (e) {
  650. e.keyCode = 8
  651. })
  652. expect(vm.test).toBe('a')
  653. _.isIE9 = ie9
  654. done()
  655. })
  656. })
  657. if (!_.isAndroid) {
  658. it('text + compositionevents', function (done) {
  659. var vm = new Vue({
  660. el: el,
  661. data: {
  662. test: 'aaa',
  663. test2: 'bbb'
  664. },
  665. template: '<input v-model="test"><input v-model="test2 | uppercase">'
  666. })
  667. var input = el.firstChild
  668. var input2 = el.childNodes[1]
  669. trigger(input, 'compositionstart')
  670. trigger(input2, 'compositionstart')
  671. input.value = input2.value = 'ccc'
  672. // input before composition unlock should not call set
  673. trigger(input, 'input')
  674. trigger(input2, 'input')
  675. expect(vm.test).toBe('aaa')
  676. expect(vm.test2).toBe('bbb')
  677. // after composition unlock it should work
  678. trigger(input, 'compositionend')
  679. trigger(input2, 'compositionend')
  680. trigger(input, 'input')
  681. trigger(input2, 'input')
  682. expect(vm.test).toBe('ccc')
  683. expect(vm.test2).toBe('ccc')
  684. // IE complains about "unspecified error" when calling
  685. // setSelectionRange() on an input element that's been
  686. // removed from the DOM, so we wait until the
  687. // selection range callback has fired to end this test.
  688. _.nextTick(done)
  689. })
  690. }
  691. it('textarea', function () {
  692. var vm = new Vue({
  693. el: el,
  694. data: {
  695. test: 'b',
  696. b: 'BB'
  697. },
  698. template: '<textarea v-model="test">a {{b}} c</textarea>'
  699. })
  700. expect(vm.test).toBe('a BB c')
  701. expect(el.firstChild.value).toBe('a BB c')
  702. })
  703. it('warn invalid tag', function () {
  704. new Vue({
  705. el: el,
  706. template: '<div v-model="test"></div>'
  707. })
  708. expect(hasWarned(_, 'does not support element type')).toBe(true)
  709. })
  710. it('warn invalid option value', function () {
  711. new Vue({
  712. el: el,
  713. data: { a: 123 },
  714. template: '<select v-model="test" options="a"></select>'
  715. })
  716. expect(hasWarned(_, 'Invalid options value')).toBe(true)
  717. })
  718. it('warn read-only filters', function () {
  719. new Vue({
  720. el: el,
  721. template: '<input v-model="abc | test">',
  722. filters: {
  723. test: function (v) {
  724. return v
  725. }
  726. }
  727. })
  728. expect(hasWarned(_, 'read-only filter')).toBe(true)
  729. })
  730. it('support jQuery change event', function (done) {
  731. // restore jQuery
  732. jQuery = $
  733. var vm = new Vue({
  734. el: el,
  735. data: {
  736. test: 'b'
  737. },
  738. template: '<input v-model="test">'
  739. })
  740. expect(el.firstChild.value).toBe('b')
  741. vm.test = 'a'
  742. _.nextTick(function () {
  743. expect(el.firstChild.value).toBe('a')
  744. el.firstChild.value = 'c'
  745. jQuery(el.firstChild).trigger('change')
  746. expect(vm.test).toBe('c')
  747. vm._directives[0]._teardown()
  748. el.firstChild.value = 'd'
  749. jQuery(el.firstChild).trigger('change')
  750. expect(vm.test).toBe('c')
  751. // unset jQuery
  752. jQuery = null
  753. done()
  754. })
  755. })
  756. it('support debounce', function (done) {
  757. var spy = jasmine.createSpy()
  758. var vm = new Vue({
  759. el: el,
  760. data: {
  761. test: 'a'
  762. },
  763. watch: {
  764. test: spy
  765. },
  766. template: '<input v-model="test" debounce="100">'
  767. })
  768. el.firstChild.value = 'b'
  769. trigger(el.firstChild, 'input')
  770. setTimeout(function () {
  771. el.firstChild.value = 'c'
  772. trigger(el.firstChild, 'input')
  773. }, 10)
  774. setTimeout(function () {
  775. el.firstChild.value = 'd'
  776. trigger(el.firstChild, 'input')
  777. }, 20)
  778. setTimeout(function () {
  779. expect(spy.calls.count()).toBe(0)
  780. expect(vm.test).toBe('a')
  781. }, 30)
  782. setTimeout(function () {
  783. expect(spy.calls.count()).toBe(1)
  784. expect(vm.test).toBe('d')
  785. done()
  786. }, 200)
  787. })
  788. })
  789. }