repeat_spec.js 21 KB

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