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:44 UTC

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

* [test] refactor the unit test cases of runtime


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/9e13c860
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/9e13c860
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/9e13c860

Branch: refs/heads/0.16-dev
Commit: 9e13c86051e4e8e615ea0be0ae86e7237b546494
Parents: bade955
Author: Hanks <zh...@gmail.com>
Authored: Thu Aug 10 16:27:05 2017 +0800
Committer: Hanks <zh...@gmail.com>
Committed: Thu Aug 10 16:27:05 2017 +0800

----------------------------------------------------------------------
 html5/test/unit/default/app/bundle.js       |  96 ----
 html5/test/unit/default/helper/document.js  | 145 -----
 html5/test/unit/default/runtime.js          | 485 -----------------
 html5/test/unit/default/vm/compiler.js      | 614 ---------------------
 html5/test/unit/default/vm/directive.js     | 279 ----------
 html5/test/unit/runtime/legacy-framework.js | 353 ++++++++++++
 html5/test/unit/runtime/vdom/directive.js   |  82 +++
 html5/test/unit/runtime/vdom/index.js       | 639 ++++++++++++++++++++++
 html5/test/unit/runtime/vdom/listener.js    | 381 +++++++++++++
 html5/test/unit/runtime/vdom/node.js        |  39 ++
 html5/test/unit/shared/BroadcastChannel.js  |   7 -
 html5/test/unit/shared/arrayFrom.js         |   5 -
 html5/test/unit/shared/index.js             |  20 +-
 html5/test/unit/vdom/directive.js           |  82 ---
 html5/test/unit/vdom/index.js               | 659 -----------------------
 html5/test/unit/vdom/listener.js            | 423 ---------------
 html5/test/unit/vdom/node.js                |  39 --
 package.json                                |   6 +-
 18 files changed, 1505 insertions(+), 2849 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/default/app/bundle.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/app/bundle.js b/html5/test/unit/default/app/bundle.js
index 64e860a..f44b2f6 100644
--- a/html5/test/unit/default/app/bundle.js
+++ b/html5/test/unit/default/app/bundle.js
@@ -362,70 +362,6 @@ describe('parsing a bundle file', () => {
           .to.deep.equal(template)
       })
     })
-
-    describe.skip('render', () => {
-      it('a component', () => {
-        app.render('main')
-
-        expect(callTasksSpy.callCount).to.be.equal(4)
-
-        expect(readySpy.calledTwice).to.be.true
-        expect(readySpy.firstCall.args[0].a).to.be.equal('b')
-        expect(readySpy.secondCall.args[0].b).to.be.equal('c')
-
-        const task1 = callTasksSpy.firstCall.args[0][0]
-        expect(task1).to.deep.equal({
-          module: 'dom',
-          method: 'createBody',
-          args: [{
-            type: 'container',
-            ref: '_root',
-            attr: {},
-            style: {}
-          }]
-        })
-
-        const task2 = callTasksSpy.secondCall.args[0][0]
-        expect(task2).to.deep.equal({
-          module: 'dom',
-          method: 'addElement',
-          args: ['_root', {
-            type: 'text',
-            ref: app.doc.body.children[0].ref,
-            attr: {
-              value: 'Hello World'
-            },
-            style: {}
-          }, -1]
-        })
-
-        const task3 = callTasksSpy.thirdCall.args[0][0]
-        expect(task3).to.deep.equal({
-          module: 'dom',
-          method: 'addElement',
-          args: ['_root', {
-            type: 'container',
-            ref: app.doc.body.children[1].ref,
-            attr: {},
-            style: {}
-          }, -1]
-        })
-
-        const task4 = callTasksSpy.getCall(3).args[0][0]
-        expect(task4).to.deep.equal({
-          module: 'dom',
-          method: 'addElement',
-          args: [app.doc.body.children[1].ref, {
-            type: 'text',
-            ref: app.doc.body.children[1].children[0].ref,
-            attr: {
-              value: 'Hello World'
-            },
-            style: {}
-          }, -1]
-        })
-      })
-    })
   })
 
   describe('use define/require(backward compatibility)', () => {
@@ -469,37 +405,5 @@ describe('parsing a bundle file', () => {
           .to.deep.equal(componentTemplate)
       })
     })
