You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by da...@apache.org on 2017/08/17 03:59:43 UTC

[26/43] incubator-weex git commit: * [test] refactor the unit test cases of runtime

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/runtime/vdom/listener.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/vdom/listener.js b/html5/test/unit/runtime/vdom/listener.js
new file mode 100644
index 0000000..1eab8d5
--- /dev/null
+++ b/html5/test/unit/runtime/vdom/listener.js
@@ -0,0 +1,381 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import chai from 'chai'
+import sinon from 'sinon'
+import sinonChai from 'sinon-chai'
+const { expect } = chai
+chai.use(sinonChai)
+
+import { Document } from '../../../../runtime/vdom'
+import Listener from '../../../../runtime/bridge/Listener'
+
+describe('dom listener basic', () => {
+  it('works with no id', () => {
+    const doc = new Document(null, null, null)
+    doc.destroy()
+  })
+
+  it('works with no handler', () => {
+    const oriCallNative = global.callNative
+    const oriCallAddElement = global.callAddElement
+    const oriDocumentHandler = Document.handler
+
+    Document.handler = null
+    global.callNative = function () { return -1 }
+    global.callAddElement = function () { return -1 }
+
+    const doc = new Document('foo1', null, null)
+    doc.createBody('r')
+    doc.documentElement.appendChild(doc.body)
+    const el = doc.createElement('a')
+    doc.body.appendChild(el)
+    doc.destroy()
+
+    global.callNative = oriCallNative
+    global.callAddElement = oriCallAddElement
+    Document.handler = oriDocumentHandler
+  })
+
+  it('works with an handler', () => {
+    const doc = new Document('foo2', null, function () {})
+    doc.createBody('r')
+    doc.documentElement.appendChild(doc.body)
+    doc.destroy()
+  })
+
+  it('works with an handler', () => {
+    const doc = new Document('foo2', null, function () {})
+    doc.createBody('r')
+    doc.documentElement.appendChild(doc.body)
+    doc.destroy()
+  })
+})
+
+describe('dom listener details', () => {
+  let doc, spy
+
+  beforeEach(() => {
+    spy = sinon.spy()
+    doc = new Document('foo', '', spy, Listener)
+  })
+
+  afterEach(() => {
+    doc.destroy()
+  })
+
+  it('create document again', (done) => {
+    const documentElement = doc.createDocumentElement()
+
+    expect(documentElement).eql(doc.documentElement)
+    done()
+  })
+
+  it('create body', (done) => {
+    const body = doc.createBody('r', {
+      attr: { a: 1 }, style: { b: 2 }
+    })
+
+    doc.documentElement.appendChild(body)
+
+    expect(spy.args.length).eql(1)
+    expect(spy.args[0]).eql([[{
+      module: 'dom', method: 'createBody',
+      args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
+    }], '-1'])
+    done()
+  })
+
+  it('document appendChild', (done) => {
+    const el = doc.createElement('father')
+    const el2 = doc.createElement('child1')
+    const el3 = doc.createElement('child2')
+
+    el.appendChild(el2)
+    el.appendChild(el3)
+
+    doc.documentElement.appendChild(el)
+
+    expect(doc.documentElement.children.length).eql(1)
+    expect(doc.documentElement.children[0]).eql(el)
+
+    done()
+  })
+
+  it('document insertBefore', (done) => {
+    const body = doc.createBody('r', {
+      attr: { a: 1 }, style: { b: 2 }
+    })
+
+    doc.documentElement.insertBefore(body)
+
+    expect(spy.args.length).eql(1)
+    expect(spy.args[0]).eql([[{
+      module: 'dom', method: 'createBody',
+      args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
+    }], '-1'])
+    done()
+  })
+
+  it('document insertBefore with comment', (done) => {
+    const body = doc.createBody('r', {
+      attr: { a: 1 }, style: { b: 2 }
+    })
+    const el = doc.createComment('asd')
+
+    doc.documentElement.appendChild(el)
+    doc.documentElement.insertBefore(body, el)
+
+    expect(doc.documentElement.children.length).eql(2)
+    expect(doc.documentElement.children[0]).eql(body)
+    done()
+  })
+
+  it('document fireEvent with no element', (done) => {
+    doc.fireEvent(null)
+    done()
+  })
+
+  it('document fireEvent with domChanges', (done) => {
+    const el = doc.createElement('el', {
+      attr: { a: 1 }, style: { b: 2 }
+    })
+
+    doc.documentElement.appendChild(el)
+
+    doc.fireEvent(el, null, null, {})
+
+    expect(el.attr).eql({ a: 1 })
+    expect(el.style).eql({ b: 2 })
+
+    doc.fireEvent(el, null, null, {
+      attrs: { a: 1 }, style: { b: 2 }
+    })
+
+    expect(el.attr).eql({ a: 1 })
+    expect(el.style).eql({ b: 2 })
+
+    doc.fireEvent(el, null, null, {
+      attrs: { a: 2 }, style: { b: 3 }
+    })
+
+    expect(el.attr).eql({ a: 2 })
+    expect(el.style).eql({ b: 3 })
+    done()
+  })
+
+  it('toString has pureChildren', (done) => {
+    const el = doc.createElement('el')
+    const el1 = doc.createElement('el1')
+    el.appendChild(el1)
+    expect(el.toString()).eql('<el attr={} style={}><el1 attr={} style={}></el1></el>')
+
+    done()
+  })
+
+  it('removeChild', (done) => {
+    const el = doc.createElement('el')
+    const el1 = doc.createElement('el1')
+
+    el.removeChild(el1)
+    el.removeChild(el1, true)
+
+    done()
+  })
+
+  it('removeEvent', (done) => {
+    const el = doc.createElement('el')
+    el.removeEvent(null)
+    done()
+  })
+
+  it('add element', (done) => {
+    const body = doc.createBody('r')
+
+    doc.documentElement.appendChild(body)
+
+    expect(spy.args[0]).eql([[{
+      module: 'dom', method: 'createBody',
+      args: [body.toJSON()]
+    }], '-1'])
+
+    const el = doc.createElement('a')
+    el.setAttr('x', 1)
+    el.addEvent('click', () => {})
+    doc.body.appendChild(el)
+
+    expect(spy.args[1]).eql([[{
+      module: 'dom', method: 'addElement',
+      args: ['_root', el.toJSON(), -1]
+    }], '-1'])
+
+    const el2 = doc.createElement('b')
+    doc.body.insertBefore(el2, el) // [el2, el]
+
+    const el3 = doc.createElement('c')
+    doc.body.insertAfter(el3, el) // [el2, el, el3]
+
+    expect(spy.args.length).eql(4)
+    expect(spy.args[2]).eql([[{
+      module: 'dom', method: 'addElement',
+      args: ['_root', el2.toJSON(), 0]
+    }], '-1'])
+    expect(spy.args[3]).eql([[{
+      module: 'dom', method: 'addElement',
+      args: ['_root', el3.toJSON(), 2]
+    }], '-1'])
+
+    done()
+  })
+
+  it('bind listener for element props', () => {
+    const el = doc.createElement('bar')
+    doc.createBody('r')
+    doc.documentElement.appendChild(doc.body)
+
+    expect(spy.args.length).eql(1)
+    expect(spy.args[0][0]).eql([{
+      module: 'dom', method: 'createBody',
+      args: [doc.body.toJSON()]
+    }])
+
+    el.setAttr('a', 1)
+    el.setStyle('a', 2)
+    el.setClassStyle({ a: 3, b: 4 })
+    el.addEvent('click', () => {})
+    el.addEvent('appear', () => {})
+    el.removeEvent('appear')
+    doc.body.appendChild(el)
+
+    expect(spy.args.length).eql(2)
+    expect(spy.args[1][0]).eql([{
+      module: 'dom', method: 'addElement',
+      args: ['_root', el.toJSON(), -1]
+    }])
+
+    el.setAttr('a', 11, true)
+    expect(spy.args.length).eql(2)
+    el.setAttr('a', 12)
+    expect(spy.args.length).eql(3)
+    expect(spy.args[2][0]).eql([{
+      module: 'dom', method: 'updateAttrs',
+      args: [el.ref, { a: 12 }]
+    }])
+    el.setAttr('a', 12, false)
+    expect(spy.args.length).eql(4)
+    expect(spy.args[3][0]).eql([{
+      module: 'dom', method: 'updateAttrs',
+      args: [el.ref, { a: 12 }]
+    }])
+
+    el.setStyle('a', 13, true)
+    expect(spy.args.length).eql(4)
+    el.setStyle('a', 14)
+    expect(spy.args.length).eql(5)
+    expect(spy.args[4][0]).eql([{
+      module: 'dom', method: 'updateStyle',
+      args: [el.ref, { a: 14 }]
+    }])
+    el.setStyle('a', 14, false)
+    expect(spy.args.length).eql(6)
+    expect(spy.args[5][0]).eql([{
+      module: 'dom', method: 'updateStyle',
+      args: [el.ref, { a: 14 }]
+    }])
+
+    el.setClassStyle({ a: 13, b: 14 })
+    expect(spy.args[6][0]).eql([{
+      module: 'dom', method: 'updateStyle',
+      args: [el.ref, { a: 14, b: 14 }]
+    }])
+    expect(spy.args.length).eql(7)
+    el.addEvent('click', () => {})
+    expect(spy.args.length).eql(7)
+    el.addEvent('appear', () => {})
+    expect(spy.args.length).eql(8)
+    expect(spy.args[7][0]).eql([{
+      module: 'dom', method: 'addEvent',
+      args: [el.ref, 'appear']
+    }])
+
+    el.removeEvent('click')
+    expect(spy.args.length).eql(9)
+    expect(spy.args[8][0]).eql([{
+      module: 'dom', method: 'removeEvent',
+      args: [el.ref, 'click']
+    }])
+    el.removeEvent('appear')
+    expect(spy.args.length).eql(10)
+    expect(spy.args[9][0]).eql([{
+      module: 'dom', method: 'removeEvent',
+      args: [el.ref, 'appear']
+    }])
+
+    el.setAttr('a', 1)
+    el.setStyle('a', 2)
+    el.setClassStyle({ a: 3, b: 4 })
+    el.addEvent('click', () => {})
+    el.addEvent('appear', () => {})
+    el.removeEvent('appear')
+    expect(spy.args.length).eql(16)
+    expect(spy.args.slice(10).map(c => c[0][0])).eql([
+      { module: 'dom', method: 'updateAttrs', args: [el.ref, { a: 1 }] },
+      { module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2 }] },
+      { module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2, b: 4 }] },
+      { module: 'dom', method: 'addEvent', args: [el.ref, 'click'] },
+      { module: 'dom', method: 'addEvent', args: [el.ref, 'appear'] },
+      { module: 'dom', method: 'removeEvent', args: [el.ref, 'appear'] }
+    ])
+  })
+})
+
+describe('listener', () => {
+  let spy, listener
+
+  beforeEach(() => {
+    spy = sinon.spy()
+    listener = new Listener('1', spy)
+  })
+
+  it('removeElement many', () => {
+    listener.removeElement(['1', '2', '3', '4'])
+
+    expect(spy.args[0][0]).eql([
+      { module: 'dom', method: 'removeElement', args: ['1'] },
+      { module: 'dom', method: 'removeElement', args: ['2'] },
+      { module: 'dom', method: 'removeElement', args: ['3'] },
+      { module: 'dom', method: 'removeElement', args: ['4'] }
+    ])
+
+    listener = null
+  })
+
+  it('no-handler', () => {
+    listener = new Listener('1')
+    listener.handler(
+      { module: 'dom', method: 'removeElement', args: ['1'] },
+      spy
+    )
+    expect(spy).callCount(1)
+  })
+
+  afterEach(() => {
+    spy = null
+    listener = null
+  })
+})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/runtime/vdom/node.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/vdom/node.js b/html5/test/unit/runtime/vdom/node.js
new file mode 100644
index 0000000..b05d277
--- /dev/null
+++ b/html5/test/unit/runtime/vdom/node.js
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import chai from 'chai'
+const { expect } = chai
+
+import {
+  Node
+} from '../../../../runtime/vdom'
+
+describe('Node', () => {
+  it('create node', () => {
+    const node = new Node()
+    expect(node).is.an.object
+    expect(node.nodeId).to.be.a('string')
+    expect(node.ref).eql(node.nodeId)
+    expect(node.children).eql([])
+    expect(node.pureChildren).eql([])
+    expect(node.parentNode).to.be.null
+    expect(node.nextSibling).to.be.null
+    expect(node.previousSibling).to.be.null
+    node.destroy()
+  })
+})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/shared/BroadcastChannel.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/BroadcastChannel.js b/html5/test/unit/shared/BroadcastChannel.js
index bacaf75..880ed6b 100644
--- a/html5/test/unit/shared/BroadcastChannel.js
+++ b/html5/test/unit/shared/BroadcastChannel.js
@@ -42,13 +42,6 @@ describe('BroadcastChannel', () => {
     JamesBond.close()
   })
 
