2
0

repeat_spec.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. var _ = require('../../../../src/util')
  2. var Vue = require('../../../../src/vue')
  3. if (_.inBrowser) {
  4. describe('v-repeat', function () {
  5. var el
  6. beforeEach(function () {
  7. el = document.createElement('div')
  8. spyOn(_, 'warn')
  9. })
  10. it('objects', function (done) {
  11. var vm = new Vue({
  12. el: el,
  13. data: {
  14. items: [{a:1}, {a:2}]
  15. },
  16. template: '<div v-repeat="items">{{$index}} {{a}}</div>'
  17. })
  18. assertMutations(vm, el, done)
  19. })
  20. it('primitive values', function (done) {
  21. var vm = new Vue({
  22. el: el,
  23. data: {
  24. items: [2, 1, 2]
  25. },
  26. template: '<div v-repeat="items">{{$index}} {{$value}}</div>'
  27. })
  28. assertPrimitiveMutations(vm, el, done)
  29. })
  30. it('objects with identifier', function (done) {
  31. var vm = new Vue({
  32. el: el,
  33. data: {
  34. items: [{a:1}, {a:2}]
  35. },
  36. template: '<div v-repeat="item:items">{{$index}} {{item.a}}</div>'
  37. })
  38. assertMutations(vm, el, done)
  39. })
  40. it('primitive with identifier', function (done) {
  41. var vm = new Vue({
  42. el: el,
  43. data: {
  44. items: [2, 1, 2]
  45. },
  46. template: '<div v-repeat="item:items">{{$index}} {{item}}</div>'
  47. })
  48. assertPrimitiveMutations(vm, el, done)
  49. })
  50. it('repeating an object of objects', function (done) {
  51. var vm = new Vue({
  52. el: el,
  53. data: {
  54. items: {
  55. a: {a:1},
  56. b: {a:2}
  57. }
  58. },
  59. template: '<div v-repeat="items">{{$index}} {{$key}} {{a}}</div>'
  60. })
  61. assertObjectMutations(vm, el, done)
  62. })
  63. it('repeating an object of primitives', function (done) {
  64. var vm = new Vue({
  65. el: el,
  66. data: {
  67. items: {
  68. a: 1,
  69. b: 2
  70. }
  71. },
  72. template: '<div v-repeat="items">{{$index}} {{$key}} {{$value}}</div>'
  73. })
  74. assertObjectPrimitiveMutations(vm, el, done)
  75. })
  76. it('repeating an object of objects with identifier', function (done) {
  77. var vm = new Vue({
  78. el: el,
  79. data: {
  80. items: {
  81. a: {a:1},
  82. b: {a:2}
  83. }
  84. },
  85. template: '<div v-repeat="item:items">{{$index}} {{$key}} {{item.a}}</div>'
  86. })
  87. assertObjectMutations(vm, el, done)
  88. })
  89. it('repeating an object of primitives with identifier', function (done) {
  90. var vm = new Vue({
  91. el: el,
  92. data: {
  93. items: {
  94. a: 1,
  95. b: 2
  96. }
  97. },
  98. template: '<div v-repeat="item:items">{{$index}} {{$key}} {{item}}</div>'
  99. })
  100. assertObjectPrimitiveMutations(vm, el, done)
  101. })
  102. it('array of arrays', function () {
  103. var vm = new Vue({
  104. el: el,
  105. data: {
  106. items: [[1,1], [2,2], [3,3]]
  107. },
  108. template: '<div v-repeat="items">{{$index}} {{$value}}</div>'
  109. })
  110. var markup = vm.items.map(function (item, i) {
  111. return '<div>' + i + ' ' + item.toString() + '</div>'
  112. }).join('') + '<!--v-repeat-->'
  113. expect(el.innerHTML).toBe(markup)
  114. })
  115. it('repeating object with filter', function () {
  116. var vm = new Vue({
  117. el: el,
  118. data: {
  119. items: {
  120. a: { msg: 'aaa' },
  121. b: { msg: 'bbb' }
  122. }
  123. },
  124. template: '<div v-repeat="items | filterBy \'aaa\'">{{msg}}</div>'
  125. })
  126. expect(el.innerHTML).toBe('<div>aaa</div><!--v-repeat-->')
  127. })
  128. it('v-component', function (done) {
  129. var vm = new Vue({
  130. el: el,
  131. data: {
  132. items: [{a:1}, {a:2}]
  133. },
  134. template: '<p v-repeat="items" v-component="test"></p>',
  135. components: {
  136. test: {
  137. template: '<div>{{$index}} {{a}}</div>',
  138. replace: true
  139. }
  140. }
  141. })
  142. assertMutations(vm, el, done)
  143. })
  144. it('v-component with inline-template', function (done) {
  145. var vm = new Vue({
  146. el: el,
  147. data: {
  148. items: [{a:1}, {a:2}]
  149. },
  150. template:
  151. '<div v-repeat="items" v-component="test" inline-template>' +
  152. '{{$index}} {{a}}' +
  153. '</div>',
  154. components: {
  155. test: {}
  156. }
  157. })
  158. assertMutations(vm, el, done)
  159. })
  160. it('v-component with primitive values', function (done) {
  161. var vm = new Vue({
  162. el: el,
  163. data: {
  164. items: [2, 1, 2]
  165. },
  166. template: '<p v-repeat="items" v-component="test"></p>',
  167. components: {
  168. test: {
  169. template: '<div>{{$index}} {{$value}}</div>',
  170. replace: true
  171. }
  172. }
  173. })
  174. assertPrimitiveMutations(vm, el, done)
  175. })
  176. it('v-component with object of objects', function (done) {
  177. var vm = new Vue({
  178. el: el,
  179. data: {
  180. items: {
  181. a: {a:1},
  182. b: {a:2}
  183. }
  184. },
  185. template: '<p v-repeat="items" v-component="test"></p>',
  186. components: {
  187. test: {
  188. template: '<div>{{$index}} {{$key}} {{a}}</div>',
  189. replace: true
  190. }
  191. }
  192. })
  193. assertObjectMutations(vm, el, done)
  194. })
  195. it('custom element component', function () {
  196. var vm = new Vue({
  197. el: el,
  198. data: {
  199. items: [{a:1}, {a:2}, {a:3}]
  200. },
  201. template: '<test-component v-repeat="items"></test-component>',
  202. components: {
  203. 'test-component': {
  204. template: '<p>{{$index}} {{a}}</p>',
  205. replace: true
  206. }
  207. }
  208. })
  209. expect(el.innerHTML).toBe('<p>0 1</p><p>1 2</p><p>2 3</p><!--v-repeat-->')
  210. })
  211. it('nested repeats', function () {
  212. var vm = new Vue({
  213. el: el,
  214. data: {
  215. items: [
  216. { items: [{a:1}, {a:2}], a: 1 },
  217. { items: [{a:3}, {a:4}], a: 2 }
  218. ]
  219. },
  220. template: '<div v-repeat="items">' +
  221. '<p v-repeat="items">{{$index}} {{a}} {{$parent.$index}} {{$parent.a}}</p>' +
  222. '</div>'
  223. })
  224. expect(el.innerHTML).toBe(
  225. '<div><p>0 1 0 1</p><p>1 2 0 1</p><!--v-repeat--></div>' +
  226. '<div><p>0 3 1 2</p><p>1 4 1 2</p><!--v-repeat--></div>' +
  227. '<!--v-repeat-->'
  228. )
  229. })
  230. it('nested repeats on object', function(){
  231. var vm = new Vue({
  232. el: el,
  233. data: {
  234. listHash: {
  235. listA: [{a: 1},{a: 2}],
  236. listB: [{a: 1},{a: 2}]
  237. }
  238. },
  239. template: '<div v-repeat="listHash">{{$key}}' +
  240. '<p v-repeat="$data">{{a}}</p>' +
  241. '</div>'
  242. })
  243. function output(key){
  244. var key1 = key === 'listA' ? 'listB' : 'listA'
  245. return '<div>'+ key +'<p>1</p><p>2</p><!--v-repeat--></div>' +
  246. '<div>'+ key1 +'<p>1</p><p>2</p><!--v-repeat--></div>' +
  247. '<!--v-repeat-->'
  248. }
  249. expect(el.innerHTML === output('listA') || el.innerHTML === output('listB')).toBeTruthy()
  250. })
  251. it('dynamic component type based on instance data', function () {
  252. var vm = new Vue({
  253. el: el,
  254. template: '<div v-repeat="list" v-component="view-{{type}}"></div>',
  255. data: {
  256. list: [
  257. { type: 'a' },
  258. { type: 'b' },
  259. { type: 'c' }
  260. ]
  261. },
  262. components: {
  263. 'view-a': {
  264. template: 'AAA'
  265. },
  266. 'view-b': {
  267. template: 'BBB'
  268. },
  269. 'view-c': {
  270. template: 'CCC'
  271. }
  272. }
  273. })
  274. expect(el.innerHTML).toBe('<div>AAA</div><div>BBB</div><div>CCC</div><!--v-repeat-->')
  275. // #458 meta properties
  276. vm = new Vue({
  277. el: el,
  278. template: '<div v-repeat="list" v-component="view-{{$value}}"></div>',
  279. data: {
  280. list: ['a', 'b', 'c']
  281. },
  282. components: {
  283. 'view-a': {
  284. template: 'AAA'
  285. },
  286. 'view-b': {
  287. template: 'BBB'
  288. },
  289. 'view-c': {
  290. template: 'CCC'
  291. }
  292. }
  293. })
  294. expect(el.innerHTML).toBe('<div>AAA</div><div>BBB</div><div>CCC</div><!--v-repeat-->')
  295. })
  296. it('block repeat', function () {
  297. var vm = new Vue({
  298. el: el,
  299. template: '<template v-repeat="list"><p>{{a}}</p><p>{{a + 1}}</p></template>',
  300. data: {
  301. list: [
  302. { a: 1 },
  303. { a: 2 },
  304. { a: 3 }
  305. ]
  306. }
  307. })
  308. var markup = vm.list.map(function (item) {
  309. return '<!--v-start--><p>' + item.a + '</p><p>' + (item.a + 1) + '</p><!--v-end-->'
  310. }).join('')
  311. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  312. })
  313. it('component + parent directive + transclusion', function (done) {
  314. var vm = new Vue({
  315. el: el,
  316. template: '<div v-repeat="list" v-component="test" v-class="cls">{{msg}}</div>',
  317. data: {
  318. cls: 'parent',
  319. msg: 'hi',
  320. list: [{a:1},{a:2},{a:3}]
  321. },
  322. components: {
  323. test: {
  324. replace: true,
  325. template: '<div class="child">{{a}} <content></content></div>'
  326. }
  327. }
  328. })
  329. var markup = vm.list.map(function (item) {
  330. return '<div class="child parent">' + item.a + ' hi</div>'
  331. }).join('')
  332. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  333. vm.msg = 'ho'
  334. markup = vm.list.map(function (item) {
  335. return '<div class="child parent">' + item.a + ' ho</div>'
  336. }).join('')
  337. _.nextTick(function () {
  338. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  339. done()
  340. })
  341. })
  342. it('array filters', function (done) {
  343. var vm = new Vue({
  344. el: el,
  345. template: '<div v-repeat="list | filterBy filterKey | orderBy sortKey -1">{{id}}</div>',
  346. data: {
  347. filterKey: 'hi!',
  348. sortKey: 'id',
  349. list: [
  350. { id: 1, id2: 4, msg: 'hi!' },
  351. { id: 2, id2: 3, msg: 'na' },
  352. { id: 3, id2: 2, msg: 'hi!' },
  353. { id: 4, id2: 1, msg: 'na' }
  354. ]
  355. }
  356. })
  357. assertMarkup()
  358. go(
  359. function () {
  360. vm.filterKey = 'na'
  361. }, assertMarkup
  362. )
  363. .then(
  364. function () {
  365. vm.sortKey = 'id2'
  366. }, assertMarkup
  367. )
  368. .then(
  369. function () {
  370. vm.list[0].id2 = 0
  371. }, assertMarkup
  372. )
  373. .then(
  374. function () {
  375. vm.list.push({ id: 0, id2: 4, msg: 'na' })
  376. }, assertMarkup
  377. )
  378. .then(
  379. function () {
  380. vm.list = [
  381. { id: 33, id2: 4, msg: 'hi!' },
  382. { id: 44, id2: 3, msg: 'na' }
  383. ]
  384. }, assertMarkup
  385. )
  386. .run(done)
  387. function assertMarkup () {
  388. var markup = vm.list
  389. .filter(function (item) {
  390. return item.msg === vm.filterKey
  391. })
  392. .sort(function (a, b) {
  393. return a[vm.sortKey] > b[vm.sortKey] ? -1 : 1
  394. })
  395. .map(function (item) {
  396. return '<div>' + item.id + '</div>'
  397. }).join('')
  398. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  399. }
  400. })
  401. it('orderBy supporting $key for object repeaters', function (done) {
  402. var vm = new Vue({
  403. el: el,
  404. template: '<div v-repeat="obj | orderBy sortKey">{{$value}}</div>',
  405. data: {
  406. sortKey: '$key',
  407. obj: {
  408. c: 1,
  409. a: 3,
  410. b: 2
  411. }
  412. }
  413. })
  414. expect(el.innerHTML).toBe('<div>3</div><div>2</div><div>1</div><!--v-repeat-->')
  415. vm.sortKey = '$value'
  416. _.nextTick(function () {
  417. expect(el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div><!--v-repeat-->')
  418. done()
  419. })
  420. })
  421. it('orderBy supporting $value for primitive arrays', function () {
  422. var vm = new Vue({
  423. el: el,
  424. template: '<div v-repeat="list | orderBy \'$value\'">{{$value}}</div>',
  425. data: {
  426. list: [3, 2, 1]
  427. }
  428. })
  429. expect(el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div><!--v-repeat-->')
  430. })
  431. it('track by id', function (done) {
  432. assertTrackBy('<div v-repeat="list" v-component="test" track-by="id"></div>', '{{msg}}', function () {
  433. assertTrackBy('<div v-repeat="item:list" v-component="test" track-by="id"></div>', '{{item.msg}}', done)
  434. })
  435. function assertTrackBy (template, componentTemplate, next) {
  436. var vm = new Vue({
  437. el: el,
  438. template: template,
  439. data: {
  440. list: [
  441. { id: 1, msg: 'hi' },
  442. { id: 2, msg: 'ha' },
  443. { id: 3, msg: 'ho' }
  444. ]
  445. },
  446. components: {
  447. test: {
  448. template: componentTemplate
  449. }
  450. }
  451. })
  452. assertMarkup()
  453. var oldVms = vm._children.slice()
  454. // swap the data with different objects, but with
  455. // the same ID!
  456. vm.list = [
  457. { id: 1, msg: 'wa' },
  458. { id: 2, msg: 'wo' }
  459. ]
  460. _.nextTick(function () {
  461. assertMarkup()
  462. // should reuse old vms!
  463. var i = 2
  464. while (i--) {
  465. expect(vm._children[i]).toBe(oldVms[i])
  466. }
  467. next()
  468. })
  469. function assertMarkup () {
  470. var markup = vm.list.map(function (item) {
  471. return '<div>' + item.msg + '</div>'
  472. }).join('')
  473. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  474. }
  475. }
  476. })
  477. it('warn duplicate objects', function () {
  478. var obj = {}
  479. var vm = new Vue({
  480. el: el,
  481. template: '<div v-repeat="items" v-component="test"></div>',
  482. data: {
  483. items: [obj, obj]
  484. },
  485. components: {
  486. test: {}
  487. }
  488. })
  489. expect(_.warn).toHaveBeenCalled()
  490. })
  491. it('warn duplicate trackby id', function () {
  492. var vm = new Vue({
  493. el: el,
  494. template: '<div v-repeat="items" v-component="test" track-by="id"></div>',
  495. data: {
  496. items: [{id:1}, {id:1}]
  497. },
  498. components: {
  499. test: {}
  500. }
  501. })
  502. expect(_.warn).toHaveBeenCalled()
  503. })
  504. it('warn v-if', function () {
  505. var vm = new Vue({
  506. el: el,
  507. template: '<div v-repeat="items" v-if="aaa"></div>',
  508. data: {
  509. items: []
  510. }
  511. })
  512. expect(_.warn).toHaveBeenCalled()
  513. })
  514. it('repeat number', function () {
  515. var vm = new Vue({
  516. el: el,
  517. template: '<div v-repeat="3">{{$index}} {{$value}}</div>'
  518. })
  519. expect(el.innerHTML).toBe('<div>0 0</div><div>1 1</div><div>2 2</div><!--v-repeat-->')
  520. })
  521. it('repeat string', function () {
  522. var vm = new Vue({
  523. el: el,
  524. template: '<div v-repeat="\'vue\'">{{$index}} {{$value}}</div>'
  525. })
  526. expect(el.innerHTML).toBe('<div>0 v</div><div>1 u</div><div>2 e</div><!--v-repeat-->')
  527. })
  528. it('teardown', function () {
  529. var vm = new Vue({
  530. el: el,
  531. template: '<div v-repeat="items" v-component="test"></div>',
  532. data: {
  533. items: [{a:1}, {a:2}]
  534. },
  535. components: {
  536. test: {}
  537. }
  538. })
  539. vm._directives[0].unbind()
  540. expect(vm._children.length).toBe(0)
  541. })
  542. it('with transition', function (done) {
  543. document.body.appendChild(el)
  544. var vm = new Vue({
  545. el: el,
  546. template: '<div v-repeat="items" v-transition="test">{{a}}</div>',
  547. data: {
  548. items: [{a:1}, {a:2}, {a:3}]
  549. },
  550. transitions: {
  551. test: {
  552. leave: function (el, done) {
  553. setTimeout(done, 1)
  554. }
  555. }
  556. }
  557. })
  558. vm.items.splice(1, 1, {a:4})
  559. setTimeout(function () {
  560. expect(el.innerHTML).toBe('<div>1</div><div>4</div><div>3</div><!--v-repeat-->')
  561. document.body.removeChild(el)
  562. done()
  563. }, 30)
  564. })
  565. it('sync $value changes back to original array/object', function (done) {
  566. var vm = new Vue({
  567. el: el,
  568. template:
  569. '<div v-repeat="items">{{$value}}</div>' +
  570. '<div v-repeat="obj">{{$value}}</div>',
  571. data: {
  572. items: ['a', 'b'],
  573. obj: { foo: 'a', bar: 'b' }
  574. }
  575. })
  576. vm._children[0].$value = 'c'
  577. var key = vm._children[2].$key
  578. vm._children[2].$value = 'd'
  579. _.nextTick(function () {
  580. expect(vm.items[0]).toBe('c')
  581. expect(vm.obj[key]).toBe('d')
  582. done()
  583. })
  584. })
  585. })
  586. }
  587. /**
  588. * Simple helper for chained async asssertions
  589. *
  590. * @param {Function} fn - the data manipulation function
  591. * @param {Function} cb - the assertion fn to be called on nextTick
  592. */
  593. function go (fn, cb) {
  594. return {
  595. stack: [{fn:fn, cb:cb}],
  596. then: function (fn, cb) {
  597. this.stack.push({fn:fn, cb:cb})
  598. return this
  599. },
  600. run: function (done) {
  601. var self = this
  602. var step = this.stack.shift()
  603. if (!step) return done()
  604. step.fn()
  605. _.nextTick(function () {
  606. step.cb()
  607. self.run(done)
  608. })
  609. }
  610. }
  611. }
  612. /**
  613. * Assert mutation and markup correctness for v-repeat on
  614. * an Array of Objects
  615. */
  616. function assertMutations (vm, el, done) {
  617. assertMarkup()
  618. var poppedItem
  619. go(
  620. function () {
  621. vm.items.push({a:3})
  622. },
  623. assertMarkup
  624. )
  625. .then(
  626. function () {
  627. vm.items.shift()
  628. },
  629. assertMarkup
  630. )
  631. .then(
  632. function () {
  633. vm.items.reverse()
  634. },
  635. assertMarkup
  636. )
  637. .then(
  638. function () {
  639. poppedItem = vm.items.pop()
  640. },
  641. assertMarkup
  642. )
  643. .then(
  644. function () {
  645. vm.items.unshift(poppedItem)
  646. },
  647. assertMarkup
  648. )
  649. .then(
  650. function () {
  651. vm.items.sort(function (a, b) {
  652. return a.a > b.a ? 1 : -1
  653. })
  654. },
  655. assertMarkup
  656. )
  657. .then(
  658. function () {
  659. vm.items.splice(1, 1, {a:5})
  660. },
  661. assertMarkup
  662. )
  663. // test swapping the array
  664. .then(
  665. function () {
  666. vm.items = [{a:0}, {a:1}, {a:2}]
  667. },
  668. assertMarkup
  669. )
  670. .run(done)
  671. function assertMarkup () {
  672. var markup = vm.items.map(function (item, i) {
  673. return '<div>' + i + ' ' + item.a + '</div>'
  674. }).join('')
  675. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  676. }
  677. }
  678. /**
  679. * Assert mutation and markup correctness for v-repeat on
  680. * an Array of primitive values
  681. */
  682. function assertPrimitiveMutations (vm, el, done) {
  683. assertMarkup()
  684. go(
  685. function () {
  686. // check duplicate
  687. vm.items.push(2, 2, 3)
  688. },
  689. assertMarkup
  690. )
  691. .then(
  692. function () {
  693. vm.items.shift()
  694. },
  695. assertMarkup
  696. )
  697. .then(
  698. function () {
  699. vm.items.reverse()
  700. },
  701. assertMarkup
  702. )
  703. .then(
  704. function () {
  705. vm.items.pop()
  706. },
  707. assertMarkup
  708. )
  709. .then(
  710. function () {
  711. vm.items.unshift(3)
  712. },
  713. assertMarkup
  714. )
  715. .then(
  716. function () {
  717. vm.items.sort(function (a, b) {
  718. return a > b ? 1 : -1
  719. })
  720. },
  721. assertMarkup
  722. )
  723. .then(
  724. function () {
  725. vm.items.splice(1, 1, 5)
  726. },
  727. assertMarkup
  728. )
  729. // test swapping the array
  730. .then(
  731. function () {
  732. vm.items = [1, 2, 2]
  733. },
  734. assertMarkup
  735. )
  736. .run(done)
  737. function assertMarkup () {
  738. var markup = vm.items.map(function (item, i) {
  739. return '<div>' + i + ' ' + item + '</div>'
  740. }).join('')
  741. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  742. }
  743. }
  744. /**
  745. * Assert mutation and markup correctness for v-repeat on
  746. * an Object of Objects
  747. */
  748. function assertObjectMutations (vm, el, done) {
  749. assertMarkup()
  750. go(
  751. function () {
  752. vm.items.a = {a:3}
  753. },
  754. assertMarkup
  755. )
  756. .then(
  757. function () {
  758. vm.items = {
  759. c: {a:1},
  760. d: {a:2}
  761. }
  762. },
  763. assertMarkup
  764. )
  765. .then(
  766. function () {
  767. vm.items.$add('a', {a:3})
  768. },
  769. assertMarkup
  770. )
  771. .run(done)
  772. function assertMarkup () {
  773. var markup = Object.keys(vm.items).map(function (key, i) {
  774. return '<div>' + i + ' ' + key + ' ' + vm.items[key].a + '</div>'
  775. }).join('')
  776. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  777. }
  778. }
  779. /**
  780. * Assert mutation and markup correctness for v-repeat on
  781. * an Object of primitive values
  782. */
  783. function assertObjectPrimitiveMutations (vm, el, done) {
  784. assertMarkup()
  785. go(
  786. function () {
  787. vm.items.a = 3
  788. },
  789. assertMarkup
  790. )
  791. .then(
  792. function () {
  793. vm.items = {
  794. c: 1,
  795. d: 2
  796. }
  797. },
  798. assertMarkup
  799. )
  800. .then(
  801. function () {
  802. vm.items.$add('a', 3)
  803. },
  804. assertMarkup
  805. )
  806. .run(done)
  807. function assertMarkup () {
  808. var markup = Object.keys(vm.items).map(function (key, i) {
  809. return '<div>' + i + ' ' + key + ' ' + vm.items[key] + '</div>'
  810. }).join('')
  811. expect(el.innerHTML).toBe(markup + '<!--v-repeat-->')
  812. }
  813. }