-
-    describe.skip('require(old)', () => {
-      it('a component', () => {
-        app.require('main')()
-
-        expect(callTasksSpy.calledTwice).to.be.true
-
-        const task1 = callTasksSpy.firstCall.args[0][0]
-        expect(task1.module).to.be.equal('dom')
-        expect(task1.method).to.be.equal('createBody')
-        expect(task1.args[0]).to.deep.equal({
-          type: 'container',
-          ref: '_root',
-          attr: {},
-          style: {}
-        })
-
-        const task2 = callTasksSpy.secondCall.args[0][0]
-        expect(task2.module).to.be.equal('dom')
-        expect(task2.method).to.be.equal('addElement')
-        expect(task2.args[1]).to.deep.equal({
-          type: 'text',
-          ref: app.doc.body.children[0].ref,
-          attr: {
-            value: 'Hello World'
-          },
-          style: {}
-        })
-        expect(task2.args[0]).to.be.equal('_root')
-        expect(task2.args[2]).to.be.equal(-1)
-      })
-    })
   })
 })

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/default/helper/document.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/helper/document.js b/html5/test/unit/default/helper/document.js
deleted file mode 100644
index bac9c25..0000000
--- a/html5/test/unit/default/helper/document.js
+++ /dev/null
@@ -1,145 +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.
- */
-
-function Document () {
-  this.refs = {}
-}
-
-Document.prototype.createBody = function (config) {
-  const doc = this
-  const body = this.body = new Element(config)
-  this.refs._root = this.body
-  if (config.children) {
-    config.children.forEach(function (child) {
-      appendToDoc(doc, child, body.ref, -1)
-    })
-  }
-}
-
-Document.prototype.addElement = function (parentRef, config, index) {
-  appendToDoc(this, config, parentRef, index)
-}
-
-function appendToDoc (doc, config, parentRef, index) {
-  const parent = doc.refs[parentRef]
-  const el = new Element(config)
-  doc.refs[el.ref] = el
-  el.parentRef = parentRef
-
-  if (index < 0) {
-    parent.children.push(el)
-  }
-  else {
-    parent.children.splice(index, 0, el)
-  }
-
-  if (config.children) {
-    config.children.forEach(function (child) {
-      appendToDoc(doc, child, el.ref, -1)
-    })
-  }
-}
-
-Document.prototype.moveElement = function (ref, parentRef, index) {
-  const el = this.refs[ref]
-  const oldParent = this.refs[el.parentRef]
-  const oldIndex = oldParent.children.indexOf(el)
-
-  const parent = this.refs[parentRef]
-
-  if (parent === oldParent && oldIndex <= index) {
-    index = index - 1
-  }
-
-  oldParent.children.splice(oldIndex, 1)
-  parent.children.splice(index, 0, el)
-  el.parentRef = parentRef
-}
-
-Document.prototype.removeElement = function (ref) {
-  removeEl(this, ref)
-}
-
-function removeEl (doc, ref) {
-  const el = doc.refs[ref]
-  const parent = doc.refs[el.parentRef]
-  const index = parent.children.indexOf(el)
-  const children = el.children || []
-  parent.children.splice(index, 1)
-  delete doc.refs[ref]
-  children.forEach(function (child) {
-    removeEl(doc, child.ref)
-  })
-}
-
-Document.prototype.addEvent = function (ref, type) {
-  const el = this.refs[ref]
-  const index = el.event.indexOf(type)
-  if (index < 0) {
-    el.event.push(type)
-  }
-}
-
-Document.prototype.removeEvent = function (ref, type) {
-  const el = this.refs[ref]
-  const index = el.event.indexOf(type)
-  if (index >= 0) {
-    el.event.splice(index, 1)
-  }
-}
-
-Document.prototype.toJSON = function () {
-  const body = this.refs._root
-  if (body) {
-    return body.toJSON()
-  }
-  return {}
-}
-
-function Element (config) {
-  this.ref = config.ref
-  this.parentRef = config.parentRef
-  this.type = config.type
-  this.attr = config.attr || {}
-  this.style = config.style || {}
-  this.event = config.event || []
-  this.children = [] // todo children
-}
-
-Element.prototype.toJSON = function () {
-  const result = { type: this.type }
-  if (Object.keys(this.attr).length > 0) {
-    result.attr = this.attr
-  }
-  if (Object.keys(this.style).length > 0) {
-    result.style = this.style
-  }
-  if (this.event.length > 0) {
-    result.event = this.event
-  }
-  if (this.children.length > 0) {
-    result.children = this.children.map(function (child) {
-      return child.toJSON()
-    })
-  }
-
-  return result
-}
-
-exports.Document = Document

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/default/runtime.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/runtime.js b/html5/test/unit/default/runtime.js
deleted file mode 100644
index 9a52fff..0000000
--- a/html5/test/unit/default/runtime.js
+++ /dev/null
@@ -1,485 +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 runtime from '../../../runtime'
-import frameworks from '../../../frameworks'
-import defaultConfig from '../../../frameworks/legacy/config'
-import { init as resetTaskHandler } from '../../../runtime/bridge/TaskCenter'
-
-const { init, config } = runtime
-config.frameworks = frameworks
-runtime.setNativeConsole()
-
-import Vm from '../../../frameworks/legacy/vm'
-import { clearModules, getModule } from '../../../frameworks/legacy/app/register'
-
-const framework = init(config)
-
-function clearRefs (json) {
-  delete json.ref
-  if (json.children) {
-    json.children.forEach(clearRefs)
-  }
-}
-
-describe('framework entry', () => {
-  const oriCallNative = global.callNative
-  const oriCallAddElement = global.callAddElement
-  const oriDocumentHandler = config.Document.handler
-  const callNativeSpy = sinon.spy()
-  const callAddElementSpy = sinon.spy()
-  const documentHandlerSpy = sinon.spy()
-  const instanceId = Date.now() + ''
-
-  before(() => {
-    global.callNative = (id, tasks, callbackId) => {
-      callNativeSpy(id, tasks, callbackId)
-      /* istanbul ignore if */
-      if (callbackId !== '-1') {
-        framework.callJS(id, [{
-          method: 'callback',
-          args: [callbackId, null, true]
-        }])
-      }
-    }
-    global.callAddElement = (name, id, ref, json, index, callbackId) => {
-      callAddElementSpy(name, ref, json, index, callbackId)
-      /* istanbul ignore if */
-      if (callbackId !== '-1') {
-        framework.callJS(id, [{
-          method: 'callback',
-          args: [callbackId, null, true]
-        }])
-      }
-    }
-    config.Document.handler = oriDocumentHandler
-    resetTaskHandler()
-  })
-
-  afterEach(() => {
-    callNativeSpy.reset()
-    callAddElementSpy.reset()
-    documentHandlerSpy.reset()
-  })
-
-  after(() => {
-    config.Document.handler = oriDocumentHandler
-    global.callNative = oriCallNative
-    global.callAddElement = oriCallAddElement
-  })
-
-  describe('createInstance', () => {
-    it('a simple bundle', () => {
-      const code = `
-        define('@weex-component/main',
-          function(require, exports, module) {
-            module.exports = {
-              data: function() {
-                return {
-                  text: 'Hello World',
-                  showText: true
-                };
-              }
-            }
-
-            ;module.exports.style = {}
-
-            ;module.exports.template = {
-              'type': 'container',
-              'children': [{
-                'type': 'text',
-                'shown': function() {
-                  return this.showText
-                },
-                'attr': {
-                  'value': function() {
-                    return this.text
-                  }
-                }
-              }]
-            }
-          }
-        )
-
-        bootstrap('@weex-component/main')
-      `
-      framework.createInstance(instanceId, code)
-      expect(callNativeSpy.callCount).to.be.equal(2)
-      expect(callAddElementSpy.callCount).to.be.equal(1)
-
-      expect(callNativeSpy.firstCall.args[0]).to.be.equal(instanceId)
-      expect(callNativeSpy.firstCall.args[1]).to.deep.equal([{
-        module: 'dom',
-        method: 'createBody',
-        args: [{
-          ref: '_root',
-          type: 'container',
-          attr: {},
-          style: {}
-        }]
-      }])
-      // expect(callNativeSpy.firstCall.args[2]).to.not.equal('-1')
-
-      expect(callAddElementSpy.firstCall.args[0]).to.be.equal(instanceId)
-      delete callAddElementSpy.firstCall.args[1].ref
-      expect(callAddElementSpy.firstCall.args[1]).to.deep.equal({
-        type: 'text',
-        attr: { value: 'Hello World' },
-        style: {}
-      })
-
-      // expect(callNativeSpy.secondCall.args[2]).to.not.equal('-1')
-
-      expect(callNativeSpy.secondCall.args[0]).to.be.equal(instanceId)
-      expect(callNativeSpy.secondCall.args[1]).to.deep.equal([{
-        module: 'dom',
-        method: 'createFinish',
-        args: []
-      }])
-      // expect(callNativeSpy.thirdCall.args[2]).to.not.equal('-1')
-    })
-
-    it('with a exist instanceId', () => {
-      const code = ''
-      const result = framework.createInstance(instanceId, code)
-      expect(result).to.be.an.instanceof(Error)
-    })
-
-    it('js bundle format version checker', function () {
-      const weexFramework = frameworks.Weex
-      frameworks.Weex = {
-        init: function () {},
-        createInstance: sinon.spy()
-      }
-      frameworks.xxx = {
-        init: function () {},
-        createInstance: sinon.spy()
-      }
-      frameworks.yyy = {
-        init: function () {},
-        createInstance: sinon.spy()
-      }
-
-      // test framework xxx
-      let code = `// {"framework":"xxx","version":"0.3.1"}
-      'This is a piece of JavaScript from a third-party Framework...'`
-      framework.createInstance(instanceId + '~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(1)
-      expect(frameworks.yyy.createInstance.callCount).equal(0)
-      expect(frameworks.Weex.createInstance.callCount).equal(0)
-      expect(frameworks.xxx.createInstance.firstCall.args.slice(0, 4)).eql([
-        instanceId + '~',
-        code,
-        { env: {}},
-        undefined
-      ])
-
-      // also support spaces in JSON string
-      // also ignore spaces between double-slash and JSON string
-      code = `//{ "framework":"xxx" }
-      'This is a piece of JavaScript from a third-party Framework...'`
-      framework.createInstance(instanceId + '~~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(2)
-      expect(frameworks.yyy.createInstance.callCount).equal(0)
-      expect(frameworks.Weex.createInstance.callCount).equal(0)
-
-      // also support non-strict JSON format
-      code = `// {framework:"xxx",'version':"0.3.1"}
-      'This is a piece of JavaScript from a third-party Framework...'`
-      framework.createInstance(instanceId + '~~~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(2)
-      expect(frameworks.yyy.createInstance.callCount).equal(0)
-      expect(frameworks.Weex.createInstance.callCount).equal(1)
-      expect(frameworks.Weex.createInstance.firstCall.args.slice(0, 4)).eql([
-        instanceId + '~~~',
-        code,
-        { env: {}},
-        undefined
-      ])
-
-      // test framework yyy
-      /* eslint-disable */
-      code = `
-
-
-
-        // {"framework":"yyy"}
-
-'JS Bundle with space and empty lines behind'` // modified from real generated code from tb
-      /* eslint-enable */
-      framework.createInstance(instanceId + '~~~~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(2)
-      expect(frameworks.yyy.createInstance.callCount).equal(1)
-      expect(frameworks.Weex.createInstance.callCount).equal(1)
-      expect(frameworks.yyy.createInstance.firstCall.args.slice(0, 4)).eql([
-        instanceId + '~~~~',
-        code,
-        { env: {}},
-        undefined
-      ])
-
-      // test framework Weex (wrong format at the middle)
-      code = `'Some JS bundle code here ... // {"framework":"xxx"}\n ... end.'`
-      framework.createInstance(instanceId + '~~~~~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(2)
-      expect(frameworks.yyy.createInstance.callCount).equal(1)
-      expect(frameworks.Weex.createInstance.callCount).equal(2)
-      expect(frameworks.Weex.createInstance.secondCall.args.slice(0, 4)).eql([
-        instanceId + '~~~~~',
-        code,
-        { env: {}},
-        undefined
-      ])
-
-      // test framework Weex (without any JSON string in comment)
-      code = `'Some JS bundle code here'`
-      framework.createInstance(instanceId + '~~~~~~', code)
-      expect(frameworks.xxx.createInstance.callCount).equal(2)
-      expect(frameworks.yyy.createInstance.callCount).equal(1)
-      expect(frameworks.Weex.createInstance.callCount).equal(3)
-      expect(frameworks.Weex.createInstance.thirdCall.args.slice(0, 4)).eql([
-        instanceId + '~~~~~~',
-        code,
-        { env: {}},
-        undefined
-      ])
-
-      // revert frameworks
-      delete frameworks.xxx
-      delete frameworks.yyy
-      frameworks.Weex = weexFramework
-    })
-  })
-
-  describe('getRoot', () => {
-    it('with a exist instanceId', () => {
-      const json = framework.getRoot(instanceId)
-      expect(json.ref).eql('_root')
-      clearRefs(json)
-      const expectJSON = {
-        type: 'container',
-        attr: {},
-        style: {},
-        children: [{
-          type: 'text',
-          attr: {
-            value: 'Hello World'
-          },
-          style: {}
-        }]
-      }
-      expect(json).to.be.deep.equal(expectJSON)
-    })
-
-    it('with a non-exist instanceId', () => {
-      const result = framework.getRoot('123')
-      expect(result).to.be.an.instanceof(Error)
-    })
-  })
-
-  describe('callJS', () => {
-    it('fireEvent with no params', () => {
-      framework.callJS()
-    })
-
-    it('fireEvent with a exist instanceId', () => {
-      framework.callJS(instanceId, [{
-        method: 'fireEvent',
-        args: []
-      }])
-    })
-
-    it('callback with a exist instanceId', () => {
-      framework.callJS(instanceId, [{
-        method: 'callback',
-        args: []
-      }])
-    })
-
-    it('with a non-exist instanceId', () => {
-      const result = framework.callJS('123', [{
-        method: 'fireEvent',
-        args: []
-      }])
-      expect(result).to.be.an.instanceof(Error)
-    })
-
-    it('with a non-array tasks', () => {
-      const result = framework.callJS(instanceId, {
-        method: 'fireEvent',
-        args: []
-      })
-      expect(result).to.be.an.instanceof(Error)
-    })
-  })
-
-  describe('refreshInstance', () => {
-    it('modify showText to false', () => {
-      const json = framework.getRoot(instanceId)
-      const textRef = json.children[0].ref
-      framework.refreshInstance(instanceId, { showText: false })
-      expect(callNativeSpy.callCount).to.be.equal(2)
-      expect(callNativeSpy.firstCall.args[0]).to.be.equal(instanceId)
-      expect(callNativeSpy.firstCall.args[1]).to.deep.equal([{
-        module: 'dom',
-        method: 'removeElement',
-        args: [textRef]
-      }])
-      // expect(callNativeSpy.firstCall.args[2]).to.be.equal('-1')
-
-      expect(callNativeSpy.secondCall.args[0]).to.be.equal(instanceId)
-      expect(callNativeSpy.secondCall.args[1]).to.deep.equal([{
-        module: 'dom',
-        method: 'refreshFinish',
-        args: []
-      }])
-      // expect(callNativeSpy.secondCall.args[2]).to.be.equal('-1')
-    })
-
-    it('with a non-exist instanceId', () => {
-      const result = framework.refreshInstance('123', {})
-      expect(result).to.be.an.instanceof(Error)
-    })
-  })
-
-  describe('destroyInstance', () => {
-    it('with no params', () => {
-      framework.destroyInstance()
-    })
-
-    it('with a exist instanceId', () => {
-      const result = framework.destroyInstance(instanceId)
-      expect(result[instanceId]).to.be.undefined
-    })
-
-    it('with a non-exist instanceId', () => {
-      const result = framework.destroyInstance('123')
-      expect(result).to.be.an.instanceof(Error)
-    })
-  })
-
-  describe('registerComponents', () => {
-    it('with old format', () => {
-      framework.registerComponents(['a', 'b', 'c'])
-      expect(defaultConfig.nativeComponentMap).to.contain.keys('a', 'b', 'c')
-    })
-
-    it('with new format', () => {
-      framework.registerComponents([{
-        type: 'd',
-        append: 'tree'
-      }])
-      expect(defaultConfig.nativeComponentMap).to.contain.keys('d')
-      expect(defaultConfig.nativeComponentMap['d']).to.be.deep.equal({
-        type: 'd',
-        append: 'tree'
-      })
-    })
-
-    it('with non-array', () => {
-      framework.registerComponents({
-        type: 'e'
-      })
-      expect(defaultConfig.nativeComponentMap).not.contain.keys('e')
-    })
-
-    it('with methods', () => {
-      const components = [{
-        type: 'x',
-        methods: ['foo', 'bar']
-      }, {
-        type: 'y',
-        methods: []
-      }, {
-        type: 'z',
-        methods: null
-      }]
-      framework.registerComponents(components)
-      expect(defaultConfig.nativeComponentMap).to.contain.keys('x', 'y', 'z')
-    })
-  })
-
-  describe('register modules', () => {
-    it('with object of modules', () => {
-      clearModules()
-      const modules = {
-        a: [{
-          name: 'b',
-          args: ['string']
-        }]
-      }
-
-      framework.registerModules(modules)
-      expect(getModule('b')).an.object
-      clearModules()
-    })
-  })
-
-  describe('register methods', () => {
-    it('with object of methods', () => {
-      const methods = {
-        a: sinon.spy()
-      }
-
-      framework.registerMethods(methods)
-      expect(Vm.prototype.a).a.function
-      delete Vm.prototype.a
-    })
-  })
-})
-
-describe('config', () => {
-  it('config is an object', () => {
-    init({})
-  })
-})
-
-describe.skip('freeze the prototypes of vdom', function () {
-  const { Document, Element, Comment, Listener } = config
-
-  before(() => {
-    runtime.freezePrototype()
-  })
-
-  it('Document.prototype', () => {
-    expect(Document.prototype).to.be.frozen
-  })
-
-  it('Element & Element.prototype', () => {
-    expect(Element).to.be.frozen
-    expect(Element.prototype).to.be.frozen
-  })
-
-  it('Comment & Comment.prototype', () => {
-    expect(Comment).to.be.frozen
-    expect(Comment.prototype).to.be.frozen
-  })
-
-  it('Listener & Listener.prototype', () => {
-    expect(Listener).to.be.frozen
-    expect(Listener.prototype).to.be.frozen
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/default/vm/compiler.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/vm/compiler.js b/html5/test/unit/default/vm/compiler.js
deleted file mode 100644
index 654f1ed..0000000
--- a/html5/test/unit/default/vm/compiler.js
+++ /dev/null
@@ -1,614 +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 * as compiler from '../../../../frameworks/legacy/vm/compiler'
-import * as directive from '../../../../frameworks/legacy/vm/directive'
-import { initState } from '../../../../frameworks/legacy/core/state'
-
-describe.skip('generate workflow', () => {
-  let contentIndex = 0
-  const vm = {}
-  Object.assign(vm, compiler, directive, {
-    _watchers: [],
-    _createBlock: function () { return { element: {}} },
-    _mergeContext: function () { return this },
-    _createBody: type => { return { type } },
-    _createElement: type => { return { type } },
-    _attachTarget: (element, dest) => element,
-    _bindElement: () => {},
-    _setId: function () {},
-    _bindSubVm: function () {},
-    _bindSubVmAfterInitialized: function () {},
-    _applyNaitveComponentOptions: function () {}
-  })
-
-  vm.constructor = function () {
-    contentIndex++
-    this._content = { index: contentIndex }
-    this.$on = sinon.spy()
-  }
-
-  beforeEach(() => {
-    contentIndex = 0
-    sinon.spy(vm, '_compile')
-    sinon.spy(vm, '_compileNativeComponent')
-    sinon.spy(vm, '_createBody')
-    sinon.spy(vm, '_createElement')
-    sinon.spy(vm, '_bindElement')
-    sinon.spy(vm, '_attachTarget')
-    sinon.spy(vm, '_createBlock')
-    sinon.spy(vm, '_mergeContext')
-    sinon.spy(vm, 'constructor')
-  })
-
-  afterEach(() => {
-    vm._compile.restore()
-    vm._compileNativeComponent.restore()
-    vm._createBody.restore()
-    vm._createElement.restore()
-    vm._bindElement.restore()
-    vm._attachTarget.restore()
-    vm._createBlock.restore()
-    vm._mergeContext.restore()
-    vm.constructor.restore()
-    contentIndex = 0
-  })
-
-  it('generate a body', (done) => {
-    const target = {
-      type: 'a'
-    }
-    const dest = {
-      ref: '_documentElement'
-    }
-
-    function check () {
-      expect(vm._compile).callCount(1)
-      expect(vm._compile).calledWith(target, dest)
-      expect(vm._createBody).callCount(1)
-      expect(vm._bindElement).callCount(1)
-      expect(vm._createElement).callCount(0)
-      expect(vm._attachTarget).callCount(1)
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate a single element', (done) => {
-    const target = {
-      type: 'a'
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(1)
-      expect(vm._compile).calledWith(target, dest)
-      expect(vm._createBody).callCount(0)
-      expect(vm._bindElement).callCount(1)
-      expect(vm._createElement).callCount(1)
-      expect(vm._attachTarget).callCount(1)
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate some child nodes', (done) => {
-    const target = [{
-      type: 'a'
-    }, {
-      type: 'b'
-    }]
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(3)
-      expect(vm._compile.args[0]).eql(
-        [target, dest])
-      expect(vm._compile.args[1]).eql(
-        [target[0], { element: {}}, undefined])
-      expect(vm._compile.args[2]).eql(
-        [target[1], { element: {}}, undefined])
-      expect(vm._createBlock).callCount(1)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate content holder', (done) => {
-    const target = {
-      type: 'a', children: [
-        { type: 'b' },
-        { type: 'content' },
-        { type: 'c' }
-      ]
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(4)
-      expect(vm._compile.args[0]).eql(
-        [target, dest])
-      expect(vm._compile.args[1]).eql(
-        [target.children[0], { type: 'a' }])
-      expect(vm._compile.args[2]).eql(
-        [target.children[1], { type: 'a' }])
-      expect(vm._compile.args[3]).eql(
-        [target.children[2], { type: 'a' }])
-      expect(vm._content).is.an.object
-      expect(vm._content).eql({ element: {}})
-      expect(vm._createBlock).callCount(1)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate a repeat element', (done) => {
-    const target = {
-      type: 'a',
-      repeat: () => [1, 2, 3]
-    }
-    const dest = {}
-
-    function checkRepeatVm (args, target, meta) {
-      expect(args[0]).eql(target)
-      expect(args[2]).eql(meta)
-      const vm = args[1]
-      expect(vm.element).eql({})
-      expect(vm.data).eql([1, 2, 3])
-    }
-
-    function check () {
-      expect(vm._compile).callCount(4)
-      expect(vm._compile.args[0]).eql([target, dest])
-      checkRepeatVm(vm._compile.args[1], target, { repeat: 1 })
-      checkRepeatVm(vm._compile.args[2], target, { repeat: 2 })
-      checkRepeatVm(vm._compile.args[3], target, { repeat: 3 })
-      expect(vm._createBlock).callCount(1)
-      expect(vm._mergeContext).callCount(3)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('can\'t not use repeat on root element', (done) => {
-    const target = {
-      type: 'a',
-      repeat: () => [1, 2, 3]
-    }
-    const dest = {
-      type: 'document'
-    }
-
-    function check () {
-      expect(vm._compile).callCount(1)
-      expect(vm._createBody).callCount(0)
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate a shown element', (done) => {
-    const target = {
-      type: 'a',
-      shown: () => true
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(2)
-      expect(vm._compile.args[0]).eql(
-        [target, dest])
-      expect(vm._compile.args[1][0]).eql(target)
-      expect(vm._compile.args[1][1].display).eql(true)
-      expect(vm._compile.args[1][2]).eql({ shown: true })
-      expect(vm._createBlock).callCount(1)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('can\'t not use shown on root element', (done) => {
-    const target = {
-      type: 'a',
-      shown: () => true
-    }
-    const dest = {
-      type: 'document'
-    }
-
-    function check () {
-      expect(vm._compile).callCount(1)
-      expect(vm._createBody).callCount(0)
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate a repeat shown element', (done) => {
-    let index = 0
-    const target = {
-      type: 'a',
-      repeat: () => [1, 2, 3],
-      shown: () => {
-        index++
-        return index % 2
-      }
-    }
-    const dest = {}
-
-    function checkRepeatVm (args, target, meta) {
-      expect(args[0]).eql(target)
-      expect(args[2]).eql(meta)
-      const vm = args[1]
-      expect(vm.element).eql({})
-      expect(vm.data).eql([1, 2, 3])
-    }
-
-    function check () {
-      expect(vm._compile).callCount(6)
-      expect(vm._compile.args[0]).eql([target, dest])
-      checkRepeatVm(vm._compile.args[1], target, { repeat: 1 })
-      expect(vm._compile.args[2][0]).eql(target)
-      expect(vm._compile.args[2][1].display).eql(true)
-      expect(vm._compile.args[2][2]).eql({ repeat: 1, shown: true })
-      checkRepeatVm(vm._compile.args[3], target, { repeat: 2 })
-      checkRepeatVm(vm._compile.args[4], target, { repeat: 3 })
-      expect(vm._compile.args[5][0]).eql(target)
-      expect(vm._compile.args[5][1].display).eql(true)
-      expect(vm._compile.args[5][2]).eql({ repeat: 3, shown: true })
-      expect(vm._createBlock).callCount(4)
-      expect(vm._mergeContext).callCount(3)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate an element with children', (done) => {
-    const target = {
-      type: 'a',
-      children: [{ type: 'b' }, { type: 'c' }]
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(3)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], { type: 'a' }])
-      expect(vm._compile.args[2]).eql([target.children[1], { type: 'a' }])
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate an whole element with children', (done) => {
-    const target = {
-      type: 'a',
-      append: 'tree',
-      children: [{ type: 'b' }, { type: 'c' }]
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(3)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], {
-        attr: {
-          append: 'tree'
-        }, type: 'a' }])
-      expect(vm._compile.args[2]).eql([target.children[1], {
-        attr: {
-          append: 'tree'
-        }, type: 'a' }])
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate an element with repeat shown children', (done) => {
-    let index = 0
-    const target = {
-      type: 'a',
-      children: [
-        {
-          type: 'b',
-          repeat: () => [1, 2, 3],
-          shown: () => {
-            index++
-            return index % 2
-          }
-        },
-        { type: 'c' }
-      ]
-    }
-    const dest = {}
-
-    function checkRepeatVm (args, target, meta) {
-      expect(args[0]).eql(target)
-      expect(args[2]).eql(meta)
-      const vm = args[1]
-      expect(vm.element).eql({})
-      expect(vm.data).eql([1, 2, 3])
-    }
-
-    function check () {
-      expect(vm._compile).callCount(8)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], { type: 'a' }])
-      checkRepeatVm(vm._compile.args[2], target.children[0], { repeat: 1 })
-      expect(vm._compile.args[3][0]).eql(target.children[0])
-      expect(vm._compile.args[3][1].display).eql(true)
-      expect(vm._compile.args[3][2]).eql({ repeat: 1, shown: true })
-      checkRepeatVm(vm._compile.args[4], target.children[0], { repeat: 2 })
-      checkRepeatVm(vm._compile.args[5], target.children[0], { repeat: 3 })
-      expect(vm._compile.args[6][0]).eql(target.children[0])
-      expect(vm._compile.args[6][1].display).eql(true)
-      expect(vm._compile.args[6][2]).eql({ repeat: 3, shown: true })
-      expect(vm._compile.args[7]).eql([target.children[1], { type: 'a' }])
-      expect(vm._createBlock).callCount(4)
-      expect(vm._mergeContext).callCount(3)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate an element with repeat shown tree', (done) => {
-    let index = 0
-    const target = {
-      type: 'a',
-      children: [
-        {
-          type: 'b',
-          children: [{ type: 'c' }],
-          repeat: () => [1, 2, 3],
-          shown: function () {
-            index++
-            return index % 2
-          }
-        },
-        { type: 'd' }
-      ]
-    }
-    const dest = {}
-
-    function checkRepeatVm (args, target, meta) {
-      expect(args[0]).eql(target)
-      expect(args[2]).eql(meta)
-      const vm = args[1]
-      expect(vm.element).eql({})
-      expect(vm.data).eql([1, 2, 3])
-    }
-
-    function check () {
-      expect(vm._compile).callCount(10)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], { type: 'a' }])
-      checkRepeatVm(vm._compile.args[2], target.children[0], { repeat: 1 })
-      expect(vm._compile.args[3][0]).eql(target.children[0])
-      expect(vm._compile.args[3][1].display).eql(true)
-      expect(vm._compile.args[3][2]).eql({ repeat: 1, shown: true })
-      expect(vm._compile.args[4]).eql([target.children[0].children[0],
-        { type: 'b' }])
-      checkRepeatVm(vm._compile.args[5], target.children[0], { repeat: 2 })
-      checkRepeatVm(vm._compile.args[6], target.children[0], { repeat: 3 })
-      expect(vm._compile.args[7][0]).eql(target.children[0])
-      expect(vm._compile.args[7][1].display).eql(true)
-      expect(vm._compile.args[7][2]).eql({ repeat: 3, shown: true })
-      expect(vm._compile.args[8]).eql([target.children[0].children[0],
-        { type: 'b' }])
-      expect(vm._compile.args[9]).eql([target.children[1], { type: 'a' }])
-      expect(vm._createBlock).callCount(4)
-      expect(vm._mergeContext).callCount(3)
-      expect(vm.constructor).callCount(0)
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('generate an element with custom children', (done) => {
-    const target = {
-      type: 'a',
-      children: [
-        { type: 'b', component: true },
-        { type: 'c' }
-      ]
-    }
-    const dest = {}
-
-    function check () {
-      expect(vm._compile).callCount(3)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], { type: 'a' }])
-      expect(vm._compile.args[2]).eql([target.children[1], { type: 'a' }])
-      expect(vm._createBlock).callCount(0)
-      expect(vm._mergeContext).callCount(0)
-      expect(vm.constructor).callCount(1)
-      expect(vm.constructor.args[0][0]).eql('b')
-      expect(vm.constructor.args[0][1]).eql({})
-      expect(vm.constructor.args[0][3]).eql({ type: 'a' })
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-
-  it('with custom repeat show children', (done) => {
-    let index = 0
-    const target = {
-      type: 'a',
-      children: [
-        {
-          type: 'b',
-          component: true,
-          repeat: () => [1, 2, 3],
-          shown: function () {
-            index++
-            return index % 2
-          }
-        },
-        { type: 'd' }
-      ]
-    }
-    const dest = {}
-
-    function checkRepeatVm (args, target, meta) {
-      expect(args[0]).eql(target)
-      expect(args[2]).eql(meta)
-      const vm = args[1]
-      expect(vm.element).eql({})
-      expect(vm.data).eql([1, 2, 3])
-    }
-
-    function check () {
-      expect(vm._compile).callCount(8)
-      expect(vm._compile.args[0]).eql([target, dest])
-      expect(vm._compile.args[1]).eql([target.children[0], { type: 'a' }])
-      checkRepeatVm(vm._compile.args[2], target.children[0], { repeat: 1 })
-      expect(vm._compile.args[3][0]).eql(target.children[0])
-      expect(vm._compile.args[3][1].display).eql(true)
-      expect(vm._compile.args[3][2]).eql({ repeat: 1, shown: true })
-      checkRepeatVm(vm._compile.args[4], target.children[0], { repeat: 2 })
-      checkRepeatVm(vm._compile.args[5], target.children[0], { repeat: 3 })
-      expect(vm._compile.args[6][0]).eql(target.children[0])
-      expect(vm._compile.args[6][1].display).eql(true)
-      expect(vm._compile.args[6][2]).eql({ repeat: 3, shown: true })
-      expect(vm._compile.args[7]).eql([target.children[1], { type: 'a' }])
-      expect(vm._createBlock).callCount(4)
-      expect(vm._mergeContext).callCount(3)
-
-      expect(vm.constructor).callCount(2)
-      expect(vm.constructor.args[0][0]).eql('b')
-      expect(vm.constructor.args[0][3]).eql({ element: {}, display: true })
-      expect(vm.constructor.args[1][0]).eql('b')
-      expect(vm.constructor.args[1][3]).eql({ element: {}, display: true })
-
-      done()
-    }
-
-    vm._compile(target, dest)
-    check()
-  })
-})
-
-describe.skip('merge context', () => {
-  const { mergeContext } = compiler
-  let vm
-
-  beforeEach(() => {
-    vm = {
-      _data: { a: 1, b: 2 }
-    }
-    initState(vm)
-  })
-
-  afterEach(() => {
-    vm = null
-  })
-
-  it('merge external data', () => {
-    const context = mergeContext(vm, { a: 3 })
-    expect(context).not.equal(vm)
-    expect(context.a).eql(3)
-    expect(context.b).eql(2)
-  })
-
-  it('react with changes, but not with internal for ext-key', () => {
-    const context = mergeContext(vm, { a: 3 })
-    vm.a = 4
-    vm.b = 5
-    expect(context.a).eql(3)
-    expect(context.b).eql(5)
-    context.a = 6
-    expect(context.a).eql(6)
-  })
-
-  it('merge external data if key not bound', () => {
-    const context = mergeContext(vm, { c: 3 })
-    expect(context).not.equal(vm)
-    expect(context.a).eql(1)
-    expect(context.b).eql(2)
-    expect(context.c).eql(3)
-  })
-
-  it('not react with changes for extra key', () => {
-    const context = mergeContext(vm, { c: 3 })
-    vm.c = 9
-    expect(context.a).eql(1)
-    expect(context.b).eql(2)
-    expect(context.c).eql(3)
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/default/vm/directive.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/vm/directive.js b/html5/test/unit/default/vm/directive.js
index caa93c5..fa21969 100644
--- a/html5/test/unit/default/vm/directive.js
+++ b/html5/test/unit/default/vm/directive.js
@@ -52,84 +52,6 @@ function initElement (el) {
   }
 }
 
-// exports._watch(calc, callback)
-// exports._bindKey(obj, key, calc)
-// exports._bindDir(el, name, data)
-describe.skip('watch key or props', () => {
-  let vm, cb
-  const update = function () { return this.a + this.b }
-  const update2 = function () { return this.plus() }
-  const callPlus = sinon.spy()
-  const methodNames = ['_watch', '_bindKey', '_bindDir']
-  beforeEach(() => {
-    vm = {
-      _data: { a: 1, b: 2 },
-      _methods: {
-        plus: function () {
-          callPlus()
-          return this.a + this.b
-        }
-      },
-      _watchers: [],
-      _app: {}
-    }
-    extendVm(vm, methodNames)
-    cb = sinon.spy()
-  })
-  afterEach(() => {
-    vm = null
-    cb = null
-  })
-  // - watch update when data source changed
-  it('watch simple exp', () => {
-    vm._watch(update, cb)
-    const value = update.call(vm)
-    expect(cb).not.called
-    expect(value).equal(3)
-    vm.a = 2
-    expect(vm._data).eql({ a: 2, b: 2 })
-    expect(cb).calledOnce
-    expect(cb).calledOn(undefined)
-    expect(cb).calledWith(4)
-    vm.b = 3
-    expect(vm._data).eql({ a: 2, b: 3 })
-    expect(cb).calledTwice
-    expect(cb).calledWith(5)
-  })
-
-  // - update object key-value when data source changed
-  it('watch k-v pairs', () => {
-    const el = { attr: { c: 3 }}
-    initElement(el)
-    const attr = el.attr
-    vm._bindKey = directive._bindKey
-    vm._bindKey(el, 'attr', 'd', update)
-    expect(attr.d).equal(3)
-    vm.a = 2
-    expect(vm._data).eql({ a: 2, b: 2 })
-    expect(attr.d).equal(4)
-    vm.b = 3
-    expect(vm._data).eql({ a: 2, b: 3 })
-    expect(attr.d).equal(5)
-  })
-  // - update prop value when data source changed
-  it('watch element props', () => {
-    const el = { attr: { c: 3 }}
-    initElement(el)
-    vm._bindDir(el, 'attr', { d: 4, e: update, f: update2 })
-    expect(el.attr).eql({ c: 3, d: 4, e: 3, f: 3 })
-    expect(callPlus).calledOnce
-    vm.a = 2
-    expect(vm._data).eql({ a: 2, b: 2 })
-    expect(el.attr).eql({ c: 3, d: 4, e: 4, f: 4 })
-    expect(callPlus).calledTwice
-    vm.b = 3
-    expect(vm._data).eql({ a: 2, b: 3 })
-    expect(el.attr).eql({ c: 3, d: 4, e: 5, f: 5 })
-    expect(callPlus).calledThird
-  })
-})
-
 describe('apply component options', () => {
   it('apply top prop', () => {
     nativeComponentMap['test-apply'] = {
@@ -177,207 +99,6 @@ describe('apply component options', () => {
   })
 })
 
-// exports._setId(id, el, vm) ?
-// exports._setAttr(el, attr)
-// exports._setClass(el, classList)
-// exports._setStyle(el, style)
-describe.skip('set props', () => {
-  let vm, el
-  const update = function () { return this.a + this.b }
-  const methodNames = [
-    '_watch', '_bindKey', '_bindDir',
-    '_setId', '_setAttr', '_setClass', '_setStyle',
-    '_setEvent', '_bindEvents', '_bindElement']
-
-  before(() => {
-    sinon.stub(console, 'info')
-    sinon.stub(console, 'warn')
-    sinon.stub(console, 'error')
-  })
-
-  after(() => {
-    console.info.restore()
-    console.warn.restore()
-    console.error.restore()
-  })
-
-  beforeEach(() => {
-    el = {
-      attr: {}, style: {}
-    }
-    initElement(el)
-    vm = {
-      _ids: {},
-      _options: {
-        style: {
-          x: { e: 0, f: 5 },
-          y: { f: 6 },
-          z: { e: 10 }
-        }
-      },
-      _data: { a: 1, b: 2, classNameVar: 'x', idVar: 'n' },
-      _methods: {},
-      _watchers: [],
-      _app: {}
-    }
-    extendVm(vm, methodNames)
-  })
-  afterEach(() => {
-    el = null
-    vm = null
-  })
-  // - set value to id
-  it('set value to id', () => {
-    const targetVm = {}
-    vm._setId('m', el, targetVm)
-    expect(vm._ids).a('object')
-    expect(vm._ids.m).a('object')
-    expect(vm._ids.m.el).equal(el)
-    expect(vm._ids.m.vm).equal(targetVm)
-  })
-  // - set function to id
-  it('set function to id', () => {
-    const targetVm = {}
-    vm._setId(function () { return this.idVar }, el, targetVm)
-    expect(vm._ids.n).a('object')
-    expect(vm._ids.n.el).equal(el)
-    expect(vm._ids.n.vm).equal(targetVm)
-    vm.idVar = 'l'
-    expect(vm._ids.l).a('object')
-    expect(vm._ids.l.el).equal(el)
-    expect(vm._ids.l.vm).equal(targetVm)
-  })
-  // - set value to attr
-  // - set function to attr
-  it('set value to attr', () => {
-    vm._setAttr(el, { c: 1, d: update })
-    expect(el.attr).eql({ c: 1, d: 3 })
-  })
-  // - set value to class
-  it('set value to classList', () => {
-    vm._setClass(el, [])
-    expect(el.classStyle).eql({})
-    vm._setClass(el, ['x', 'y'])
-    expect(el.classStyle).eql({ e: 0, f: 6 })
-    vm._setClass(el, [])
-    expect(el.classStyle).eql({})
-  })
-  // - set value to class with another class order
-  it('set value to classList with another class order', () => {
-    vm._setClass(el, ['y', 'x'])
-    expect(el.classStyle).eql({ e: 0, f: 5 })
-  })
-  // - set a function to class
-  it('set a function to classList', () => {
-    vm._setClass(el, function () {
-      return [this.classNameVar, 'y']
-    })
-    expect(el.classStyle).eql({ e: 0, f: 6 })
-    vm.classNameVar = 'z'
-    expect(el.classStyle).eql({ e: 10, f: 6 })
-  })
-  // - set value to style
-  // - set function to style
-  it('set value to style', () => {
-    vm._setStyle(el, { c: 1, d: update })
-    expect(el.style).eql({ c: 1, d: 3 })
-  })
-
-  it('bind elements', () => {
-    // _data: a, b, classNameVar, idVar
-    // _css: {
-    //   x: {e: 0, f: 5},
-    //   y: {f: 6},
-    //   z: {e: 10}
-    // },
-    el.event = {}
-
-    vm._bindElement(el, {
-      id: 'abc',
-      attr: {
-        a: function () { return this.a },
-        b: 456
-      },
-      style: {
-        a: 123,
-        b: function () { return this.b }
-      },
-      events: { click: 'foo' }
-    })
-    expect(vm._ids).a('object')
-    expect(vm._ids.abc).a('object')
-    expect(vm._ids.abc.el).equal(el)
-    expect(vm._ids.abc.vm).equal(vm)
-    expect(el.attr.a).eql(1)
-    expect(el.attr.b).eql(456)
-    expect(el.style.a).eql(123)
-    expect(el.style.b).eql(2)
-    expect(el.event.click).a('function')
-  })
-})
-
-// exports._bindEvents(el, events)
-describe.skip('bind events', () => {
-  let vm, el, cb
-  const app = {}
-  const methodNames = ['_setEvent', '_bindEvents']
-
-  beforeEach(() => {
-    cb = sinon.spy()
-    el = { event: {}}
-    initElement(el)
-
-    vm = {
-      _data: { a: 1 },
-      _methods: {
-        foo: cb
-      },
-      _app: app
-    }
-
-    extendVm(vm, methodNames)
-  })
-  afterEach(() => {
-    vm = null
-    el = null
-    cb = null
-  })
-
-  // - bind method to eventManager
-  it('add event to manager by type', () => {
-    vm._bindEvents(el, { click: 'foo' })
-    expect(el.event.click).a('function')
-  })
-  // - bind method to eventManager
-  it('add event to manager by handler', () => {
-    const cb2 = sinon.spy()
-    vm._bindEvents(el, { click: cb2 })
-    expect(el.event.click).a('function')
-  })
-  // - fireEvent to call method
-  // - with right event info
-  it('fire event from manager by type', () => {
-    const e = {}
-    vm._bindEvents(el, { click: 'foo' })
-    el.event.click(e)
-    expect(cb).calledOnce
-    expect(cb).calledOn(vm)
-    expect(cb).calledWith(e)
-  })
-  // - fireEvent to call method
-  // - with right event info
-  it('fire event from manager by handler', () => {
-    const e = {}
-    vm._bindEvents(el, { click: function ($event) {
-      this.foo(this.a, $event)
-    } })
-    el.event.click(e)
-    expect(cb).calledOnce
-    expect(cb).calledOn(vm)
-    expect(cb).calledWith(1, e)
-  })
-})
-
 // exports._bindSubVm(subVm, template)
 describe('bind external infomations to sub vm', () => {
   let vm, subVm

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/runtime/legacy-framework.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/legacy-framework.js b/html5/test/unit/runtime/legacy-framework.js
new file mode 100644
index 0000000..b25d14d
--- /dev/null
+++ b/html5/test/unit/runtime/legacy-framework.js
@@ -0,0 +1,353 @@
+/*
+ * 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 runtime from '../../../runtime'
+import frameworks from '../../../frameworks'
+import defaultConfig from '../../../frameworks/legacy/config'
+import { init as resetTaskHandler } from '../../../runtime/bridge/TaskCenter'
+
+const { init, config } = runtime
+config.frameworks = frameworks
+runtime.setNativeConsole()
+
+import Vm from '../../../frameworks/legacy/vm'
+import { clearModules, getModule } from '../../../frameworks/legacy/app/register'
+
+const framework = init(config)
+
+function clearRefs (json) {
+  delete json.ref
+  if (json.children) {
+    json.children.forEach(clearRefs)
+  }
+}
+
+describe('framework entry', () => {
+  const oriCallNative = global.callNative
+  const oriCallAddElement = global.callAddElement
+  const oriDocumentHandler = config.Document.handler
+  const callNativeSpy = sinon.spy()
+  const callAddElementSpy = sinon.spy()
+  const documentHandlerSpy = sinon.spy()
+  const instanceId = Date.now() + ''
+
+  before(() => {
+    global.callNative = (id, tasks, callbackId) => {
+      callNativeSpy(id, tasks, callbackId)
+      /* istanbul ignore if */
+      if (callbackId !== '-1') {
+        framework.callJS(id, [{
+          method: 'callback',
+          args: [callbackId, null, true]
+        }])
+      }
+    }
+    global.callAddElement = (name, id, ref, json, index, callbackId) => {
+      callAddElementSpy(name, ref, json, index, callbackId)
+      /* istanbul ignore if */
+      if (callbackId !== '-1') {
+        framework.callJS(id, [{
+          method: 'callback',
+          args: [callbackId, null, true]
+        }])
+      }
+    }
+    config.Document.handler = oriDocumentHandler
+    resetTaskHandler()
+  })
+
+  afterEach(() => {
+    callNativeSpy.reset()
+    callAddElementSpy.reset()
+    documentHandlerSpy.reset()
+  })
+
+  after(() => {
+    config.Document.handler = oriDocumentHandler
+    global.callNative = oriCallNative
+    global.callAddElement = oriCallAddElement
+  })
+
+  describe('createInstance', () => {
+    it('a simple bundle', () => {
+      const code = `
+        define('@weex-component/main',
+          function(require, exports, module) {
+            module.exports = {
+              data: function() {
+                return {
+                  text: 'Hello World',
+                  showText: true
+                };
+              }
+            }
+
+            ;module.exports.style = {}
+
+            ;module.exports.template = {
+              'type': 'container',
+              'children': [{
+                'type': 'text',
+                'shown': function() {
+                  return this.showText
+                },
+                'attr': {
+                  'value': function() {
+                    return this.text
+                  }
+                }
+              }]
+            }
+          }
+        )
+
+        bootstrap('@weex-component/main')
+      `
+      framework.createInstance(instanceId, code)
+      expect(callNativeSpy.callCount).to.be.equal(2)
+      expect(callAddElementSpy.callCount).to.be.equal(1)
+
+      expect(callNativeSpy.firstCall.args[0]).to.be.equal(instanceId)
+      expect(callNativeSpy.firstCall.args[1]).to.deep.equal([{
+        module: 'dom',
+        method: 'createBody',
+        args: [{
+          ref: '_root',
+          type: 'container',
+          attr: {},
+          style: {}
+        }]
+      }])
+      // expect(callNativeSpy.firstCall.args[2]).to.not.equal('-1')
+
+      expect(callAddElementSpy.firstCall.args[0]).to.be.equal(instanceId)
+      delete callAddElementSpy.firstCall.args[1].ref
+      expect(callAddElementSpy.firstCall.args[1]).to.deep.equal({
+        type: 'text',
+        attr: { value: 'Hello World' },
+        style: {}
+      })
+
+      // expect(callNativeSpy.secondCall.args[2]).to.not.equal('-1')
+
+      expect(callNativeSpy.secondCall.args[0]).to.be.equal(instanceId)
+      expect(callNativeSpy.secondCall.args[1]).to.deep.equal([{
+        module: 'dom',
+        method: 'createFinish',
+        args: []
+      }])
+      // expect(callNativeSpy.thirdCall.args[2]).to.not.equal('-1')
+    })
+
+    it('with a exist instanceId', () => {
+      const code = ''
+      const result = framework.createInstance(instanceId, code)
+      expect(result).to.be.an.instanceof(Error)
+    })
+  })
+
+  describe('getRoot', () => {
+    it('with a exist instanceId', () => {
+      const json = framework.getRoot(instanceId)
+      expect(json.ref).eql('_root')
+      clearRefs(json)
+      const expectJSON = {
+        type: 'container',
+        attr: {},
+        style: {},
+        children: [{
+          type: 'text',
+          attr: {
+            value: 'Hello World'
+          },
+          style: {}
+        }]
+      }
+      expect(json).to.be.deep.equal(expectJSON)
+    })
+
+    it('with a non-exist instanceId', () => {
+      const result = framework.getRoot('123')
+      expect(result).to.be.an.instanceof(Error)
+    })
+  })
+
+  describe('callJS', () => {
+    it('fireEvent with no params', () => {
+      framework.callJS()
+    })
+
+    it('fireEvent with a exist instanceId', () => {
+      framework.callJS(instanceId, [{
+        method: 'fireEvent',
+        args: []
+      }])
+    })
+
+    it('callback with a exist instanceId', () => {
+      framework.callJS(instanceId, [{
+        method: 'callback',
+        args: []
+      }])
+    })
+
+    it('with a non-exist instanceId', () => {
+      const result = framework.callJS('123', [{
+        method: 'fireEvent',
+        args: []
+      }])
+      expect(result).to.be.an.instanceof(Error)
+    })
+
+    it('with a non-array tasks', () => {
+      const result = framework.callJS(instanceId, {
+        method: 'fireEvent',
+        args: []
+      })
+      expect(result).to.be.an.instanceof(Error)
+    })
+  })
+
+  describe('refreshInstance', () => {
+    it('modify showText to false', () => {
+      const json = framework.getRoot(instanceId)
+      const textRef = json.children[0].ref
+      framework.refreshInstance(instanceId, { showText: false })
+      expect(callNativeSpy.callCount).to.be.equal(2)
+      expect(callNativeSpy.firstCall.args[0]).to.be.equal(instanceId)
+      expect(callNativeSpy.firstCall.args[1]).to.deep.equal([{
+        module: 'dom',
+        method: 'removeElement',
+        args: [textRef]
+      }])
+      // expect(callNativeSpy.firstCall.args[2]).to.be.equal('-1')
+
+      expect(callNativeSpy.secondCall.args[0]).to.be.equal(instanceId)
+      expect(callNativeSpy.secondCall.args[1]).to.deep.equal([{
+        module: 'dom',
+        method: 'refreshFinish',
+        args: []
+      }])
+      // expect(callNativeSpy.secondCall.args[2]).to.be.equal('-1')
+    })
+
+    it('with a non-exist instanceId', () => {
+      const result = framework.refreshInstance('123', {})
+      expect(result).to.be.an.instanceof(Error)
+    })
+  })
+
+  describe('destroyInstance', () => {
+    it('with no params', () => {
+      framework.destroyInstance()
+    })
+
+    it('with a exist instanceId', () => {
+      const result = framework.destroyInstance(instanceId)
+      expect(result[instanceId]).to.be.undefined
+    })
+
+    it('with a non-exist instanceId', () => {
+      const result = framework.destroyInstance('123')
+      expect(result).to.be.an.instanceof(Error)
+    })
+  })
+
+  describe('registerComponents', () => {
+    it('with old format', () => {
+      framework.registerComponents(['a', 'b', 'c'])
+      expect(defaultConfig.nativeComponentMap).to.contain.keys('a', 'b', 'c')
+    })
+
+    it('with new format', () => {
+      framework.registerComponents([{
+        type: 'd',
+        append: 'tree'
+      }])
+      expect(defaultConfig.nativeComponentMap).to.contain.keys('d')
+      expect(defaultConfig.nativeComponentMap['d']).to.be.deep.equal({
+        type: 'd',
+        append: 'tree'
+      })
+    })
+
+    it('with non-array', () => {
+      framework.registerComponents({
+        type: 'e'
+      })
+      expect(defaultConfig.nativeComponentMap).not.contain.keys('e')
+    })
+
+    it('with methods', () => {
+      const components = [{
+        type: 'x',
+        methods: ['foo', 'bar']
+      }, {
+        type: 'y',
+        methods: []
+      }, {
+        type: 'z',
+        methods: null
+      }]
+      framework.registerComponents(components)
+      expect(defaultConfig.nativeComponentMap).to.contain.keys('x', 'y', 'z')
+    })
+  })
+
+  describe('register modules', () => {
+    it('with object of modules', () => {
+      clearModules()
+      const modules = {
+        a: [{
+          name: 'b',
+          args: ['string']
+        }]
+      }
+
+      framework.registerModules(modules)
+      expect(getModule('b')).an.object
+      clearModules()
+    })
+  })
+
+  describe('register methods', () => {
+    it('with object of methods', () => {
+      const methods = {
+        a: sinon.spy()
+      }
+
+      framework.registerMethods(methods)
+      expect(Vm.prototype.a).a.function
+      delete Vm.prototype.a
+    })
+  })
+})
+
+describe('config', () => {
+  it('config is an object', () => {
+    init({})
+  })
+})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e13c860/html5/test/unit/runtime/vdom/directive.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/vdom/directive.js b/html5/test/unit/runtime/vdom/directive.js
new file mode 100644
index 0000000..6c9109b
--- /dev/null
+++ b/html5/test/unit/runtime/vdom/directive.js
@@ -0,0 +1,82 @@
+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/runtime/vdom/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/vdom/index.js b/html5/test/unit/runtime/vdom/index.js
new file mode 100644
index 0000000..c79bcf6
--- /dev/null
+++ b/html5/test/unit/runtime/vdom/index.js
@@ -0,0 +1,639 @@
+/*
+ * 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('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] }])
+  })
+})