You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ha...@apache.org on 2018/01/03 07:13:42 UTC

[11/22] incubator-weex git commit: * [jsfm] Adjust the file structure of js framework

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/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
deleted file mode 100644
index a82d23b..0000000
--- a/html5/test/unit/runtime/legacy-framework.js
+++ /dev/null
@@ -1,348 +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)
-    })
-  })
-
-  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)
-    })
-  })
-
-  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/51dd277e/html5/test/unit/runtime/runner/helper.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/runner/helper.js b/html5/test/unit/runtime/runner/helper.js
deleted file mode 100644
index dce81c7..0000000
--- a/html5/test/unit/runtime/runner/helper.js
+++ /dev/null
@@ -1,73 +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 runtime from '../../../../runtime'
-import frameworks from '../../../../frameworks'
-import services from '../../../../services'
-
-const defaultModules = {
-  animation: ['transition'],
-  clipboard: ['getString', 'setString'],
-  dom: ['scrollToElement', 'getComponentRect', 'addRule'],
-  modal: ['alert', 'confirm', 'prompt', 'toast'],
-  navigator: ['push', 'pop'],
-  picker: ['pick', 'pickDate', 'pickTime'],
-  storage: ['setItem', 'getItem', 'removeItem', 'length', 'getAllKeys'],
-  stream: ['fetch'],
-  timer: ['setTimeout', 'setInterval'],
-  WebSocket: ['send', 'close', 'onopen', 'onmessage', 'onclose', 'onerror'],
-  webview: ['goBack', 'goForward', 'reload']
-}
-
-const defaultComponents = [
-  'div', 'text', 'image', 'input', 'a', 'switch', 'scroller', 'list', 'cell',
-  'slider', 'indicator', 'loading', 'refresh', 'textarea', 'web', 'video',
-  'embed', 'richtext'
-]
-
-export function createContext () {
-  const currentConfig = Object.assign({}, runtime.config)
-  currentConfig.frameworks = frameworks
-
-  for (const serviceName in services) {
-    runtime.service.register(serviceName, services[serviceName])
-  }
-
-  const context = runtime.init(currentConfig)
-
-  context.registerModules(defaultModules)
-  context.registerComponents(defaultComponents)
-
-  return context
-}
-
-// execute code and return the generated vdom tree
-export function execute (type, code) {
-  const context = createContext()
-  return new Promise(resolve => {
-    const id = String(Date.now() + Math.random())
-    context.createInstance(id, `
-      // { "framework": "${type}" }
-      ${code}
-    `)
-    setTimeout(() => {
-      resolve(context.getRoot(id))
-    }, 10)
-  })
-}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/runtime/runner/vanilla.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/runner/vanilla.js b/html5/test/unit/runtime/runner/vanilla.js
deleted file mode 100644
index 2bb6226..0000000
--- a/html5/test/unit/runtime/runner/vanilla.js
+++ /dev/null
@@ -1,59 +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 { expect } from 'chai'
-import { execute } from './helper'
-
-describe('Vanilla Examples', () => {
-  it('execute vanilla code', (done) => {
-    execute('Vanilla', `
-      const body = document.createElement('div')
-      document.documentElement.appendChild(body)
-    `).then($root => {
-      expect($root.type).to.be.equal('div')
-    }).then(done)
-  })
-
-  it('instert child nodes', (done) => {
-    execute('Vanilla', `
-      const body = document.createElement('div')
-      body.appendChild(document.createElement('text'))
-      body.appendChild(document.createElement('image'))
-      document.documentElement.appendChild(body)
-    `).then($root => {
-      expect($root.type).to.be.equal('div')
-      expect($root.children[0].type).to.be.equal('text')
-      expect($root.children[1].type).to.be.equal('image')
-    }).then(done)
-  })
-
-  it('add text nodes', (done) => {
-    execute('Vanilla', `
-      const body = document.createElement('div')
-      const text = document.createElement('text')
-      text.setAttr('value', 'whatever')
-      body.appendChild(text)
-      document.documentElement.appendChild(body)
-    `).then($root => {
-      expect($root.type).to.be.equal('div')
-      expect($root.children[0].type).to.be.equal('text')
-      expect($root.children[0].attr.value).to.be.equal('whatever')
-    }).then(done)
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/runtime/runner/vue.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/runner/vue.js b/html5/test/unit/runtime/runner/vue.js
deleted file mode 100644
index bdb0006..0000000
--- a/html5/test/unit/runtime/runner/vue.js
+++ /dev/null
@@ -1,67 +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 { expect } from 'chai'
-import { execute } from './helper'
-import { compile } from 'weex-template-compiler'
-
-function toFunction (content) {
-  return `function () { ${content} }`
-}
-
-function compileAndExecute (template, additional) {
-  const { render, staticRenderFns } = compile(template)
-  return execute('Vue', `
-    new Vue({
-      el: '#root',
-      render: ${toFunction(render)},
-      staticRenderFns: [${staticRenderFns.map(toFunction).join(',')}],
-      ${additional}
-    })
-  `)
-}
-
-describe('Vue Examples', () => {
-  it('execute Vue code', (done) => {
-    execute('Vue', `
-      new Vue({
-        el: 'body',
-        render (h) {
-          return h('div', {}, [h('text', {}, 'Hello World')])
-        }
-      })
-    `).then($root => {
-      expect($root.type).to.be.equal('div')
-      expect($root.children[0].type).to.be.equal('text')
-      expect($root.children[0].attr.value).to.be.equal('Hello World')
-    }).then(done)
-  })
-
-  it('compile and execute', (done) => {
-    compileAndExecute(`
-      <div>
-        <text>Hello World</text>
-      </div>
-    `).then($root => {
-      expect($root.type).to.be.equal('div')
-      expect($root.children[0].type).to.be.equal('text')
-      expect($root.children[0].attr.value).to.be.equal('Hello World')
-    }).then(done)
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/runtime/utils.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/runtime/utils.js b/html5/test/unit/runtime/utils.js
deleted file mode 100644
index 6480705..0000000
--- a/html5/test/unit/runtime/utils.js
+++ /dev/null
@@ -1,41 +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 { expect } from 'chai'
-import * as utils from '../../../runtime/utils'
-
-describe('utils', () => {
-  it('isEmpty', () => {
-    expect(utils.isEmpty()).to.be.true
-    expect(utils.isEmpty(0)).to.be.true
-    expect(utils.isEmpty(null)).to.be.true
-    expect(utils.isEmpty(undefined)).to.be.true
-    expect(utils.isEmpty(false)).to.be.true
-    expect(utils.isEmpty(true)).to.be.true
-    expect(utils.isEmpty(NaN)).to.be.true
-    expect(utils.isEmpty([])).to.be.true
-    expect(utils.isEmpty({})).to.be.true
-    expect(utils.isEmpty(Object.create(null))).to.be.true
-    expect(utils.isEmpty(Object.create({}))).to.be.true
-    expect(utils.isEmpty(Object.create({ x: '' }))).to.be.true
-
-    expect(utils.isEmpty({ abc: '' })).to.be.false
-    expect(utils.isEmpty([0])).to.be.false
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/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
deleted file mode 100644
index 5270014..0000000
--- a/html5/test/unit/runtime/vdom/index.js
+++ /dev/null
@@ -1,639 +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.handler).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] }])
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/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
deleted file mode 100644
index 1eab8d5..0000000
--- a/html5/test/unit/runtime/vdom/listener.js
+++ /dev/null
@@ -1,381 +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('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/51dd277e/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
deleted file mode 100644
index b05d277..0000000
--- a/html5/test/unit/runtime/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/51dd277e/html5/test/unit/shared/BroadcastChannel.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/BroadcastChannel.js b/html5/test/unit/shared/BroadcastChannel.js
deleted file mode 100644
index 880ed6b..0000000
--- a/html5/test/unit/shared/BroadcastChannel.js
+++ /dev/null
@@ -1,231 +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 { expect } from 'chai'
-import sinon from 'sinon'
-
-import service from '../../../services/broadcast-channel/index'
-import { MessageEvent } from '../../../services/broadcast-channel/message-event'
-const { BroadcastChannel } = service.create('foo').instance
-
-describe('BroadcastChannel', () => {
-  it('is a function', () => {
-    expect(BroadcastChannel).is.an('function')
-  })
-
-  it('has standard APIs', () => {
-    const JamesBond = new BroadcastChannel('007')
-    expect(JamesBond.name).is.an('string')
-    expect(JamesBond.onmessage).is.an('null')
-    expect(JamesBond.postMessage).is.an('function')
-    expect(JamesBond.close).is.an('function')
-
-    expect(JamesBond).to.have.ownProperty('name')
-    expect(JamesBond).to.have.ownProperty('onmessage')
-    expect(JamesBond).not.to.have.ownProperty('postMessage')
-    expect(JamesBond).not.to.have.ownProperty('close')
-    JamesBond.close()
-  })
-
-  it('name attribute is readonly', () => {
-    const Wolverine = new BroadcastChannel('Logan')
-    expect(Wolverine.name).to.equal('Logan')
-    Wolverine.name = 'Wolverine'
-    expect(Wolverine.name).to.equal('Logan')
-    Wolverine.close()
-  })
-
-  describe('basci usage', () => {
-    const Hulk = new BroadcastChannel('Avengers')
-    const Stack = new BroadcastChannel('Avengers')
-    const Steven = new BroadcastChannel('Avengers')
-    const Logan = new BroadcastChannel('Mutants')
-    const Erik = new BroadcastChannel('Mutants')
-
-    beforeEach(() => {
-      Hulk.onmessage = sinon.spy()
-      Stack.onmessage = sinon.spy()
-      Steven.onmessage = sinon.spy()
-      Logan.onmessage = sinon.spy()
-    })
-
-    afterEach(() => {
-      Hulk.onmessage = null
-      Stack.onmessage = null
-      Steven.onmessage = null
-      Logan.onmessage = null
-      Erik.onmessage = null
-    })
-
-    it('trigger onmessage', () => {
-      Hulk.postMessage('Hulk Smash !!!')
-      expect(Hulk.onmessage.callCount).to.be.equal(0)
-      expect(Logan.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(1)
-      expect(Steven.onmessage.callCount).to.be.equal(1)
-    })
-
-    it('don\'t trigger onmessage itself', () => {
-      Logan.postMessage('Any one here ?')
-      expect(Hulk.onmessage.callCount).to.be.equal(0)
-      expect(Logan.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(0)
-      expect(Steven.onmessage.callCount).to.be.equal(0)
-    })
-
-    it('send multi messages', () => {
-      Hulk.postMessage('Hulk Smash !!!')
-      Logan.postMessage('I will fight you !')
-      Stack.postMessage('whatever')
-      Hulk.postMessage('whatever')
-      Stack.postMessage('whatever')
-      Steven.postMessage('whatever')
-      Stack.postMessage('whatever')
-
-      expect(Hulk.onmessage.callCount).to.be.equal(4)
-      expect(Logan.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(3)
-      expect(Steven.onmessage.callCount).to.be.equal(5)
-    })
-
-    it('send string message', () => {
-      Stack.postMessage('I am Iron-Man.')
-
-      expect(Hulk.onmessage.callCount).to.be.equal(1)
-      expect(Steven.onmessage.callCount).to.be.equal(1)
-
-      const event = Hulk.onmessage.firstCall.args[0]
-      expect(event).is.an('object')
-      expect(event.data).is.a('string')
-      expect(event.data).to.be.equal('I am Iron-Man.')
-    })
-
-    it('send object message', () => {
-      const message = {
-        type: 'SOKOVIA ACCORDS',
-        approvedCountry: 117,
-        content: 'The Avengers shall no longer be a private organization.'
-      }
-
-      Stack.postMessage(message)
-
-      const event = Steven.onmessage.firstCall.args[0]
-      expect(event).is.an('object')
-      expect(event.data).is.a('object')
-      expect(event.data).to.deep.equal(message)
-    })
-
-    it('close channel', () => {
-      Hulk.close()
-
-      Steven.postMessage('come to fight !')
-      expect(Hulk.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(1)
-      expect(Steven.onmessage.callCount).to.be.equal(0)
-    })
-
-    it('send message after close', () => {
-      Hulk.close()
-
-      expect(() => { Hulk.postMessage('I am leaving.') }).to.throw(Error)
-
-      expect(Hulk.onmessage.callCount).to.be.equal(0)
-      expect(Logan.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(0)
-      expect(Steven.onmessage.callCount).to.be.equal(0)
-    })
-
-    it('MessageEvent dafault parameters', () => {
-      const event = new MessageEvent()
-
-      expect(event).is.an('object')
-      expect(event.data).to.be.null
-      expect(event.type).to.be.equal('message')
-      expect(event.origin).to.be.equal('')
-      expect(event.target).to.be.null
-      expect(event.source).to.be.null
-      expect(event.timeStamp).to.be.a('number')
-      expect(event.ports).to.be.an('array')
-    })
-
-    it('MessageEvent constructor', () => {
-      const source = { type: 'empty' }
-      const event = new MessageEvent('custom', {
-        source,
-        data: 'Nothing',
-        origin: 'http://127.0.0.1',
-        ports: ['8080']
-      })
-
-      expect(event).is.an('object')
-      expect(event.data).to.be.equal('Nothing')
-      expect(event.type).to.be.equal('custom')
-      expect(event.origin).to.be.equal('http://127.0.0.1')
-      expect(event.target).to.be.null
-      expect(event.source).to.deep.equal(source)
-      expect(event.timeStamp).to.be.a('number')
-      expect(event.ports).to.deep.equal(['8080'])
-    })
-
-    it('use MessageEvent', () => {
-      Steven.postMessage('Be Together.')
-
-      const event = Stack.onmessage.firstCall.args[0]
-      expect(event).is.an('object')
-      expect(event.data).to.be.equal('Be Together.')
-      expect(event.type).to.be.equal('message')
-      expect(event.origin).to.be.equal('')
-      expect(event.target).to.be.null
-      expect(event.timeStamp).to.be.a('number')
-    })
-
-    it('invalid usage', () => {
-      const stranger = {
-        name: 'stranger',
-        close: Erik.close,
-        postMessage: Erik.postMessage
-      }
-
-      stranger.postMessage('hello world.')
-
-      expect(Hulk.onmessage.callCount).to.be.equal(0)
-      expect(Logan.onmessage.callCount).to.be.equal(0)
-      expect(Stack.onmessage.callCount).to.be.equal(0)
-      expect(Steven.onmessage.callCount).to.be.equal(0)
-
-      stranger.close()
-    })
-
-    it('close all', () => {
-      Hulk.close()
-      Stack.close()
-      Steven.close()
-      Logan.close()
-      Erik.close()
-
-      // close again
-      expect(() => {
-        Hulk.close()
-        Stack.close()
-        Steven.close()
-        Logan.close()
-        Erik.close()
-      }).to.not.throw
-    })
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/shared/arrayFrom.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/arrayFrom.js b/html5/test/unit/shared/arrayFrom.js
deleted file mode 100644
index 99e9495..0000000
--- a/html5/test/unit/shared/arrayFrom.js
+++ /dev/null
@@ -1,90 +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
-
-// remove original Array.from
-// Array.from = null
-
-import '../../../shared/arrayFrom'
-
-/* eslint-disable */
-describe('Array.from', () => {
-  it('is a function', () => {
-    expect(Array.from).is.an('function')
-  })
-
-  it('requires an array-like object', () => {
-    expect(() => Array.from()).to.throw(TypeError)
-    expect(() => Array.from(null)).to.throw(TypeError)
-	})
-
-  it('throws with invalid lengths', () => {
-    expect(() => Array.from({ 'length': Infinity })).to.throw(RangeError)
-    expect(() => Array.from({ 'length': Math.pow(2, 32) })).to.throw(RangeError)
-	})
-
-  it('swallows negative lengths', () => {
-    expect(Array.from({ length: -1 }).length).to.equal(0)
-    expect(Array.from({ length: -0 }).length).to.equal(0)
-    expect(Array.from({ length: -Infinity }).length).to.equal(0)
-	})
-
-  it('works with primitives', () => {
-    expect(Array.from(false)).to.deep.equal([])
-    expect(Array.from(true)).to.deep.equal([])
-    expect(Array.from(0)).to.deep.equal([])
-    expect(Array.from(-0)).to.deep.equal([])
-    expect(Array.from(1)).to.deep.equal([])
-    expect(Array.from(-1)).to.deep.equal([])
-    expect(Array.from(Infinity)).to.deep.equal([])
-    expect(Array.from(-Infinity)).to.deep.equal([])
-	})
-
-  it('works with primitive strings', () => {
-    expect(Array.from('')).to.deep.equal([])
-    expect(Array.from('abc')).to.deep.equal(['a', 'b', 'c'])
-    expect(Array.from('a\u5F20\u7FF0')).to.deep.equal(['a', '\u5F20', '\u7FF0'])
-    expect(Array.from('x\uD834\uDF06Y')).to.deep.equal(['x', '\uD834\uDF06', 'Y'])
-	})
-
-  it('works with objects', () => {
-    expect(Array.from({})).to.deep.equal([])
-    expect(Array.from({ name: 'abc' })).to.deep.equal([])
-  })
-
-  it('works with arrays', () => {
-    expect(Array.from([])).to.deep.equal([])
-    expect(Array.from(['a', 2, false, {}])).to.deep.equal(['a', 2, false, {}])
-  })
-
-  it('throws with an invalid mapping function', () => {
-    expect(() => Array.from([], null)).to.throw(TypeError)
-    expect(() => Array.from([], false)).to.throw(TypeError)
-    expect(() => Array.from([], 'true')).to.throw(TypeError)
-    expect(() => Array.from([], 42)).to.throw(TypeError)
-    expect(() => Array.from([], {})).to.throw(TypeError)
-    expect(() => Array.from([], [])).to.throw(TypeError)
-	})
-
-  it('works with mapping function', () => {
-    expect(Array.from([1, 2, 3], n => n * n)).to.deep.equal([1, 4, 9])
-    expect(Array.from('abc', x => x.toUpperCase())).to.deep.equal(['A', 'B', 'C'])
-	})
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/shared/console.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/console.js b/html5/test/unit/shared/console.js
deleted file mode 100644
index 60eb281..0000000
--- a/html5/test/unit/shared/console.js
+++ /dev/null
@@ -1,224 +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 { setNativeConsole, resetNativeConsole } from '../../../shared/console'
-
-const oriEnv = global.WXEnvironment
-const oriConsole = global.console
-
-describe.skip('polyfill for console', () => {
-  const scope = {}
-  const nativeLogSpy = sinon.spy()
-
-  before(() => {
-    delete global.console
-    global.nativeLog = function (...args) {
-      nativeLogSpy(...args)
-    }
-    global.WXEnvironment = {
-      platform: 'iOS',
-      logLevel: 'log'
-    }
-    setNativeConsole()
-    scope.console = global.console
-    // global.console = oriConsole // no output for these test case
-  })
-
-  after(() => {
-    global.WXEnvironment = oriEnv
-    resetNativeConsole()
-    expect(global.console).eql(oriConsole)
-  })
-
-  beforeEach(() => {
-    nativeLogSpy.reset()
-  })
-
-  it('export apis', () => {
-    expect(setNativeConsole).is.a('function')
-    expect(resetNativeConsole).is.a('function')
-  })
-
-  it('nativeLog', () => {
-    expect(global.nativeLog).is.a('function')
-    global.nativeLog('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-  })
-
-  it('console apis', () => {
-    expect(scope.console).is.a('object')
-    expect(scope.console.debug).is.a('function')
-    expect(scope.console.log).is.a('function')
-    expect(scope.console.info).is.a('function')
-    expect(scope.console.warn).is.a('function')
-    expect(scope.console.error).is.a('function')
-  })
-
-  it('no debug message', () => {
-    scope.console.debug('a debug message')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-  })
-
-  it('a log message', () => {
-    scope.console.log('a log message')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    expect(nativeLogSpy.firstCall.args).to.deep.equal(
-      ['a log message', '__LOG']
-    )
-  })
-
-  it('multi log message', () => {
-    scope.console.log('A', 'B', 'C')
-    scope.console.log('D', 'E')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-    expect(nativeLogSpy.firstCall.args).to.deep.equal(
-      ['A', 'B', 'C', '__LOG']
-    )
-    expect(nativeLogSpy.lastCall.args).to.deep.equal(
-      ['D', 'E', '__LOG']
-    )
-  })
-
-  it('an info message', () => {
-    scope.console.info('a info message')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    expect(nativeLogSpy.firstCall.args).to.deep.equal(
-      ['a info message', '__INFO']
-    )
-  })
-
-  it('a warn message', () => {
-    scope.console.warn('a warn message')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    expect(nativeLogSpy.firstCall.args).eql(
-      ['a warn message', '__WARN']
-    )
-  })
-
-  it('a error message', () => {
-    scope.console.error('a error message')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    expect(nativeLogSpy.firstCall.args).eql(
-      ['a error message', '__ERROR']
-    )
-  })
-
-  it('debug logLevel', () => {
-    global.WXEnvironment.logLevel = 'debug'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(3)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(4)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(5)
-  })
-
-  it('log logLevel', () => {
-    global.WXEnvironment.logLevel = 'log'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(3)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(4)
-  })
-
-  it('info logLevel', () => {
-    global.WXEnvironment.logLevel = 'info'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(3)
-  })
-
-  it('warn logLevel', () => {
-    global.WXEnvironment.logLevel = 'warn'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-  })
-
-  it('error logLevel', () => {
-    global.WXEnvironment.logLevel = 'error'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-  })
-
-  it('off logLevel', () => {
-    global.WXEnvironment.logLevel = 'off'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-  })
-
-  it('unknown logLevel', () => {
-    global.WXEnvironment.logLevel = 'log'
-    scope.console.debug('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(0)
-    scope.console.log('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(1)
-    scope.console.info('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(2)
-    scope.console.warn('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(3)
-    scope.console.error('whatever')
-    expect(nativeLogSpy.callCount).to.be.equal(4)
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/shared/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/index.js b/html5/test/unit/shared/index.js
deleted file mode 100644
index 337bdf1..0000000
--- a/html5/test/unit/shared/index.js
+++ /dev/null
@@ -1,73 +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 shared from '../../../shared'
-
-describe('a polyfill of', () => {
-  it('Promise', () => {
-    expect(typeof Promise).to.be.equal('function')
-    expect(() => {
-      new Promise(sinon.spy()).then(sinon.spy())
-      Promise.all()
-      Promise.race()
-      Promise.resolve()
-      Promise.reject()
-    }).to.not.throw
-  })
-
-  it('Object.assign', () => {
-    expect(typeof Object.assign).to.be.equal('function')
-  })
-
-  it('setTimeout', () => {
-    expect(typeof setTimeout).to.be.equal('function')
-  })
-
-  it('console.log', () => {
-    expect(typeof console.log).to.be.equal('function')
-  })
-})
-
-describe('freeze the prototype of build-in objects', function () {
-  before(() => {
-    shared.freezePrototype()
-  })
-
-  it('Object & Object.prototype', () => {
-    expect(Object).to.be.frozen
-    // expect(Object.prototype).to.be.frozen
-  })
-  it('Array & Array.prototype', () => {
-    expect(Array).to.be.frozen
-    expect(Array.prototype).to.be.frozen
-  })
-
-  it('String.prototype', () => { expect(String.prototype).to.be.frozen })
-  it('Number.prototype', () => { expect(Number.prototype).to.be.frozen })
-  it('Boolean.prototype', () => { expect(Boolean.prototype).to.be.frozen })
-  it('Error.prototype', () => { expect(Error.prototype).to.be.frozen })
-  it('Date.prototype', () => { expect(Date.prototype).to.be.frozen })
-  it('Math.prototype', () => { expect(Math.prototype).to.be.frozen })
-  it('RegExp.prototype', () => { expect(RegExp.prototype).to.be.frozen })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/shared/objectAssign.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/objectAssign.js b/html5/test/unit/shared/objectAssign.js
deleted file mode 100644
index 7c76a4a..0000000
--- a/html5/test/unit/shared/objectAssign.js
+++ /dev/null
@@ -1,50 +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 '../../../shared/objectAssign'
-
-describe('object.assign', () => {
-  it('is a function', () => {
-    expect(Object.assign).is.an('function')
-  })
-
-  it('source to taget', () => {
-    const target = {
-      a: 'a',
-      b: 'b'
-    }
-    const src1 = {
-      b: 'bb',
-      c: 'c'
-    }
-    const src2 = {
-      d: 'd',
-      a: 'aa'
-    }
-    Object.assign(target, src1, src2)
-    expect(target).to.deep.equal({
-      a: 'aa',
-      b: 'bb',
-      c: 'c',
-      d: 'd'
-    })
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/shared/objectSetPrototypeOf.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/objectSetPrototypeOf.js b/html5/test/unit/shared/objectSetPrototypeOf.js
deleted file mode 100644
index 58056bc..0000000
--- a/html5/test/unit/shared/objectSetPrototypeOf.js
+++ /dev/null
@@ -1,42 +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 '../../../shared/objectSetPrototypeOf'
-
-/* eslint-disable */
-describe('Object.setPrototypeOf', () => {
-  it('is a function', () => {
-    expect(Object.setPrototypeOf).is.an('function')
-  })
-
-  it('be able to set prototype', () => {
-    const JonSnow = { name: 'Jon Snow' }
-    Object.setPrototypeOf(JonSnow, {
-      know: function() { return 'nothing' }
-    })
-
-    expect(Object.hasOwnProperty.call(JonSnow, 'name')).to.be.true
-    expect(Object.hasOwnProperty.call(JonSnow, 'know')).to.be.false
-
-    expect(JonSnow.know()).to.equal('nothing')
-
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/html5/test/unit/vanilla/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vanilla/index.js b/html5/test/unit/vanilla/index.js
deleted file mode 100644
index 6389c4c..0000000
--- a/html5/test/unit/vanilla/index.js
+++ /dev/null
@@ -1,159 +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 { expect } from 'chai'
-
-import vanilla from '../../../frameworks/vanilla'
-import runtime from '../../../runtime'
-
-// clear ref property in vdom
-function clearRefs (json) {
-  delete json.ref
-  if (json.children) {
-    json.children.forEach(clearRefs)
-  }
-}
-
-describe('vanilla test', () => {
-  it('standard APIs', () => {
-    expect(vanilla.init).to.be.a('function')
-    expect(vanilla.createInstance).to.be.a('function')
-    expect(vanilla.destroyInstance).to.be.a('function')
-    expect(vanilla.getRoot).to.be.a('function')
-    expect(vanilla.receiveTasks).to.be.a('function')
-  })
-
-  it('create & destroy instance', () => {
-    const id = 'basic-demo'
-    vanilla.init(runtime.config)
-    vanilla.createInstance(id, `
-      var body = document.createBody()
-      var div = document.createElement('div')
-      body.appendChild(div)
-    `, {})
-    vanilla.destroyInstance(id)
-  })
-
-  it('getRoot', () => {
-    const id = 'sample-demo'
-    const code = `
-      var body = document.createBody()
-      var div = document.createElement('div')
-      div.setStyle('color', 'red')
-      var span = document.createElement('span')
-      span.setAttr('value', 'text node')
-      div.appendChild(span)
-      body.appendChild(div)
-    `
-    vanilla.init(runtime.config)
-    vanilla.createInstance(id, code, {})
-
-    const vdom = vanilla.getRoot(id)
-    clearRefs(vdom)
-    expect(vdom).to.deep.equal({
-      // ref: '_root',
-      type: 'div',
-      attr: {},
-      style: {},
-      children: [
-        {
-          // ref: '8',
-          type: 'div',
-          attr: {},
-          style: {
-            color: 'red'
-          },
-          children: [
-            {
-              // ref: '9',
-              type: 'span',
-              attr: {
-                value: 'text node'
-              },
-              style: {}
-            }
-          ]
-        }
-      ]
-    })
-
-    vanilla.destroyInstance(id)
-  })
-
-  describe('receiveTasks', () => {
-    const id = 'task-demo'
-
-    before(() => {
-      vanilla.init(runtime.config)
-      vanilla.createInstance(id, `
-        var body = document.createBody()
-        body.addEvent('click', function() {
-          this.setStyle('width', '200')
-        })
-        document.addCallback(function(message) {
-          body.setAttr('from', message)
-        })
-        `, {})
-    })
-
-    after(() => {
-      vanilla.destroyInstance(id)
-    })
-
-    it('initial state', () => {
-      // initial style and attr in empty
-      expect(vanilla.getRoot(id).style).to.deep.equal({})
-      expect(vanilla.getRoot(id).attr).to.deep.equal({})
-
-      // empty task
-      vanilla.receiveTasks(id, [])
-    })
-
-    it('invalid tasks', () => {
-      vanilla.receiveTasks('invalid id', [])
-      vanilla.receiveTasks(id, {})
-      vanilla.receiveTasks(id, [{
-        method: 'whatever',
-        args: []
-      }])
-    })
-
-    it('fireEvent', () => {
-      vanilla.receiveTasks(id, [{
-        method: 'fireEvent',
-        args: ['_root', 'click']
-      }])
-      expect(vanilla.getRoot(id).style).to.deep.equal({ width: '200' })
-    })
-
-    it('callback', () => {
-      vanilla.receiveTasks(id, [{
-        method: 'callback',
-        args: ['1', 'callback']
-      }])
-      expect(vanilla.getRoot(id).attr).to.deep.equal({ from: 'callback' })
-
-      // last callback
-      vanilla.receiveTasks(id, [{
-        method: 'callback',
-        args: ['1', 'last message', true]
-      }])
-      expect(vanilla.getRoot(id).attr).to.deep.equal({ from: 'last message' })
-    })
-  })
-})

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/51dd277e/runtime/api/WeexInstance.js
----------------------------------------------------------------------
diff --git a/runtime/api/WeexInstance.js b/runtime/api/WeexInstance.js
new file mode 100644
index 0000000..3bc25e6
--- /dev/null
+++ b/runtime/api/WeexInstance.js
@@ -0,0 +1,138 @@
+/*
+ * 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 Document from '../vdom/Document'
+import { isRegisteredModule, getModuleDescription } from './module'
+import { isRegisteredComponent } from './component'
+import { getTaskCenter } from '../vdom/operation'
+
+const moduleProxies = {}
+
+function setId (weex, id) {
+  Object.defineProperty(weex, '[[CurrentInstanceId]]', { value: id })
+}
+
+function getId (weex) {
+  return weex['[[CurrentInstanceId]]']
+}
+
+function moduleGetter (id, module, method) {
+  const taskCenter = getTaskCenter(id)
+  if (!taskCenter || typeof taskCenter.send !== 'function') {
+    console.error(`[JS Framework] Failed to find taskCenter (${id}).`)
+    return null
+  }
+  return (...args) => taskCenter.send('module', { module, method }, args)
+}
+
+function moduleSetter (id, module, method, fn) {
+  const taskCenter = getTaskCenter(id)
+  if (!taskCenter || typeof taskCenter.send !== 'function') {
+    console.error(`[JS Framework] Failed to find taskCenter (${id}).`)
+    return null
+  }
+  if (typeof fn !== 'function') {
+    console.error(`[JS Framework] ${module}.${method} must be assigned as a function.`)
+    return null
+  }
+  return fn => taskCenter.send('module', { module, method }, [fn])
+}
+
+export default class WeexInstance {
+  constructor (id, config) {
+    setId(this, String(id))
+    this.config = config || {}
+    this.document = new Document(id, this.config.bundleUrl)
+    this.requireModule = this.requireModule.bind(this)
+    this.isRegisteredModule = isRegisteredModule
+    this.isRegisteredComponent = isRegisteredComponent
+  }
+
+  requireModule (moduleName) {
+    const id = getId(this)
+    if (!(id && this.document && this.document.taskCenter)) {
+      console.error(`[JS Framework] Failed to requireModule("${moduleName}"), `
+        + `instance (${id}) doesn't exist anymore.`)
+      return
+    }
+
+    // warn for unknown module
+    if (!isRegisteredModule(moduleName)) {
+      console.warn(`[JS Framework] using unregistered weex module "${moduleName}"`)
+      return
+    }
+
+    // create new module proxy
+    const proxyName = `${moduleName}#${id}`
+    if (!moduleProxies[proxyName]) {
+      // create registered module apis
+      const moduleDefine = getModuleDescription(moduleName)
+      const moduleApis = {}
+      for (const methodName in moduleDefine) {
+        Object.defineProperty(moduleApis, methodName, {
+          enumerable: true,
+          configurable: true,
+          get: () => moduleGetter(id, moduleName, methodName),
+          set: fn => moduleSetter(id, moduleName, methodName, fn)
+        })
+      }
+
+      // create module Proxy
+      if (typeof Proxy === 'function') {
+        moduleProxies[proxyName] = new Proxy(moduleApis, {
+          get (target, methodName) {
+            if (methodName in target) {
+              return target[methodName]
+            }
+            console.warn(`[JS Framework] using unregistered method "${moduleName}.${methodName}"`)
+            return moduleGetter(id, moduleName, methodName)
+          }
+        })
+      }
+      else {
+        moduleProxies[proxyName] = moduleApis
+      }
+    }
+
+    return moduleProxies[proxyName]
+  }
+
+  supports (condition) {
+    if (typeof condition !== 'string') return null
+
+    const res = condition.match(/^@(\w+)\/(\w+)(\.(\w+))?$/i)
+    if (res) {
+      const type = res[1]
+      const name = res[2]
+      const method = res[4]
+      switch (type) {
+        case 'module': return isRegisteredModule(name, method)
+        case 'component': return isRegisteredComponent(name)
+      }
+    }
+
+    return null
+  }
+
+  // registerStyleSheet (styles) {
+  //   if (this.document) {
+  //     this.document.registerStyleSheet(styles)
+  //   }
+  // }
+}