| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- import { basePatch as patch } from 'web/runtime/patch'
- import VNode from 'core/vdom/vnode'
- function prop (name) {
- return obj => { return obj[name] }
- }
- function map (fn, list) {
- const ret = []
- for (let i = 0; i < list.length; i++) {
- ret[i] = fn(list[i])
- }
- return ret
- }
- function spanNum (n) {
- if (typeof n === 'string') {
- return new VNode('span', {}, undefined, n)
- } else {
- return new VNode('span', { key: n }, undefined, n.toString())
- }
- }
- function shuffle (array) {
- let currentIndex = array.length
- let temporaryValue
- let randomIndex
- // while there remain elements to shuffle...
- while (currentIndex !== 0) {
- // pick a remaining element...
- randomIndex = Math.floor(Math.random() * currentIndex)
- currentIndex -= 1
- // and swap it with the current element.
- temporaryValue = array[currentIndex]
- array[currentIndex] = array[randomIndex]
- array[randomIndex] = temporaryValue
- }
- return array
- }
- const inner = prop('innerHTML')
- describe('children', () => {
- let vnode0
- beforeEach(() => {
- vnode0 = new VNode('p', { attrs: { id: '1' }}, [createTextVNode('hello world')])
- patch(null, vnode0)
- })
- it('should appends elements', () => {
- const vnode1 = new VNode('p', {}, [1].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 3].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(1)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(3)
- expect(elm.children[1].innerHTML).toBe('2')
- expect(elm.children[2].innerHTML).toBe('3')
- })
- it('should prepends elements', () => {
- const vnode1 = new VNode('p', {}, [4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(2)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
- })
- it('should add elements in the middle', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(4)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
- })
- it('should add elements at begin and end', () => {
- const vnode1 = new VNode('p', {}, [2, 3, 4].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(3)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
- })
- it('should add children to parent with no children', () => {
- const vnode1 = new VNode('p', { key: 'p' })
- const vnode2 = new VNode('p', { key: 'p' }, [1, 2, 3].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(0)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['1', '2', '3'])
- })
- it('should remove all children from parent', () => {
- const vnode1 = new VNode('p', { key: 'p' }, [1, 2, 3].map(spanNum))
- const vnode2 = new VNode('p', { key: 'p' })
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['1', '2', '3'])
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(0)
- })
- it('should remove elements from the beginning', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [3, 4, 5].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(5)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['3', '4', '5'])
- })
- it('should removes elements from end', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 3].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(5)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(3)
- expect(elm.children[0].innerHTML).toBe('1')
- expect(elm.children[1].innerHTML).toBe('2')
- expect(elm.children[2].innerHTML).toBe('3')
- })
- it('should remove elements from the middle', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 2, 4, 5].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(5)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(4)
- expect(elm.children[0].innerHTML).toBe('1')
- expect(elm.children[1].innerHTML).toBe('2')
- expect(elm.children[2].innerHTML).toBe('4')
- expect(elm.children[3].innerHTML).toBe('5')
- })
- it('should moves element forward', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
- const vnode2 = new VNode('p', {}, [2, 3, 1, 4].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(4)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(4)
- expect(elm.children[0].innerHTML).toBe('2')
- expect(elm.children[1].innerHTML).toBe('3')
- expect(elm.children[2].innerHTML).toBe('1')
- expect(elm.children[3].innerHTML).toBe('4')
- })
- it('should move elements to end', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3].map(spanNum))
- const vnode2 = new VNode('p', {}, [2, 3, 1].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(3)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(3)
- expect(elm.children[0].innerHTML).toBe('2')
- expect(elm.children[1].innerHTML).toBe('3')
- expect(elm.children[2].innerHTML).toBe('1')
- })
- it('should move element backwards', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
- const vnode2 = new VNode('p', {}, [1, 4, 2, 3].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(4)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(4)
- expect(elm.children[0].innerHTML).toBe('1')
- expect(elm.children[1].innerHTML).toBe('4')
- expect(elm.children[2].innerHTML).toBe('2')
- expect(elm.children[3].innerHTML).toBe('3')
- })
- it('should swap first and last', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
- const vnode2 = new VNode('p', {}, [4, 2, 3, 1].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(4)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(4)
- expect(elm.children[0].innerHTML).toBe('4')
- expect(elm.children[1].innerHTML).toBe('2')
- expect(elm.children[2].innerHTML).toBe('3')
- expect(elm.children[3].innerHTML).toBe('1')
- })
- it('should move to left and replace', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [4, 1, 2, 3, 6].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(5)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(5)
- expect(elm.children[0].innerHTML).toBe('4')
- expect(elm.children[1].innerHTML).toBe('1')
- expect(elm.children[2].innerHTML).toBe('2')
- expect(elm.children[3].innerHTML).toBe('3')
- expect(elm.children[4].innerHTML).toBe('6')
- })
- it('should move to left and leaves hold', () => {
- const vnode1 = new VNode('p', {}, [1, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [4, 6].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(3)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['4', '6'])
- })
- it('should handle moved and set to undefined element ending at the end', () => {
- const vnode1 = new VNode('p', {}, [2, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [4, 5, 3].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(3)
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(3)
- expect(elm.children[0].innerHTML).toBe('4')
- expect(elm.children[1].innerHTML).toBe('5')
- expect(elm.children[2].innerHTML).toBe('3')
- })
- it('should move a key in non-keyed nodes with a size up', () => {
- const vnode1 = new VNode('p', {}, [1, 'a', 'b', 'c'].map(spanNum))
- const vnode2 = new VNode('p', {}, ['d', 'a', 'b', 'c', 1, 'e'].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(4)
- expect(elm.textContent, '1abc')
- elm = patch(vnode1, vnode2)
- expect(elm.children.length).toBe(6)
- expect(elm.textContent, 'dabc1e')
- })
- it('should reverse element', () => {
- const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5, 6, 7, 8].map(spanNum))
- const vnode2 = new VNode('p', {}, [8, 7, 6, 5, 4, 3, 2, 1].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(8)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['8', '7', '6', '5', '4', '3', '2', '1'])
- })
- it('something', () => {
- const vnode1 = new VNode('p', {}, [0, 1, 2, 3, 4, 5].map(spanNum))
- const vnode2 = new VNode('p', {}, [4, 3, 2, 1, 5, 0].map(spanNum))
- let elm = patch(vnode0, vnode1)
- expect(elm.children.length).toBe(6)
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['4', '3', '2', '1', '5', '0'])
- })
- it('should handle random shuffle', () => {
- let n
- let i
- const arr = []
- const opacities = []
- const elms = 14
- const samples = 5
- function spanNumWithOpacity (n, o) {
- return new VNode('span', { key: n, style: { opacity: o }}, undefined, n.toString())
- }
- for (n = 0; n < elms; ++n) { arr[n] = n }
- for (n = 0; n < samples; ++n) {
- const vnode1 = new VNode('span', {}, arr.map(n => {
- return spanNumWithOpacity(n, '1')
- }))
- const shufArr = shuffle(arr.slice(0))
- let elm = patch(vnode0, vnode1)
- for (i = 0; i < elms; ++i) {
- expect(elm.children[i].innerHTML).toBe(i.toString())
- opacities[i] = Math.random().toFixed(5).toString()
- }
- const vnode2 = new VNode('span', {}, arr.map(n => {
- return spanNumWithOpacity(shufArr[n], opacities[n])
- }))
- elm = patch(vnode1, vnode2)
- for (i = 0; i < elms; ++i) {
- expect(elm.children[i].innerHTML).toBe(shufArr[i].toString())
- expect(opacities[i].indexOf(elm.children[i].style.opacity)).toBe(0)
- }
- }
- })
- it('should append elements with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'hello')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'hello'),
- new VNode('span', {}, undefined, 'world')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['hello'])
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['hello', 'world'])
- })
- it('should handle unmoved text nodes with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- createTextVNode('text'),
- new VNode('span', {}, undefined, 'hello')
- ])
- const vnode2 = new VNode('div', {}, [
- createTextVNode('text'),
- new VNode('span', {}, undefined, 'hello')
- ])
- let elm = patch(vnode0, vnode1)
- expect(elm.childNodes[0].textContent).toBe('text')
- elm = patch(vnode1, vnode2)
- expect(elm.childNodes[0].textContent).toBe('text')
- })
- it('should handle changing text children with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- createTextVNode('text'),
- new VNode('span', {}, undefined, 'hello')
- ])
- const vnode2 = new VNode('div', {}, [
- createTextVNode('text2'),
- new VNode('span', {}, undefined, 'hello')
- ])
- let elm = patch(vnode0, vnode1)
- expect(elm.childNodes[0].textContent).toBe('text')
- elm = patch(vnode1, vnode2)
- expect(elm.childNodes[0].textContent).toBe('text2')
- })
- it('should prepend element with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'world')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'hello'),
- new VNode('span', {}, undefined, 'world')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['world'])
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['hello', 'world'])
- })
- it('should prepend element of different tag type with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'world')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('div', {}, undefined, 'hello'),
- new VNode('span', {}, undefined, 'world')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['world'])
- elm = patch(vnode1, vnode2)
- expect(map(prop('tagName'), elm.children)).toEqual(['DIV', 'SPAN'])
- expect(map(inner, elm.children)).toEqual(['hello', 'world'])
- })
- it('should remove elements with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'one'),
- new VNode('span', {}, undefined, 'two'),
- new VNode('span', {}, undefined, 'three')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'one'),
- new VNode('span', {}, undefined, 'three')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['one', 'two', 'three'])
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['one', 'three'])
- })
- it('should remove a single text node with updating children without keys', () => {
- const vnode1 = new VNode('div', {}, undefined, 'one')
- const vnode2 = new VNode('div', {})
- let elm = patch(vnode0, vnode1)
- expect(elm.textContent).toBe('one')
- elm = patch(vnode1, vnode2)
- expect(elm.textContent).toBe('')
- })
- it('should remove a single text node when children are updated', () => {
- const vnode1 = new VNode('div', {}, undefined, 'one')
- const vnode2 = new VNode('div', {}, [
- new VNode('div', {}, undefined, 'two'),
- new VNode('span', {}, undefined, 'three')
- ])
- let elm = patch(vnode0, vnode1)
- expect(elm.textContent).toBe('one')
- elm = patch(vnode1, vnode2)
- expect(map(prop('textContent'), elm.childNodes)).toEqual(['two', 'three'])
- })
- it('should remove a text node among other elements', () => {
- const vnode1 = new VNode('div', {}, [
- createTextVNode('one'),
- new VNode('span', {}, undefined, 'two')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('div', {}, undefined, 'three')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(prop('textContent'), elm.childNodes)).toEqual(['one', 'two'])
- elm = patch(vnode1, vnode2)
- expect(elm.childNodes.length).toBe(1)
- expect(elm.childNodes[0].tagName).toBe('DIV')
- expect(elm.childNodes[0].textContent).toBe('three')
- })
- it('should reorder elements', () => {
- const vnode1 = new VNode('div', {}, [
- new VNode('span', {}, undefined, 'one'),
- new VNode('div', {}, undefined, 'two'),
- new VNode('b', {}, undefined, 'three')
- ])
- const vnode2 = new VNode('div', {}, [
- new VNode('b', {}, undefined, 'three'),
- new VNode('span', {}, undefined, 'two'),
- new VNode('div', {}, undefined, 'one')
- ])
- let elm = patch(vnode0, vnode1)
- expect(map(inner, elm.children)).toEqual(['one', 'two', 'three'])
- elm = patch(vnode1, vnode2)
- expect(map(inner, elm.children)).toEqual(['three', 'two', 'one'])
- })
- })
|