| /* |
| * 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] }]) |
| }) |
| }) |