model_spec.js 20 KB

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