Răsfoiți Sursa

more tests/fixes

Evan You 10 ani în urmă
părinte
comite
eca4ad8203

+ 13 - 3
src/core/vdom/patch.js

@@ -14,11 +14,11 @@ const emptyNode = new VNode('', {}, [])
 const hooks = ['create', 'update', 'postpatch', 'remove', 'destroy']
 const hooks = ['create', 'update', 'postpatch', 'remove', 'destroy']
 
 
 function isUndef (s) {
 function isUndef (s) {
-  return s === undefined
+  return s == null
 }
 }
 
 
 function isDef (s) {
 function isDef (s) {
-  return s !== undefined
+  return s != null
 }
 }
 
 
 function sameVnode (vnode1, vnode2) {
 function sameVnode (vnode1, vnode2) {
@@ -229,8 +229,18 @@ export function createPatchFunction (backend) {
             )
             )
           }
           }
           patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
           patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
+          // possible edge case: if elmToMove and newStartVnode are not the
+          // same vnode (e.g. same key, different tag), the elmToMove is replaced
+          // by the newStartVnode. If elmToMove happens to be the oldStartVnode,
+          // the oldStartVnode will be holding on to an element that has been
+          // removed from the DOM. This causes later moving operations to
+          // fail. This can be fixed by replacing the oldStartVnode with the
+          // newStartVnode.
+          if (elmToMove === oldStartVnode) {
+            oldStartVnode = newStartVnode
+          }
           oldCh[idxInOld] = undefined
           oldCh[idxInOld] = undefined
-          nodeOps.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm)
+          nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm)
           newStartVnode = newCh[++newStartIdx]
           newStartVnode = newCh[++newStartIdx]
         }
         }
       }
       }

+ 12 - 1
test/unit/features/options/render.spec.js

@@ -7,7 +7,7 @@ describe('Options render', () => {
         const h = this.$createElement
         const h = this.$createElement
         const children = []
         const children = []
         for (let i = 0; i < this.items.length; i++) {
         for (let i = 0; i < this.items.length; i++) {
-          children.push(h('li', { staticClass: 'task' }, this.items[i].name /* string as children*/))
+          children.push(h('li', { staticClass: 'task' }, [this.items[i].name]))
         }
         }
         return h('ul', { staticClass: 'tasks' }, children)
         return h('ul', { staticClass: 'tasks' }, children)
       },
       },
@@ -23,6 +23,17 @@ describe('Options render', () => {
     }
     }
   })
   })
 
 
+  it('allow null data', () => {
+    const vm = new Vue({
+      render () {
+        const h = this.$createElement
+        return h('div', null, 'hello' /* string as children*/)
+      }
+    }).$mount()
+    expect(vm.$el.tagName).toBe('DIV')
+    expect(vm.$el.textContent).toBe('hello')
+  })
+
   it('should warn non `render` option and non `template` option', () => {
   it('should warn non `render` option and non `template` option', () => {
     new Vue().$mount()
     new Vue().$mount()
     expect('Failed to mount component: template or render function not defined.').toHaveBeenWarned()
     expect('Failed to mount component: template or render function not defined.').toHaveBeenWarned()

+ 22 - 0
test/unit/modules/vdom/patch/children.spec.js

@@ -40,6 +40,7 @@ function shuffle (array) {
 }
 }
 
 
 const inner = prop('innerHTML')
 const inner = prop('innerHTML')
+const tag = prop('tagName')
 
 
 describe('children', () => {
 describe('children', () => {
   let vnode0
   let vnode0
@@ -428,4 +429,25 @@ describe('children', () => {
     elm = patch(vnode1, vnode2)
     elm = patch(vnode1, vnode2)
     expect(map(inner, elm.children)).toEqual(['three', 'two', 'one'])
     expect(map(inner, elm.children)).toEqual(['three', 'two', 'one'])
   })
   })
+
+  it('should handle children with the same key but with different tag', () => {
+    const vnode1 = new VNode('div', {}, [
+      new VNode('div', { key: 1 }, undefined, 'one'),
+      new VNode('div', { key: 2 }, undefined, 'two'),
+      new VNode('div', { key: 3 }, undefined, 'three'),
+      new VNode('div', { key: 4 }, undefined, 'four')
+    ])
+    const vnode2 = new VNode('div', {}, [
+      new VNode('div', { key: 4 }, undefined, 'four'),
+      new VNode('span', { key: 3 }, undefined, 'three'),
+      new VNode('span', { key: 2 }, undefined, 'two'),
+      new VNode('div', { key: 1 }, undefined, 'one')
+    ])
+    let elm = patch(vnode0, vnode1)
+    expect(map(tag, elm.children)).toEqual(['DIV', 'DIV', 'DIV', 'DIV'])
+    expect(map(inner, elm.children)).toEqual(['one', 'two', 'three', 'four'])
+    elm = patch(vnode1, vnode2)
+    expect(map(tag, elm.children)).toEqual(['DIV', 'SPAN', 'SPAN', 'DIV'])
+    expect(map(inner, elm.children)).toEqual(['four', 'three', 'two', 'one'])
+  })
 })
 })

+ 4 - 2
test/unit/modules/vdom/patch/hydration.spec.js

@@ -20,6 +20,8 @@ describe('hydration', () => {
       const div = nodeOps.createElement('div')
       const div = nodeOps.createElement('div')
       const child1 = nodeOps.createElement('span')
       const child1 = nodeOps.createElement('span')
       const child2 = nodeOps.createElement('span')
       const child2 = nodeOps.createElement('span')
+      child1.textContent = 'hi'
+      child2.textContent = 'ho'
       div.appendChild(child1)
       div.appendChild(child1)
       div.appendChild(child2)
       div.appendChild(child2)
       root.appendChild(div)
       root.appendChild(div)
@@ -29,8 +31,8 @@ describe('hydration', () => {
     const vnode1 = new VNode('div', {}, [
     const vnode1 = new VNode('div', {}, [
       new VNode('span', {}),
       new VNode('span', {}),
       new VNode('div', { hook: { init }}, [
       new VNode('div', { hook: { init }}, [
-        new VNode('span', {}),
-        new VNode('span', {})
+        new VNode('span', {}, [new VNode(undefined, undefined, undefined, 'hi')]),
+        new VNode('span', {}, [new VNode(undefined, undefined, undefined, 'ho')])
       ])
       ])
     ])
     ])
     patch(node0, vnode1)
     patch(node0, vnode1)