-  it.skip('inherit APIs', () => {
-    const ProfessorX = new BroadcastChannel('Charles')
-    expect(ProfessorX.addEventListener).is.an('function')
-    expect(ProfessorX.removeEventListener).is.an('function')
-    expect(ProfessorX.dispatchEvent).is.an('function')
-  })
-
   it('name attribute is readonly', () => {
     const Wolverine = new BroadcastChannel('Logan')
     expect(Wolverine.name).to.equal('Logan')

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/shared/arrayFrom.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/arrayFrom.js b/html5/test/unit/shared/arrayFrom.js
index cc7229f..99e9495 100644
--- a/html5/test/unit/shared/arrayFrom.js
+++ b/html5/test/unit/shared/arrayFrom.js
@@ -64,11 +64,6 @@ describe('Array.from', () => {
     expect(Array.from('x\uD834\uDF06Y')).to.deep.equal(['x', '\uD834\uDF06', 'Y'])
 	})
 
-  it.skip('works with emoji', () => {
-    expect(Array.from('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ')).to.deep.equal(['๐Ÿ‘จ', 'โ€', '๐Ÿ‘ฉ', 'โ€', '๐Ÿ‘ง', 'โ€', '๐Ÿ‘ฆ'])
-    expect(Array.from('๐ŸŽ…๐Ÿพ')).to.deep.equal(['๐ŸŽ…', '๐Ÿพ'])
-	})
-
   it('works with objects', () => {
     expect(Array.from({})).to.deep.equal([])
     expect(Array.from({ name: 'abc' })).to.deep.equal([])

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/shared/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/index.js b/html5/test/unit/shared/index.js
index 6ac3458..337bdf1 100644
--- a/html5/test/unit/shared/index.js
+++ b/html5/test/unit/shared/index.js
@@ -25,19 +25,15 @@ chai.use(sinonChai)
 import * as shared from '../../../shared'
 
 describe('a polyfill of', () => {
-  it.skip('Promise', () => {
-    sinon.spy(global, 'Promise')
-    sinon.stub(console, 'warn')
+  it('Promise', () => {
     expect(typeof Promise).to.be.equal('function')
-    new Promise(sinon.spy()).then(sinon.spy())
-    Promise.all()
-    Promise.race()
-    Promise.resolve()
-    Promise.reject()
-    expect(global.Promise.callCount).to.be.equal(1)
-    expect(console.warn.callCount).to.be.equal(5)
-    console.warn.restore()
-    global.Promise.restore()
+    expect(() => {
+      new Promise(sinon.spy()).then(sinon.spy())
+      Promise.all()
+      Promise.race()
+      Promise.resolve()
+      Promise.reject()
+    }).to.not.throw
   })
 
   it('Object.assign', () => {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/vdom/directive.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/directive.js b/html5/test/unit/vdom/directive.js
deleted file mode 100644
index cbe9ab1..0000000
--- a/html5/test/unit/vdom/directive.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import { expect } from 'chai'
-import { filterDirective } from '../../../runtime/vdom/directive'
-
-describe('filterDirective', () => {
-  it('other type', () => {
-    expect(filterDirective(0)).to.be.equal(0)
-    expect(filterDirective(53)).to.be.equal(53)
-    expect(filterDirective(null)).to.be.equal(null)
-    const reg = /\w+/i
-    expect(filterDirective(reg)).to.be.equal(reg)
-  })
-
-  it('normal string', () => {
-    expect(filterDirective('')).to.be.equal('')
-    expect(filterDirective('-1')).to.be.equal('-1')
-    expect(filterDirective('abc')).to.be.equal('abc')
-    expect(filterDirective(' a bc d')).to.be.equal(' a bc d')
-    expect(filterDirective(' a {{ bc }}')).to.be.equal(' a {{ bc }}')
-  })
-
-  it('binding', () => {
-    expect(filterDirective('[[abc]]')).to.deep.equal({ '@binding': 'abc' })
-    expect(filterDirective('[[ xyz ]]')).to.deep.equal({ '@binding': 'xyz' })
-    expect(filterDirective('[[ x y z ]]')).to.deep.equal({ '@binding': 'x y z' })
-  })
-
-  it('binding and normal string', () => {
-    expect(filterDirective('xyz[[abc]]ttt')).to.deep.equal(['xyz', { '@binding': 'abc' }, 'ttt'])
-    expect(filterDirective(' x [[ w ]] t ')).to.deep.equal([' x ', { '@binding': 'w' }, ' t '])
-    expect(filterDirective('[[ wn]][xx{uur}]')).to.deep.equal([{ '@binding': 'wn' }, '[xx{uur}]'])
-  })
-
-  it('multi-binding', () => {
-    expect(filterDirective('[[abc]][[wpc]]')).to.deep.equal([{ '@binding': 'abc' }, { '@binding': 'wpc' }])
-    expect(filterDirective('abcd[[ xyz ]]ef[[w]]gh')).to.deep.equal([
-      'abcd',
-      { '@binding': 'xyz' },
-      'ef',
-      { '@binding': 'w' },
-      'gh'
-    ])
-    expect(filterDirective(' a [[ b ]] [[c]] d [[e]][[f]]g')).to.deep.equal([
-      ' a ',
-      { '@binding': 'b' },
-      ' ',
-      { '@binding': 'c' },
-      ' d ',
-      { '@binding': 'e' },
-      { '@binding': 'f' },
-      'g'
-    ])
-  })
-
-  it('parse object', () => {
-    expect(filterDirective({ key: '[[x]]' })).to.deep.equal({ key: { '@binding': 'x' }})
-    expect(filterDirective({ a: '[[A]]', b: '[[B]]' })).to.deep.equal({
-      a: { '@binding': 'A' },
-      b: { '@binding': 'B' }
-    })
-    expect(filterDirective({
-      a: '[[A]]',
-      x: 'X',
-      y: {
-        b: ' - [[B]] - ',
-        z: {
-          c: ['[[C]] + [[C]]', 'cc'],
-          w: 24
-        }
-      }
-    })).to.deep.equal({
-      a: { '@binding': 'A' },
-      x: 'X',
-      y: {
-        b: [' - ', { '@binding': 'B' }, ' - '],
-        z: {
-          c: [[{ '@binding': 'C' }, ' + ', { '@binding': 'C' }], 'cc'],
-          w: 24
-        }
-      }
-    })
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/vdom/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/index.js b/html5/test/unit/vdom/index.js
deleted file mode 100644
index 01a55c6..0000000
--- a/html5/test/unit/vdom/index.js
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import chai from 'chai'
-import sinon from 'sinon'
-import sinonChai from 'sinon-chai'
-const { expect } = chai
-chai.use(sinonChai)
-
-import {
-  Document,
-  Element,
-  Comment,
-  isWeexElement,
-  registerElement,
-  clearWeexElements
-} from '../../../runtime/vdom'
-
-describe('document constructor', () => {
-  it('create & destroy document', () => {
-    const doc = new Document('foo', 'http://path/to/url')
-    expect(doc).is.an.object
-    expect(doc.id).eql('foo')
-    expect(doc.URL).eql('http://path/to/url')
-    expect(doc.documentElement).is.an.object
-    expect(doc.documentElement.role).equal('documentElement')
-    doc.destroy()
-  })
-})
-
-describe('component methods management', () => {
-  before(() => {
-    registerElement('x', ['foo', 'bar'])
-    registerElement('y', [])
-    registerElement('z')
-  })
-
-  after(() => {
-    clearWeexElements()
-  })
-
-  it('has registered element types', () => {
-    expect(isWeexElement('x')).to.be.true
-  })
-
-  it('will call component method', () => {
-    const spy = sinon.spy()
-    const doc = new Document('test', '', spy)
-    const x = new Element('x')
-    const y = new Element('y')
-    const z = new Element('z')
-    const n = new Element('n')
-    expect(x.foo).is.function
-    expect(x.bar).is.function
-    expect(x.baz).is.undefined
-    expect(y.foo).is.undefined
-    expect(z.foo).is.undefined
-    expect(n.foo).is.undefined
-
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(x)
-    doc.body.appendChild(y)
-    doc.body.appendChild(z)
-    doc.body.appendChild(n)
-    expect(spy.args.length).eql(5)
-
-    x.foo(1, 2, 3)
-    expect(spy.args.length).eql(6)
-    expect(spy.args[5]).eql([[{ component: 'x', method: 'foo', ref: x.ref, args: [1, 2, 3] }]])
-  })
-})
-
-describe('document methods', () => {
-  let doc
-
-  beforeEach(() => {
-    doc = new Document('foo', null, function () {})
-  })
-
-  afterEach(() => {
-    doc.destroy()
-  })
-
-  it('open & close with a listener', () => {
-    expect(doc.listener.batched).is.false
-    doc.close()
-    expect(doc.listener.batched).is.true
-    doc.open()
-    expect(doc.listener.batched).is.false
-  })
-
-  it('create body', () => {
-    const ele = doc.createBody('container',
-      { attr: { id: 'a' }, style: { fontSize: 16 }})
-    expect(ele.role).equal('body')
-    expect(ele.attr).to.have.a.property('id', 'a')
-    expect(ele.style).to.have.a.property('fontSize', 16)
-    expect(ele).have.a.property('ref')
-    expect(ele).have.a.property('children')
-    expect(ele).have.a.property('pureChildren')
-    expect(ele).have.a.property('insertBefore')
-    expect(ele).have.a.property('setStyle')
-
-    const ref = ele.ref
-    expect(doc.nodeMap[ref]).equal(ele)
-  })
-
-  it('create element', () => {
-    const ele = doc.createElement('container',
-      { attr: { id: 'a' }, style: { fontSize: 16 }})
-    expect(ele.attr).to.have.a.property('id', 'a')
-    expect(ele.style).to.have.a.property('fontSize', 16)
-    expect(ele).have.a.property('ref')
-    expect(ele).have.a.property('children')
-    expect(ele).have.a.property('pureChildren')
-    expect(ele).have.a.property('insertBefore')
-    expect(ele).have.a.property('setStyle')
-
-    expect(doc.nodeMap[ele.ref]).is.undefined
-    doc.documentElement.appendChild(ele)
-    expect(doc.nodeMap[ele.ref]).equal(ele)
-  })
-
-  it('create comment', () => {
-    const comment = doc.createComment('start')
-    expect(comment).have.a.property('ref')
-    expect(comment).not.have.a.property('appendChild')
-    expect(comment).have.a.property('value', 'start')
-    expect(comment.toString()).eql('<!-- start -->')
-
-    const ref = comment.ref
-    expect(doc.nodeMap[ref]).is.undefined
-    doc.documentElement.appendChild(comment)
-    expect(doc.nodeMap[ref]).equal(comment)
-  })
-})
-
-describe('Element in document methods', () => {
-  let doc, el, el2, el3
-
-  beforeEach(() => {
-    doc = new Document('foo', null, function () {})
-    el = new Element('bar', {
-      attr: { a: 11, b: 12 },
-      style: { c: 13, d: 14 },
-      classStyle: { a: 211, c: 213 }
-    })
-    el2 = new Element('baz', {
-      attr: { a: 21, b: 22 },
-      style: { c: 23, d: 24 },
-      classStyle: { a: 221, c: 223 }
-    })
-    el3 = new Element('qux', {
-      attr: { a: 31, b: 32 },
-      style: { c: 33, d: 34 },
-      classStyle: { a: 231, c: 233 }
-    })
-  })
-
-  afterEach(() => {
-    doc.destroy()
-  })
-
-  it('init correctly', () => {
-    expect(el).is.an.object
-    expect(el.type).eql('bar')
-    expect(el.attr).eql({ a: 11, b: 12 })
-    expect(el.style).eql({ c: 13, d: 14 })
-    expect(el.event).eql({})
-    expect(el.children).eql([])
-    expect(el.pureChildren).eql([])
-    expect(doc.nodeMap).is.an.object
-    expect(doc.documentElement).is.an.object
-    expect(Object.keys(doc.nodeMap)).eql([doc.documentElement.ref])
-    doc.documentElement.appendChild(el)
-    doc.documentElement.appendChild(el2)
-    el2.appendChild(el3)
-    expect(Object.keys(doc.nodeMap)).eql([
-      doc.documentElement.ref,
-      el.ref
-    ])
-  })
-
-  it('has correct exports', () => {
-    const ref = el.ref
-    const finalStyle = el.toStyle()
-    expect(finalStyle).eql({ a: 211, c: 13, d: 14 })
-    expect(el.toJSON()).eql({
-      ref: ref, type: 'bar',
-      attr: el.attr, style: finalStyle
-    })
-    expect(el.toString()).eql(
-      '<bar attr={"a":11,"b":12} style={"a":211,"c":13,"d":14}></bar>')
-  })
-
-  it('createBody', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    expect(doc.body).is.an.object
-    expect(doc.body.role).eql('body')
-    expect(doc.body.type).eql('r')
-    expect(doc.body.docId).eql('foo')
-  })
-
-  it('appendChild', () => {
-    el.appendChild(el2)
-    expect(el.children.length).eql(1)
-    expect(el.children[0]).equal(el2)
-    expect(el2.parentNode.ref).eql(el.ref)
-
-    expect(el.docId).is.not.ok
-    expect(el2.docId).is.not.ok
-
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-    expect(doc.body.children.length).eql(1)
-    expect(el.parentNode.ref).eql(doc.body.ref)
-    expect(el.docId).is.ok
-    expect(el2.docId).is.ok
-
-    expect(el3.docId).is.not.ok
-    el.appendChild(el3)
-    expect(el.children.length).eql(2)
-    expect(el.children[0]).equal(el2)
-    expect(el.children[1]).equal(el3)
-    expect(el3.parentNode.ref).eql(el.ref)
-    expect(el3.docId).is.ok
-
-    expect(el2.previousSibling).is.not.ok
-    expect(el2.nextSibling).eql(el3)
-    expect(el3.previousSibling).eql(el2)
-    expect(el3.nextSibling).is.not.ok
-  })
-
-  it('insertBefore', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-    expect(el.parentNode.ref).eql(doc.body.ref)
-
-    el.appendChild(el2)
-    expect(el2.parentNode.ref).eql(el.ref)
-    expect(el.children.length).eql(1)
-    expect(el.children[0]).equal(el2)
-
-    el.insertBefore(el3, el2)
-    expect(el.children.length).eql(2)
-    expect(el.children[0]).equal(el3)
-    expect(el.children[1]).equal(el2)
-    expect(el3.parentNode.ref).eql(el.ref)
-
-    expect(el.docId).eql('foo')
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-
-    expect(el3.previousSibling).is.not.ok
-    expect(el3.nextSibling).eql(el2)
-    expect(el2.previousSibling).eql(el3)
-    expect(el2.nextSibling).is.not.ok
-
-    el.insertBefore(el2, el3)
-    expect(el.children.length).eql(2)
-    expect(el.children[0]).equal(el2)
-    expect(el.children[1]).equal(el3)
-
-    expect(el.docId).eql('foo')
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-
-    expect(el2.previousSibling).is.not.ok
-    expect(el2.nextSibling).eql(el3)
-    expect(el3.previousSibling).eql(el2)
-    expect(el3.nextSibling).is.not.ok
-  })
-
-  it('insertAfter', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-    expect(el.parentNode.ref).eql(doc.body.ref)
-
-    el.appendChild(el2)
-    el.insertAfter(el3, el2)
-    expect(el.children.length).eql(2)
-    expect(el.children[0]).equal(el2)
-    expect(el.children[1]).equal(el3)
-    expect(el2.parentNode.ref).eql(el.ref)
-    expect(el3.parentNode.ref).eql(el.ref)
-
-    expect(el.docId).eql('foo')
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-
-    expect(el2.previousSibling).is.not.ok
-    expect(el2.nextSibling).eql(el3)
-    expect(el3.previousSibling).eql(el2)
-    expect(el3.nextSibling).is.not.ok
-
-    el.insertAfter(el2, el3, true)
-    expect(el.children.length).eql(2)
-    expect(el.children[0]).equal(el3)
-    expect(el.children[1]).equal(el2)
-
-    expect(el3.previousSibling).is.not.ok
-    expect(el3.nextSibling).eql(el2)
-    expect(el2.previousSibling).eql(el3)
-    expect(el2.nextSibling).is.not.ok
-  })
-
-  it('removeChild', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    el2.appendChild(el3)
-
-    expect(el.docId).eql('foo')
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-    doc.body.removeChild(el)
-    expect(doc.body.children.length).equal(1)
-    expect(doc.body.children[0]).equal(el2)
-    expect(el.docId).is.not.ok
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-    doc.body.removeChild(el2)
-    expect(doc.body.children.length).equal(0)
-    expect(el.docId).is.not.ok
-    expect(el2.docId).is.not.ok
-    expect(el3.docId).is.not.ok
-  })
-
-  it('clear', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    doc.body.appendChild(el3)
-
-    expect(el.docId).eql('foo')
-    expect(el2.docId).eql('foo')
-    expect(el3.docId).eql('foo')
-
-    doc.body.clear()
-    expect(doc.body.children.length).equal(0)
-    expect(el.docId).is.not.ok
-    expect(el2.docId).is.not.ok
-    expect(el3.docId).is.not.ok
-  })
-
-  it('modify attr, style, event', () => {
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.body.appendChild(el)
-
-    el.setAttr('a', 21)
-    expect(el.toJSON().attr).eql({ a: 21, b: 12 })
-    el.setAttr('a', 22, true)
-    expect(el.toJSON().attr).eql({ a: 22, b: 12 })
-    el.setAttr('a', 23, false)
-    expect(el.toJSON().attr).eql({ a: 23, b: 12 })
-
-    el.setStyle('c', 21)
-    expect(el.toJSON().style).eql({ a: 211, c: 21, d: 14 })
-    el.setStyle('c', 22, true)
-    expect(el.toJSON().style).eql({ a: 211, c: 22, d: 14 })
-    el.setStyle('c', 23, false)
-    expect(el.toJSON().style).eql({ a: 211, c: 23, d: 14 })
-
-    el.setClassStyle({ a: 311, c: 313 })
-    expect(el.toJSON().style).eql({ a: 311, c: 23, d: 14 })
-
-    const handler = function () {}
-    el.addEvent('click', handler)
-    expect(el.toJSON().event).eql(['click'])
-    expect(el.event.click).equal(handler)
-    el.removeEvent('click')
-    expect(el.event.click).is.undefined
-  })
-})
-
-describe('Node', () => {
-  let doc, el, el2, el3, c, c2, c3, spy
-
-  beforeEach(() => {
-    spy = sinon.spy()
-    doc = new Document('foo', '', spy)
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    el = new Element('bar')
-    el2 = new Element('baz')
-    el3 = new Element('qux')
-    c = new Comment('aaa')
-    c2 = new Comment('bbb')
-    c3 = new Comment('ccc')
-  })
-
-  afterEach(() => {
-    doc.destroy()
-  })
-
-  it('prev and next', () => {
-    expect(el.previousSibling).is.not.ok
-    expect(el.nextSibling).is.not.ok
-
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    doc.body.appendChild(c)
-    doc.body.appendChild(el3)
-    doc.body.appendChild(c2)
-    doc.body.appendChild(c3)
-
-    expect(el.previousSibling).is.not.ok
-    expect(el2.previousSibling).equal(el)
-    expect(c.previousSibling).equal(el2)
-    expect(el3.previousSibling).equal(c)
-    expect(c2.previousSibling).equal(el3)
-    expect(c3.previousSibling).equal(c2)
-
-    expect(el.nextSibling).equal(el2)
-    expect(el2.nextSibling).equal(c)
-    expect(c.nextSibling).equal(el3)
-    expect(el3.nextSibling).equal(c2)
-    expect(c2.nextSibling).equal(c3)
-    expect(c3.nextSibling).is.not.ok
-  })
-
-  it('tree operations with renderer', () => {
-    doc.body.appendChild(el)
-    el.appendChild(el2)
-    el.appendChild(el3)
-
-    expect(spy.args.length).eql(4)
-    el.insertBefore(el3, el2) // [el3, el2]
-    expect(spy.args.length).eql(5)
-    expect(spy.args[4][0]).eql([{
-      module: 'dom', method: 'moveElement',
-      args: [el3.ref, el.ref, 0]
-    }])
-    el.insertAfter(el3, el2) // [el2, el3]
-    expect(spy.args.length).eql(6)
-    expect(spy.args[5][0]).eql([{
-      module: 'dom', method: 'moveElement',
-      args: [el3.ref, el.ref, 2]
-    }])
-    el.removeChild(el2) // [el3]
-    expect(spy.args.length).eql(7)
-    expect(spy.args[6][0]).eql([{
-      module: 'dom', method: 'removeElement',
-      args: [el2.ref]
-    }])
-    el.clear() // []
-    expect(spy.args.length).eql(8)
-    expect(spy.args[7][0]).eql([{
-      module: 'dom', method: 'removeElement',
-      args: [el3.ref]
-    }])
-  })
-})
-
-describe('complicated situations', () => {
-  let doc, el, el2, el3, c, c2, c3, spy
-
-  beforeEach(() => {
-    spy = sinon.spy()
-    doc = new Document('foo', '', spy)
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    el = new Element('bar')
-    el2 = new Element('baz')
-    el3 = new Element('qux')
-    c = new Comment('aaa')
-    c2 = new Comment('bbb')
-    c3 = new Comment('ccc')
-  })
-
-  afterEach(() => {
-    doc.destroy()
-  })
-
-  it('move a node to its original position', () => {
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    doc.body.appendChild(el3)
-
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertAfter(el2, el)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertAfter(el3, el2, true)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertBefore(el, el2)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertBefore(el2, el3, true)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertAfter(c, el)
-    doc.body.insertAfter(c2, el2)
-    doc.body.insertAfter(c3, el3)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, c, el2, c2, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertBefore(el, c)
-    doc.body.insertBefore(el, c, true)
-    doc.body.insertBefore(c, el2)
-    doc.body.insertBefore(c, el2, true)
-    doc.body.insertAfter(c, el)
-    doc.body.insertAfter(c, el, true)
-    doc.body.insertAfter(el2, c)
-    doc.body.insertAfter(el2, c, true)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, c, el2, c2, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    // move to another place that not change the pureChildren
-    doc.body.insertBefore(el, el2)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([c, el, el2, c2, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertBefore(el, c)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, c, el2, c2, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertAfter(c, el2)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, c, c2, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-
-    doc.body.insertBefore(c2, c)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, c2, c, el3, c3])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-  })
-
-  it.skip('move a node from another parent', () => {
-    doc.body.appendChild(el)
-    el.appendChild(el2)
-    el.appendChild(el3)
-    expect(doc.body.children).eql([el])
-    expect(el.children).eql([el2, el3])
-
-    doc.body.insertBefore(el2, el)
-    expect(doc.body.children).eql([el2, el])
-    expect(doc.body.pureChildren).eql([el2, el])
-    expect(el.children).eql([el3])
-    expect(el.pureChildren).eql([el3])
-
-    doc.body.insertAfter(el3, el)
-    expect(doc.body.children).eql([el2, el, el3])
-    expect(doc.body.pureChildren).eql([el2, el, el3])
-    expect(el.children).eql([])
-    expect(el.pureChildren).eql([])
-  })
-
-  it('insert before a comment', () => {
-    doc.body.appendChild(el)
-    doc.body.appendChild(c)
-    doc.body.appendChild(c2)
-    doc.body.appendChild(el2)
-    expect(spy.args.length).eql(3)
-    expect(doc.body.children).eql([el, c, c2, el2])
-    expect(doc.body.pureChildren).eql([el, el2])
-
-    doc.body.insertBefore(el3, c)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el3, c, c2, el2])
-    expect(doc.body.pureChildren).eql([el, el3, el2])
-    expect(spy.args[3][0]).eql([{
-      module: 'dom', method: 'addElement',
-      args: [doc.body.ref, el3.toJSON(), 1] }])
-  })
-
-  it('insert before a comment which has no more element after', () => {
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    doc.body.appendChild(c)
-    doc.body.appendChild(c2)
-    expect(spy.args.length).eql(3)
-    expect(doc.body.children).eql([el, el2, c, c2])
-    expect(doc.body.pureChildren).eql([el, el2])
-
-    doc.body.insertBefore(el3, c)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, el2, el3, c, c2])
-    expect(doc.body.pureChildren).eql([el, el2, el3])
-    expect(spy.args[3][0]).eql([{
-      module: 'dom', method: 'addElement',
-      args: [doc.body.ref, el3.toJSON(), 2] }])
-  })
-
-  it('insert after a comment', () => {
-    doc.body.appendChild(el)
-    doc.body.appendChild(c)
-    doc.body.appendChild(c2)
-    doc.body.appendChild(el2)
-    expect(spy.args.length).eql(3)
-    expect(doc.body.children).eql([el, c, c2, el2])
-    expect(doc.body.pureChildren).eql([el, el2])
-
-    doc.body.insertAfter(el3, c2)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([el, c, c2, el3, el2])
-    expect(doc.body.pureChildren).eql([el, el3, el2])
-    expect(spy.args[3][0]).eql([{
-      module: 'dom', method: 'addElement',
-      args: [doc.body.ref, el3.toJSON(), 1] }])
-  })
-
-  it('insert after a comment which has no more element before', () => {
-    doc.body.appendChild(c)
-    doc.body.appendChild(c2)
-    doc.body.appendChild(el)
-    doc.body.appendChild(el2)
-    expect(spy.args.length).eql(3)
-    expect(doc.body.children).eql([c, c2, el, el2])
-    expect(doc.body.pureChildren).eql([el, el2])
-
-    doc.body.insertAfter(el3, c2)
-    expect(spy.args.length).eql(4)
-    expect(doc.body.children).eql([c, c2, el3, el, el2])
-    expect(doc.body.pureChildren).eql([el3, el, el2])
-    expect(spy.args[3][0]).eql([{
-      module: 'dom', method: 'addElement',
-      args: [doc.body.ref, el3.toJSON(), 0] }])
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/vdom/listener.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/listener.js b/html5/test/unit/vdom/listener.js
deleted file mode 100644
index d6c5e71..0000000
--- a/html5/test/unit/vdom/listener.js
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import chai from 'chai'
-import sinon from 'sinon'
-import sinonChai from 'sinon-chai'
-const { expect } = chai
-chai.use(sinonChai)
-
-import { Document } from '../../../runtime/vdom'
-import Listener from '../../../runtime/bridge/Listener'
-
-describe('dom listener basic', () => {
-  it('works with no id', () => {
-    const doc = new Document(null, null, null)
-    doc.destroy()
-  })
-
-  it('works with no handler', () => {
-    const oriCallNative = global.callNative
-    const oriCallAddElement = global.callAddElement
-    const oriDocumentHandler = Document.handler
-
-    Document.handler = null
-    global.callNative = function () { return -1 }
-    global.callAddElement = function () { return -1 }
-
-    const doc = new Document('foo1', null, null)
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    const el = doc.createElement('a')
-    doc.body.appendChild(el)
-    doc.destroy()
-
-    global.callNative = oriCallNative
-    global.callAddElement = oriCallAddElement
-    Document.handler = oriDocumentHandler
-  })
-
-  it('works with an handler', () => {
-    const doc = new Document('foo2', null, function () {})
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.destroy()
-  })
-
-  it('works with an handler', () => {
-    const doc = new Document('foo2', null, function () {})
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-    doc.destroy()
-  })
-})
-
-describe('dom listener details', () => {
-  let doc, spy
-
-  beforeEach(() => {
-    spy = sinon.spy()
-    doc = new Document('foo', '', spy, Listener)
-  })
-
-  afterEach(() => {
-    doc.destroy()
-  })
-
-  it('create document again', (done) => {
-    const documentElement = doc.createDocumentElement()
-
-    expect(documentElement).eql(doc.documentElement)
-    done()
-  })
-
-  it('create body', (done) => {
-    const body = doc.createBody('r', {
-      attr: { a: 1 }, style: { b: 2 }
-    })
-
-    doc.documentElement.appendChild(body)
-
-    expect(spy.args.length).eql(1)
-    expect(spy.args[0]).eql([[{
-      module: 'dom', method: 'createBody',
-      args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
-    }], '-1'])
-    done()
-  })
-
-  it('document appendChild', (done) => {
-    const el = doc.createElement('father')
-    const el2 = doc.createElement('child1')
-    const el3 = doc.createElement('child2')
-
-    el.appendChild(el2)
-    el.appendChild(el3)
-
-    doc.documentElement.appendChild(el)
-
-    expect(doc.documentElement.children.length).eql(1)
-    expect(doc.documentElement.children[0]).eql(el)
-
-    done()
-  })
-
-  it('document insertBefore', (done) => {
-    const body = doc.createBody('r', {
-      attr: { a: 1 }, style: { b: 2 }
-    })
-
-    doc.documentElement.insertBefore(body)
-
-    expect(spy.args.length).eql(1)
-    expect(spy.args[0]).eql([[{
-      module: 'dom', method: 'createBody',
-      args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
-    }], '-1'])
-    done()
-  })
-
-  it('document insertBefore with comment', (done) => {
-    const body = doc.createBody('r', {
-      attr: { a: 1 }, style: { b: 2 }
-    })
-    const el = doc.createComment('asd')
-
-    doc.documentElement.appendChild(el)
-    doc.documentElement.insertBefore(body, el)
-
-    expect(doc.documentElement.children.length).eql(2)
-    expect(doc.documentElement.children[0]).eql(body)
-    done()
-  })
-
-  it('document fireEvent with no element', (done) => {
-    doc.fireEvent(null)
-    done()
-  })
-
-  it('document fireEvent with domChanges', (done) => {
-    const el = doc.createElement('el', {
-      attr: { a: 1 }, style: { b: 2 }
-    })
-
-    doc.documentElement.appendChild(el)
-
-    doc.fireEvent(el, null, null, {})
-
-    expect(el.attr).eql({ a: 1 })
-    expect(el.style).eql({ b: 2 })
-
-    doc.fireEvent(el, null, null, {
-      attrs: { a: 1 }, style: { b: 2 }
-    })
-
-    expect(el.attr).eql({ a: 1 })
-    expect(el.style).eql({ b: 2 })
-
-    doc.fireEvent(el, null, null, {
-      attrs: { a: 2 }, style: { b: 3 }
-    })
-
-    expect(el.attr).eql({ a: 2 })
-    expect(el.style).eql({ b: 3 })
-    done()
-  })
-
-  it('toString has pureChildren', (done) => {
-    const el = doc.createElement('el')
-    const el1 = doc.createElement('el1')
-    el.appendChild(el1)
-    expect(el.toString()).eql('<el attr={} style={}><el1 attr={} style={}></el1></el>')
-
-    done()
-  })
-
-  it('removeChild', (done) => {
-    const el = doc.createElement('el')
-    const el1 = doc.createElement('el1')
-
-    el.removeChild(el1)
-    el.removeChild(el1, true)
-
-    done()
-  })
-
-  it('removeEvent', (done) => {
-    const el = doc.createElement('el')
-    el.removeEvent(null)
-    done()
-  })
-
-  it('add element', (done) => {
-    const body = doc.createBody('r')
-
-    doc.documentElement.appendChild(body)
-
-    expect(spy.args[0]).eql([[{
-      module: 'dom', method: 'createBody',
-      args: [body.toJSON()]
-    }], '-1'])
-
-    const el = doc.createElement('a')
-    el.setAttr('x', 1)
-    el.addEvent('click', () => {})
-    doc.body.appendChild(el)
-
-    expect(spy.args[1]).eql([[{
-      module: 'dom', method: 'addElement',
-      args: ['_root', el.toJSON(), -1]
-    }], '-1'])
-
-    const el2 = doc.createElement('b')
-    doc.body.insertBefore(el2, el) // [el2, el]
-
-    const el3 = doc.createElement('c')
-    doc.body.insertAfter(el3, el) // [el2, el, el3]
-
-    expect(spy.args.length).eql(4)
-    expect(spy.args[2]).eql([[{
-      module: 'dom', method: 'addElement',
-      args: ['_root', el2.toJSON(), 0]
-    }], '-1'])
-    expect(spy.args[3]).eql([[{
-      module: 'dom', method: 'addElement',
-      args: ['_root', el3.toJSON(), 2]
-    }], '-1'])
-
-    done()
-  })
-
-  it.skip('batch when document closed', (done) => {
-    const body = doc.createBody('r')
-
-    doc.documentElement.appendChild(body)
-
-    expect(spy.args[0]).eql([[{
-      module: 'dom', method: 'createBody',
-      args: [body.toJSON()]
-    }]])
-
-    const el = doc.createElement('a')
-    el.setAttr('x', 1)
-    el.addEvent('click', () => {})
-    doc.body.appendChild(el)
-
-    expect(spy.args[1]).eql([[{
-      module: 'dom', method: 'addElement',
-      args: ['_root', el.toJSON(), -1]
-    }]])
-
-    doc.close()
-
-    const el2 = doc.createElement('b')
-    doc.body.insertBefore(el2, el) // [el2, el]
-
-    const el3 = doc.createElement('c')
-    doc.body.insertAfter(el3, el) // [el2, el, el3]
-
-    expect(spy.args.length).eql(2)
-    expect(doc.listener.updates).eql([
-      {
-        module: 'dom', method: 'addElement',
-        args: ['_root', el2.toJSON(), 0]
-      },
-      {
-        module: 'dom', method: 'addElement',
-        args: ['_root', el3.toJSON(), 2]
-      }
-    ])
-    done()
-  })
-
-  it('bind listener for element props', () => {
-    const el = doc.createElement('bar')
-    doc.createBody('r')
-    doc.documentElement.appendChild(doc.body)
-
-    expect(spy.args.length).eql(1)
-    expect(spy.args[0][0]).eql([{
-      module: 'dom', method: 'createBody',
-      args: [doc.body.toJSON()]
-    }])
-
-    el.setAttr('a', 1)
-    el.setStyle('a', 2)
-    el.setClassStyle({ a: 3, b: 4 })
-    el.addEvent('click', () => {})
-    el.addEvent('appear', () => {})
-    el.removeEvent('appear')
-    doc.body.appendChild(el)
-
-    expect(spy.args.length).eql(2)
-    expect(spy.args[1][0]).eql([{
-      module: 'dom', method: 'addElement',
-      args: ['_root', el.toJSON(), -1]
-    }])
-
-    el.setAttr('a', 11, true)
-    expect(spy.args.length).eql(2)
-    el.setAttr('a', 12)
-    expect(spy.args.length).eql(3)
-    expect(spy.args[2][0]).eql([{
-      module: 'dom', method: 'updateAttrs',
-      args: [el.ref, { a: 12 }]
-    }])
-    el.setAttr('a', 12, false)
-    expect(spy.args.length).eql(4)
-    expect(spy.args[3][0]).eql([{
-      module: 'dom', method: 'updateAttrs',
-      args: [el.ref, { a: 12 }]
-    }])
-
-    el.setStyle('a', 13, true)
-    expect(spy.args.length).eql(4)
-    el.setStyle('a', 14)
-    expect(spy.args.length).eql(5)
-    expect(spy.args[4][0]).eql([{
-      module: 'dom', method: 'updateStyle',
-      args: [el.ref, { a: 14 }]
-    }])
-    el.setStyle('a', 14, false)
-    expect(spy.args.length).eql(6)
-    expect(spy.args[5][0]).eql([{
-      module: 'dom', method: 'updateStyle',
-      args: [el.ref, { a: 14 }]
-    }])
-
-    el.setClassStyle({ a: 13, b: 14 })
-    expect(spy.args[6][0]).eql([{
-      module: 'dom', method: 'updateStyle',
-      args: [el.ref, { a: 14, b: 14 }]
-    }])
-    expect(spy.args.length).eql(7)
-    el.addEvent('click', () => {})
-    expect(spy.args.length).eql(7)
-    el.addEvent('appear', () => {})
-    expect(spy.args.length).eql(8)
-    expect(spy.args[7][0]).eql([{
-      module: 'dom', method: 'addEvent',
-      args: [el.ref, 'appear']
-    }])
-
-    el.removeEvent('click')
-    expect(spy.args.length).eql(9)
-    expect(spy.args[8][0]).eql([{
-      module: 'dom', method: 'removeEvent',
-      args: [el.ref, 'click']
-    }])
-    el.removeEvent('appear')
-    expect(spy.args.length).eql(10)
-    expect(spy.args[9][0]).eql([{
-      module: 'dom', method: 'removeEvent',
-      args: [el.ref, 'appear']
-    }])
-
-    el.setAttr('a', 1)
-    el.setStyle('a', 2)
-    el.setClassStyle({ a: 3, b: 4 })
-    el.addEvent('click', () => {})
-    el.addEvent('appear', () => {})
-    el.removeEvent('appear')
-    expect(spy.args.length).eql(16)
-    expect(spy.args.slice(10).map(c => c[0][0])).eql([
-      { module: 'dom', method: 'updateAttrs', args: [el.ref, { a: 1 }] },
-      { module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2 }] },
-      { module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2, b: 4 }] },
-      { module: 'dom', method: 'addEvent', args: [el.ref, 'click'] },
-      { module: 'dom', method: 'addEvent', args: [el.ref, 'appear'] },
-      { module: 'dom', method: 'removeEvent', args: [el.ref, 'appear'] }
-    ])
-  })
-})
-
-describe('listener', () => {
-  let spy, listener
-
-  beforeEach(() => {
-    spy = sinon.spy()
-    listener = new Listener('1', spy)
-  })
-
-  it('removeElement many', () => {
-    listener.removeElement(['1', '2', '3', '4'])
-
-    expect(spy.args[0][0]).eql([
-      { module: 'dom', method: 'removeElement', args: ['1'] },
-      { module: 'dom', method: 'removeElement', args: ['2'] },
-      { module: 'dom', method: 'removeElement', args: ['3'] },
-      { module: 'dom', method: 'removeElement', args: ['4'] }
-    ])
-
-    listener = null
-  })
-
-  it('no-handler', () => {
-    listener = new Listener('1')
-    listener.handler(
-      { module: 'dom', method: 'removeElement', args: ['1'] },
-      spy
-    )
-    expect(spy).callCount(1)
-  })
-
-  afterEach(() => {
-    spy = null
-    listener = null
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/vdom/node.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/node.js b/html5/test/unit/vdom/node.js
deleted file mode 100644
index a6e567e..0000000
--- a/html5/test/unit/vdom/node.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import chai from 'chai'
-const { expect } = chai
-
-import {
-  Node
-} from '../../../runtime/vdom'
-
-describe('Node', () => {
-  it('create node', () => {
-    const node = new Node()
-    expect(node).is.an.object
-    expect(node.nodeId).to.be.a('string')
-    expect(node.ref).eql(node.nodeId)
-    expect(node.children).eql([])
-    expect(node.pureChildren).eql([])
-    expect(node.parentNode).to.be.null
-    expect(node.nextSibling).to.be.null
-    expect(node.previousSibling).to.be.null
-    node.destroy()
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 0844620..0e71087 100644
--- a/package.json
+++ b/package.json
@@ -75,10 +75,10 @@
     "flow": "flow check",
     "test:case": "mocha --require reify html5/test/case/tester.js",
     "test:vue": "webpack --config build/webpack.test.web.config.js && karma start build/karma.vue.conf.js",
-    "test:unit": "mocha --require reify html5/test/unit/*/*.js html5/test/unit/*/*/*.js",
+    "test:unit": "mocha --require reify html5/test/unit/",
     "test": "npm run lint && npm run test:unit && npm run test:case && npm run test:vue",
-    "test:cover-html": "babel-istanbul cover --report html node_modules/mocha/bin/_mocha -- --require reify --reporter dot html5/test/unit/*/*.js html5/test/unit/*/*/*.js && open coverage/index.html",
-    "test:cover": "babel-istanbul cover --report text node_modules/mocha/bin/_mocha -- --require reify --reporter dot html5/test/unit/*/*.js html5/test/unit/*/*/*.js",
+    "test:cover-html": "babel-istanbul cover --report html node_modules/mocha/bin/_mocha -- --require reify --reporter dot html5/test/unit/ && open coverage/index.html",
+    "test:cover": "babel-istanbul cover --report text node_modules/mocha/bin/_mocha -- --require reify --reporter dot html5/test/unit/",
     "test:e2e": "npm run build:browser && node html5/test/e2e/runner.js",
     "serve": "serve ./ -p 12580",
     "serve:no-port": "serve ./",