| /* |
| * 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 Vm from '../../../../../runtime/frameworks/legacy/vm' |
| import { Document } from '../../../../../runtime/vdom' |
| import { init as resetTaskHandler } from '../../../../../runtime/bridge/TaskCenter' |
| import Differ from '../../../../../runtime/frameworks/legacy/app/differ' |
| |
| const oriCallNative = global.callNative |
| |
| describe('generate virtual dom for a single vm', () => { |
| const spy = sinon.spy() |
| const spy1 = sinon.spy() |
| let doc |
| let customComponentMap |
| let differ |
| |
| beforeEach(() => { |
| differ = new Differ('test') |
| doc = new Document('test', '', function (actions) { |
| actions.forEach((action) => { |
| spy.apply(null, ['test', action.method].concat(action.args)) |
| }) |
| }) |
| customComponentMap = {} |
| }) |
| |
| afterEach(() => { |
| spy.reset() |
| spy1.reset() |
| doc.destroy() |
| }) |
| |
| it('$watch', () => { |
| const data = { |
| a: { |
| b: 1 |
| } |
| } |
| |
| customComponentMap.foo = { |
| template: { |
| type: 'container' |
| }, |
| data: data |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(doc.body).is.an.object |
| |
| vm.$watch(function () { |
| return this.a.b |
| }, (value) => { |
| expect(value).eql(2) |
| }) |
| |
| data.a.b = 2 |
| }) |
| |
| it('vm.data is not a object', () => { |
| const data = 'hello' |
| |
| customComponentMap.foo = { |
| template: { |
| type: 'container' |
| }, |
| data: data |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(doc.body).is.an.object |
| }) |
| |
| it('no param parentVm', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container' |
| } |
| } |
| |
| const vm = new Vm('foo', customComponentMap.foo, null) |
| |
| expect(vm._app).is.an.object |
| expect(doc.body).is.an.object |
| }) |
| |
| it('no param options', () => { |
| const app = {} |
| const vm = new Vm('foo', null, { _app: app }) |
| |
| expect(vm._app).is.an.object |
| expect(doc.body).is.an.object |
| }) |
| |
| it('old method.ready', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container' |
| }, |
| methods: { |
| ready: spy1 |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(doc.body).is.an.object |
| expect(doc.body.type).eql('container') |
| expect(spy1).callCount(1) |
| }) |
| |
| it('generate an static element ', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| a: 1, |
| b: 2, |
| static: '' |
| }, |
| style: { |
| c: 3, |
| d: 4 |
| } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm._static).eql(true) |
| expect(doc.body).is.an.object |
| expect(doc.body.type).eql('container') |
| expect(doc.body.attr).eql({ a: 1, b: 2, static: '' }) |
| expect(doc.body.style).eql({ c: 3, d: 4 }) |
| expect(doc.body.children).is.an.array |
| expect(doc.body.children.length).eql(0) |
| }) |
| |
| it('generate an single element', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| a: 1, |
| b: 2 |
| }, |
| style: { |
| c: 3, |
| d: 4 |
| } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(doc.body).is.an.object |
| expect(doc.body.type).eql('container') |
| expect(doc.body.attr).eql({ a: 1, b: 2 }) |
| expect(doc.body.style).eql({ c: 3, d: 4 }) |
| expect(doc.body.children).is.an.array |
| expect(doc.body.children.length).eql(0) |
| }) |
| |
| it('generate an element tree', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', attr: { a: 1, b: 2 }, style: { c: 3, d: 4 }, |
| children: [ |
| { type: 'image', attr: { src: '<some image url>' }}, |
| { type: 'text', attr: { value: '<some text content>' }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.attr).eql({ a: 1, b: 2 }) |
| expect(el.style).eql({ c: 3, d: 4 }) |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(2) |
| |
| const image = el.children[0] |
| const text = el.children[1] |
| expect(image.type).eql('image') |
| expect(image.attr).eql({ src: '<some image url>' }) |
| expect(text.type).eql('text') |
| expect(text.attr).eql({ value: '<some text content>' }) |
| }) |
| |
| it('generate an element tree with component options', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'cell', |
| children: [ |
| { type: 'text', attr: { value: '<some text content>' }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(spy.firstCall.args[0]).to.be.equal('test') |
| expect(spy.firstCall.args[1]).to.be.equal('createBody') |
| expect(spy.firstCall.args[2]).to.deep.equal({ |
| ref: '_root', |
| type: 'cell', |
| attr: { |
| append: 'tree' |
| }, |
| children: [{ |
| ref: spy.firstCall.args[2].children[0].ref, |
| type: 'text', |
| attr: { |
| value: '<some text content>' |
| }, |
| style: {} |
| }], |
| style: {} |
| }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('cell') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const text = el.children[0] |
| expect(text.type).eql('text') |
| expect(text.attr).eql({ value: '<some text content>' }) |
| }) |
| |
| it('generate an element tree with data binding', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', attr: { a: 1, b: 2 }, style: { c: 3, d: 4 }, |
| children: [ |
| { type: 'image', attr: { src: function () { return this.x } }}, |
| { type: 'text', attr: { value: function () { return this.n } }}, |
| { type: 'text', attr: { value: function () { return this.m } }} |
| ] |
| }, |
| data: { |
| x: '<some image url>', y: '<some text content>' |
| }, |
| computed: { |
| n: function () { |
| return this.y.toUpperCase() |
| }, |
| m: { |
| get: function () { |
| return this.y.toUpperCase() |
| }, |
| set: function (v) { |
| this.y = v |
| } |
| } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.x).eql('<some image url>') |
| expect(vm.y).eql('<some text content>') |
| expect(vm.n).eql('<SOME TEXT CONTENT>') |
| expect(vm.m).eql('<SOME TEXT CONTENT>') |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.attr).eql({ a: 1, b: 2 }) |
| expect(el.style).eql({ c: 3, d: 4 }) |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(3) |
| |
| const image = el.children[0] |
| const text = el.children[1] |
| const text2 = el.children[2] |
| expect(image.type).eql('image') |
| expect(image.attr).eql({ src: '<some image url>' }) |
| expect(text.type).eql('text') |
| expect(text.attr).eql({ value: '<SOME TEXT CONTENT>' }) |
| expect(text2.type).eql('text') |
| expect(text2.attr).eql({ value: '<SOME TEXT CONTENT>' }) |
| |
| vm.x = '<some image url>' |
| differ.flush() |
| expect(el).equal(doc.body) |
| expect(image).equal(el.children[0]) |
| expect(text).equal(el.children[1]) |
| expect(text2).equal(el.children[2]) |
| |
| vm.x = 'other string value' |
| differ.flush() |
| expect(el).equal(doc.body) |
| expect(image).equal(el.children[0]) |
| expect(image.attr).eql({ src: 'other string value' }) |
| |
| vm.y = 'other string value' |
| differ.flush() |
| expect(el).equal(doc.body) |
| expect(text).equal(el.children[1]) |
| expect(text.attr).eql({ value: 'OTHER STRING VALUE' }) |
| expect(text2).equal(el.children[2]) |
| expect(text2.attr).eql({ value: 'OTHER STRING VALUE' }) |
| |
| vm.m = 'third string value' |
| differ.flush() |
| expect(vm.x).eql('other string value') |
| expect(vm.y).eql('third string value') |
| expect(vm.n).eql('THIRD STRING VALUE') |
| expect(vm.m).eql('THIRD STRING VALUE') |
| expect(el).equal(doc.body) |
| expect(text).equal(el.children[1]) |
| expect(text.attr).eql({ value: 'THIRD STRING VALUE' }) |
| expect(text2).equal(el.children[2]) |
| expect(text2.attr).eql({ value: 'THIRD STRING VALUE' }) |
| }) |
| |
| it('generate an element tree with shown', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'prev' }, |
| { |
| shown: function () { return this.y }, |
| type: 'image', attr: { src: function () { return this.x } } |
| }, |
| { type: 'next' } |
| ] |
| }, |
| data: { |
| x: '<some image url>', y: true |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.x).eql('<some image url>') |
| expect(vm.y).eql(true) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(5) |
| |
| const prev = el.children[0] |
| const starter = el.children[1] |
| const image = el.children[2] |
| const ender = el.children[3] |
| const next = el.children[4] |
| expect(prev.type).eql('prev') |
| expect(starter.type).eql('comment') |
| expect(ender.type).eql('comment') |
| expect(next.type).eql('next') |
| expect(image.type).eql('image') |
| expect(image.attr).eql({ src: '<some image url>' }) |
| |
| vm.y = false |
| differ.flush() |
| |
| expect(el).equal(doc.body) |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(4) |
| expect(prev).equal(el.children[0]) |
| expect(starter).equal(el.children[1]) |
| expect(ender).equal(el.children[2]) |
| expect(next).equal(el.children[3]) |
| |
| vm.y = true |
| differ.flush() |
| |
| expect(el).equal(doc.body) |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(5) |
| expect(prev).equal(el.children[0]) |
| expect(starter).equal(el.children[1]) |
| |
| const image2 = el.children[2] |
| expect(image2.type).eql('image') |
| expect(image2.attr).eql({ src: '<some image url>' }) |
| expect(ender).equal(el.children[3]) |
| expect(next).equal(el.children[4]) |
| }) |
| |
| it('generate an element tree with repeat', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'prev' }, |
| { |
| repeat: function () { return this.list }, |
| type: 'image', attr: { src: function () { return this.x } } |
| }, |
| { type: 'next' } |
| ] |
| }, |
| data: { |
| x: '<some image url>', |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.x).eql('<some image url>') |
| expect(vm.list).eql([ |
| { uid: 1, x: 1, $index: 0 }, |
| { uid: 2, x: 2, $index: 1 }, |
| { uid: 3, $index: 2 }]) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(7) |
| |
| const prev = el.children[0] |
| const starter = el.children[1] |
| const ender = el.children[5] |
| const next = el.children[6] |
| expect(prev.type).eql('prev') |
| expect(starter.type).eql('comment') |
| expect(ender.type).eql('comment') |
| expect(next.type).eql('next') |
| |
| expect(el.children[2].type).eql('image') |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].type).eql('image') |
| expect(el.children[3].attr).eql({ src: 2 }) |
| expect(el.children[4].type).eql('image') |
| expect(el.children[4].attr).eql({ src: '<some image url>' }) |
| |
| vm.list[1].x = 3 |
| differ.flush() |
| expect(el.children.length).eql(7) |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].attr).eql({ src: 3 }) |
| expect(el.children[4].attr).eql({ src: '<some image url>' }) |
| |
| vm.x = 'other string value' |
| differ.flush() |
| expect(el.children.length).eql(7) |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].attr).eql({ src: 3 }) |
| expect(el.children[4].attr).eql({ src: 'other string value' }) |
| |
| vm.list.push({ uid: 4, x: 4 }) |
| vm.list.push({ uid: 5 }, { uid: 6, x: 6 }) |
| |
| differ.flush() |
| |
| expect(el.children.length).eql(10) |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].attr).eql({ src: 3 }) |
| expect(el.children[4].attr).eql({ src: 'other string value' }) |
| expect(el.children[5].attr).eql({ src: 4 }) |
| expect(el.children[6].attr).eql({ src: 'other string value' }) |
| expect(el.children[7].attr).eql({ src: 6 }) |
| |
| vm.list.splice(1, 2, { uid: 7, x: 7 }) |
| differ.flush() |
| |
| expect(el.children.length).eql(9) |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].attr).eql({ src: 7 }) |
| expect(el.children[4].attr).eql({ src: 4 }) |
| expect(el.children[5].attr).eql({ src: 'other string value' }) |
| expect(el.children[6].attr).eql({ src: 6 }) |
| |
| vm.list.$set(0, { uid: 321, x: 32 }) |
| vm.list.$set(10, { uid: 8889, x: 8888 }) |
| differ.flush() |
| |
| expect(el.children.length).eql(10) |
| expect(el.children[2].attr).eql({ src: 32 }) |
| expect(el.children[7].attr).eql({ src: 8888 }) |
| |
| vm.list.unshift({ uid: 12345, x: 123456 }) |
| differ.flush() |
| |
| expect(el.children.length).eql(11) |
| expect(el.children[2].attr).eql({ src: 123456 }) |
| }) |
| |
| it('generate an static element tree with shown and repeat', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| static: '' |
| }, |
| children: [ |
| { type: 'prev' }, |
| { |
| shown: function () { return this.x % 2 === 0 }, |
| repeat: function () { return this.list }, |
| type: 'image', attr: { src: function () { return this.x } } |
| }, |
| { type: 'next' } |
| ] |
| }, |
| data: { |
| x: '<some image url>', |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm._static).equal(true) |
| expect(vm.x).eql('<some image url>') |
| expect(vm.list).eql([ |
| { uid: 1, x: 1, $index: 0 }, |
| { uid: 2, x: 2, $index: 1 }, |
| { uid: 3, $index: 2 }]) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(11) |
| |
| const prev = el.children[0] |
| const next = el.children[10] |
| expect(prev.type).eql('prev') |
| expect(el.children[1].type).eql('comment') |
| expect(el.children[1].value).eql('start') |
| expect(el.children[9].type).eql('comment') |
| expect(el.children[9].value).eql('end') |
| |
| expect(el.children[2].type).eql('comment') |
| expect(el.children[2].value).eql('start') |
| expect(el.children[3].type).eql('comment') |
| expect(el.children[3].value).eql('end') |
| |
| expect(el.children[4].type).eql('comment') |
| expect(el.children[4].value).eql('start') |
| expect(el.children[5].type).eql('image') |
| expect(el.children[5].attr).eql({ src: 2 }) |
| expect(el.children[6].type).eql('comment') |
| expect(el.children[6].value).eql('end') |
| |
| expect(el.children[7].type).eql('comment') |
| expect(el.children[7].value).eql('start') |
| expect(el.children[8].type).eql('comment') |
| expect(el.children[8].value).eql('end') |
| expect(next.type).eql('next') |
| |
| vm.list[0].x = 4 |
| differ.flush() |
| |
| expect(el.children.length).eql(11) |
| expect(el.children[5].type).eql('image') |
| expect(el.children[5].attr).eql({ src: 2 }) |
| }) |
| |
| it('generate an element tree which root element with shown', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| shown: function () { return this.x % 2 === 0 } |
| }, |
| data: { |
| x: 2 |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.x).eql(2) |
| }) |
| |
| it('append tree', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| append: 'tree' |
| }, |
| children: [ |
| { type: 'a' }, |
| { repeat: {}} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| }) |
| |
| it('repeat is not a function', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'a' }, |
| { repeat: {}} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| }) |
| |
| it('repeat oldStyle with item which not a object', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'a' }, |
| { repeat: function () { return [1, 2, 3] } } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| }) |
| |
| it('classList length is zero', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| classList: [] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| }) |
| |
| it('classList is a function', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| classList: function () { return [] } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| }) |
| |
| it('generate an element tree which root element with repeat', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| repeat: function () { return this.list } |
| }, |
| data: { |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.list).eql([ |
| { uid: 1, x: 1 }, |
| { uid: 2, x: 2 }, |
| { uid: 3 } |
| ]) |
| }) |
| |
| it('generate an element tree with shown and repeat', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'prev' }, |
| { |
| shown: function () { return this.x % 2 === 0 }, |
| repeat: function () { return this.list }, |
| type: 'image', attr: { src: function () { return this.x } } |
| }, |
| { type: 'next' } |
| ] |
| }, |
| data: { |
| x: '<some image url>', |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.x).eql('<some image url>') |
| expect(vm.list).eql([ |
| { uid: 1, x: 1, $index: 0 }, |
| { uid: 2, x: 2, $index: 1 }, |
| { uid: 3, $index: 2 }]) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(11) |
| |
| const prev = el.children[0] |
| const next = el.children[10] |
| expect(prev.type).eql('prev') |
| expect(el.children[1].type).eql('comment') |
| expect(el.children[1].value).eql('start') |
| expect(el.children[9].type).eql('comment') |
| expect(el.children[9].value).eql('end') |
| |
| expect(el.children[2].type).eql('comment') |
| expect(el.children[2].value).eql('start') |
| expect(el.children[3].type).eql('comment') |
| expect(el.children[3].value).eql('end') |
| |
| expect(el.children[4].type).eql('comment') |
| expect(el.children[4].value).eql('start') |
| expect(el.children[5].type).eql('image') |
| expect(el.children[5].attr).eql({ src: 2 }) |
| expect(el.children[6].type).eql('comment') |
| expect(el.children[6].value).eql('end') |
| |
| expect(el.children[7].type).eql('comment') |
| expect(el.children[7].value).eql('start') |
| expect(el.children[8].type).eql('comment') |
| expect(el.children[8].value).eql('end') |
| expect(next.type).eql('next') |
| |
| vm.list[0].x = 4 |
| differ.flush() |
| |
| expect(el.children.length).eql(12) |
| expect(el.children[3].type).eql('image') |
| expect(el.children[3].attr).eql({ src: 4 }) |
| expect(el.children[6].type).eql('image') |
| expect(el.children[6].attr).eql({ src: 2 }) |
| }) |
| |
| it('generate more than one group of elements with the same repeat data', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'begin' }, |
| { |
| repeat: { |
| expression: function () { return this.list }, |
| value: 'v1' |
| }, |
| type: 'image', attr: { src: function () { return this.v1.x } } |
| }, |
| { type: 'middle' }, |
| { |
| repeat: { |
| expression: function () { return this.list }, |
| value: 'v2' |
| }, |
| type: 'text', attr: { value: function () { return this.v2.x } } |
| }, |
| { type: 'end' } |
| ] |
| }, |
| data: { |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm.list).eql([ |
| { uid: 1, x: 1 }, |
| { uid: 2, x: 2 }, |
| { uid: 3 }]) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| |
| // [begin, comment, image x 3, comment, middle, comment, text x 3, comment, end] |
| expect(el.children.length).eql(13) |
| |
| expect(el.children[0].type).eql('begin') |
| expect(el.children[1].type).eql('comment') |
| expect(el.children[1].value).eql('start') |
| expect(el.children[2].type).eql('image') |
| expect(el.children[2].attr).eql({ src: 1 }) |
| expect(el.children[3].type).eql('image') |
| expect(el.children[3].attr).eql({ src: 2 }) |
| expect(el.children[4].type).eql('image') |
| expect(el.children[4].attr).eql({}) |
| expect(el.children[5].type).eql('comment') |
| expect(el.children[5].value).eql('end') |
| expect(el.children[6].type).eql('middle') |
| expect(el.children[7].type).eql('comment') |
| expect(el.children[7].value).eql('start') |
| expect(el.children[8].type).eql('text') |
| expect(el.children[8].attr).eql({ value: 1 }) |
| expect(el.children[9].type).eql('text') |
| expect(el.children[9].attr).eql({ value: 2 }) |
| expect(el.children[10].type).eql('text') |
| expect(el.children[10].attr).eql({}) |
| expect(el.children[11].type).eql('comment') |
| expect(el.children[11].value).eql('end') |
| expect(el.children[12].type).eql('end') |
| |
| vm.list[0].x = 4 |
| differ.flush() |
| |
| expect(el.children.length).eql(13) |
| expect(el.children[2].attr).eql({ src: 4 }) |
| expect(el.children[8].attr).eql({ value: 4 }) |
| |
| // [begin, comment, image x 4, comment, middle, comment, text x 4, comment, end] |
| vm.list.push({ uid: 10, x: 10 }) |
| differ.flush() |
| |
| expect(el.children.length).eql(15) |
| expect(el.children[5].attr).eql({ src: 10 }) |
| expect(el.children[12].attr).eql({ value: 10 }) |
| |
| // [begin, comment, image x 2, comment, middle, comment, text x 2, comment, end] |
| vm.list = [ |
| { uid: 100, x: 100 }, { uid: 1, x: 1 } |
| ] |
| differ.flush() |
| |
| expect(el.children.length).eql(11) |
| expect(el.children[2].attr).eql({ src: 100 }) |
| expect(el.children[3].attr).eql({ src: 1 }) |
| expect(el.children[7].attr).eql({ value: 100 }) |
| expect(el.children[8].attr).eql({ value: 1 }) |
| |
| vm.list[0].x = 4 |
| differ.flush() |
| |
| expect(el.children.length).eql(11) |
| expect(el.children[2].attr).eql({ src: 4 }) |
| expect(el.children[3].attr).eql({ src: 1 }) |
| expect(el.children[7].attr).eql({ value: 4 }) |
| expect(el.children[8].attr).eql({ value: 1 }) |
| |
| vm.list[1].x = 5 |
| differ.flush() |
| |
| expect(el.children.length).eql(11) |
| expect(el.children[2].attr).eql({ src: 4 }) |
| expect(el.children[3].attr).eql({ src: 5 }) |
| expect(el.children[7].attr).eql({ value: 4 }) |
| expect(el.children[8].attr).eql({ value: 5 }) |
| }) |
| |
| it('generate an element with external data', () => { |
| customComponentMap.foo = { |
| data: () => { |
| return { a: 10, b: 20 } |
| }, |
| template: { |
| type: 'container', |
| attr: { |
| x: function () { return this.a }, |
| y: function () { return this.b } |
| } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }, null, { a: 1000 }) |
| |
| expect(vm._app).equal(app) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.attr).eql({ x: 1000, y: 20 }) |
| |
| vm.a = 100 |
| vm.b = 200 |
| differ.flush() |
| |
| expect(el).equal(doc.body) |
| expect(el.attr).eql({ x: 100, y: 200 }) |
| }) |
| }) |
| |
| describe('generate virtual dom for sub vm', () => { |
| let doc |
| let customComponentMap |
| let differ |
| |
| beforeEach(() => { |
| global.callNative = function () {} |
| resetTaskHandler() |
| doc = new Document('test', null, null) |
| customComponentMap = {} |
| differ = new Differ('test') |
| }) |
| |
| afterEach(() => { |
| doc.destroy() |
| global.callNative = oriCallNative |
| }) |
| |
| it('generate sub elements', () => { |
| customComponentMap.foo = { |
| data: function () { |
| return { |
| showbar1: false, |
| showbar2: false, |
| bar2list: [{ |
| id: 'bar2-1' |
| }, { |
| id: 'bar2-2' |
| }] |
| } |
| }, |
| template: { |
| type: 'div', |
| children: [ |
| { type: 'bar', id: 'bar', component: true, |
| events: { click: 'handleClick' } |
| }, |
| { type: 'bar1', |
| shown: function () { return this.showbar1 }, |
| id: 'bar1', component: true |
| }, |
| { type: 'bar2', |
| shown: function () { return this.showbar2 }, |
| repeat: function () { return this.bar2list }, |
| id: function () { return this.id }, |
| component: true |
| } |
| ] |
| }, |
| methods: { |
| handleClick: sinon.spy() |
| } |
| } |
| customComponentMap.bar = { |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }, { type: 'bbb' }] |
| } |
| } |
| customComponentMap.bar1 = { |
| template: { |
| type: 'container', |
| children: [{ type: 'aaaa' }, { type: 'bbbb' }] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm._rootEl).to.deep.equal(vm._parentEl.children[0]) |
| |
| expect(vm._childrenVms.length).to.be.equal(1) |
| expect(vm._childrenVms[0]).to.deep.equal(vm._ids['bar'].vm) |
| expect(vm._childrenVms[0]._rootEl).to.deep.equal(vm._ids['bar'].el) |
| |
| const el = doc.body |
| expect(el.type).eql('div') |
| expect(el.pureChildren).is.an.array |
| expect(el.pureChildren.length).eql(1) |
| |
| const sub = el.children[0] |
| expect(sub.type).eql('container') |
| expect(sub.children).is.an.array |
| expect(sub.children.length).eql(2) |
| expect(sub.children[0].type).eql('aaa') |
| expect(sub.children[1].type).eql('bbb') |
| expect(sub.event.click).is.a.function |
| |
| const spy = customComponentMap.foo.methods.handleClick |
| sub.event.click.handler(1, 2, 3) |
| expect(spy.args.length).eql(1) |
| expect(spy.args[0]).eql([1, 2, 3]) |
| |
| vm.showbar1 = true |
| differ.flush() |
| |
| expect(vm._childrenVms.length).to.be.equal(2) |
| expect(vm._childrenVms[1]).to.deep.equal(vm._ids['bar1'].vm) |
| expect(vm._childrenVms[1]._rootEl).to.deep.equal(vm._ids['bar1'].el) |
| |
| vm.showbar2 = true |
| differ.flush() |
| |
| expect(vm._ids['bar2-1'].vm).to.be.not.undefined |
| expect(vm._ids['bar2-1'].el).to.be.not.undefined |
| expect(vm._ids['bar2-2'].vm).to.be.not.undefined |
| expect(vm._ids['bar2-2'].el).to.be.not.undefined |
| }) |
| |
| it('generate sub element with static', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| static: '' |
| }, |
| children: [{ type: 'bar', component: true }] |
| } |
| } |
| customComponentMap.bar = { |
| replace: true, |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| expect(vm._static).eql(true) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const aaa = el.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(vm._childrenVms.length).to.be.equal(1) |
| expect(vm._childrenVms[0]._static).eql(true) |
| }) |
| |
| it('generate replaced sub element', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true }] |
| } |
| } |
| customComponentMap.bar = { |
| replace: true, |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const aaa = el.children[0] |
| expect(aaa.type).eql('aaa') |
| }) |
| |
| it('generate replaced sub elements', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true }] |
| } |
| } |
| customComponentMap.bar = { |
| replace: true, |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }, { type: 'bbb' }] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(4) |
| |
| expect(el.children[0].type).eql('comment') |
| const aaa = el.children[1] |
| expect(aaa.type).eql('aaa') |
| const bbb = el.children[2] |
| expect(bbb.type).eql('bbb') |
| expect(el.children[3].type).eql('comment') |
| }) |
| |
| it('generate sub elements with no props', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { x: 10, y: 20 }}] |
| } |
| } |
| customComponentMap.bar = { |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const sub = el.children[0] |
| const aaa = sub.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(aaa.attr).eql({ a: 10 }) |
| const bbb = sub.children[1] |
| expect(bbb.type).eql('bbb') |
| expect(bbb.attr).eql({ b: 20 }) |
| }) |
| |
| it('generate sub elements with array props', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { x: 10, y: 20 }}] |
| } |
| } |
| customComponentMap.bar = { |
| props: ['x'], |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const sub = el.children[0] |
| const aaa = sub.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(aaa.attr).eql({ a: 10 }) |
| const bbb = sub.children[1] |
| expect(bbb.type).eql('bbb') |
| expect(bbb.attr).eql({ b: 2 }) |
| }) |
| |
| it('generate sub elements with props', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { x: 10, y: 20 }}] |
| } |
| } |
| customComponentMap.bar = { |
| props: { x: Number }, |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const sub = el.children[0] |
| const aaa = sub.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(aaa.attr).eql({ a: 10 }) |
| const bbb = sub.children[1] |
| expect(bbb.type).eql('bbb') |
| expect(bbb.attr).eql({ b: 2 }) |
| }) |
| |
| it('generate sub elements with data', () => { |
| customComponentMap.foo = { |
| data: () => { |
| return { a: 10, b: 20 } |
| }, |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { |
| x: function () { return this.a }, |
| y: function () { return this.b } |
| }}] |
| } |
| } |
| customComponentMap.bar = { |
| props: { x: Number }, |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(1) |
| |
| const sub = el.children[0] |
| const aaa = sub.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(aaa.attr).eql({ a: 10 }) |
| const bbb = sub.children[1] |
| expect(bbb.type).eql('bbb') |
| expect(bbb.attr).eql({ b: 2 }) |
| |
| vm.a = 100 |
| vm.b = 200 |
| differ.flush() |
| |
| expect(el).equal(doc.body) |
| expect(sub).equal(el.children[0]) |
| expect(aaa).equal(sub.children[0]) |
| expect(aaa.attr).eql({ a: 100 }) |
| expect(bbb).equal(sub.children[1]) |
| expect(bbb.attr).eql({ b: 2 }) |
| }) |
| |
| it('generate sub elements with shown data', () => { |
| customComponentMap.foo = { |
| data: () => { |
| return { a: 10, b: 20 } |
| }, |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { |
| x: function () { return this.a }, |
| y: function () { return this.b } |
| }, shown: function () { return this.a < 15 } }] |
| } |
| } |
| customComponentMap.bar = { |
| props: { x: Number }, |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(3) |
| |
| const sub = el.children[1] |
| const aaa = sub.children[0] |
| expect(aaa.type).eql('aaa') |
| expect(aaa.attr).eql({ a: 10 }) |
| const bbb = sub.children[1] |
| expect(bbb.type).eql('bbb') |
| expect(bbb.attr).eql({ b: 2 }) |
| |
| vm.a = 20 |
| differ.flush() |
| |
| expect(el).equal(doc.body) |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(2) |
| }) |
| |
| it('generate sub elements with repeat data', () => { |
| customComponentMap.foo = { |
| data: () => { |
| return { list: [{ uid: 1, a: 1 }, { uid: 2, a: 2 }, { uid: 3, a: 3 }] } |
| }, |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { |
| x: function () { return this.a }, |
| y: function () { return this.b } |
| }, repeat: function () { return this.list } }] |
| } |
| } |
| customComponentMap.bar = { |
| props: { x: Number }, |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(vm._app).equal(app) |
| |
| const el = doc.body |
| expect(el.type).eql('container') |
| expect(el.children).is.an.array |
| expect(el.children.length).eql(5) |
| |
| const sub1 = el.children[1] |
| const aaa1 = sub1.children[0] |
| expect(aaa1.type).eql('aaa') |
| expect(aaa1.attr).eql({ a: 1 }) |
| const bbb1 = sub1.children[1] |
| expect(bbb1.type).eql('bbb') |
| expect(bbb1.attr).eql({ b: 2 }) |
| |
| const sub2 = el.children[2] |
| const aaa2 = sub2.children[0] |
| expect(aaa2.type).eql('aaa') |
| expect(aaa2.attr).eql({ a: 2 }) |
| const bbb2 = sub2.children[1] |
| expect(bbb2.type).eql('bbb') |
| expect(bbb2.attr).eql({ b: 2 }) |
| |
| const sub3 = el.children[3] |
| const aaa3 = sub3.children[0] |
| expect(aaa3.type).eql('aaa') |
| expect(aaa3.attr).eql({ a: 3 }) |
| const bbb3 = sub3.children[1] |
| expect(bbb3.type).eql('bbb') |
| expect(bbb3.attr).eql({ b: 2 }) |
| }) |
| |
| it('generate sub elements with content', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, children: [ |
| { type: 'a' }, { type: 'b', attr: { bbb: function () { return this.x } }} |
| ] }] |
| }, |
| data: () => { |
| return { |
| x: 1, y: 2 |
| } |
| } |
| } |
| customComponentMap.bar = { |
| replace: true, |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }, { type: 'content' }, { type: 'bbb' }] |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| const el = doc.body |
| |
| expect(el.type).eql('container') |
| // [comment, aaa, comment, a, b, comment, bbb, comment] |
| expect(el.children.length).eql(8) |
| expect(el.children[0].type).eql('comment') |
| expect(el.children[2].type).eql('comment') |
| expect(el.children[5].type).eql('comment') |
| expect(el.children[7].type).eql('comment') |
| |
| expect(el.pureChildren.length).eql(4) |
| expect(el.pureChildren[0].type).eql('aaa') |
| expect(el.pureChildren[1].type).eql('a') |
| expect(el.pureChildren[2].type).eql('b') |
| expect(el.pureChildren[2].attr).eql({ bbb: 1 }) |
| expect(el.pureChildren[3].type).eql('bbb') |
| |
| vm.x = 10 |
| differ.flush() |
| expect(el.pureChildren[2].attr).eql({ bbb: 10 }) |
| }) |
| |
| it('generate sub elements with dynamic types', (done) => { |
| customComponentMap.foo = { |
| data: { |
| x: 'bar', |
| y: 'hello' |
| }, |
| template: { |
| type: 'div', |
| children: [{ |
| type: function () { return this.x }, |
| attr: { value: function () { return this.y } } |
| }] |
| } |
| } |
| customComponentMap.bar = { |
| template: { |
| type: 'text', |
| attr: { value: 'bar' } |
| } |
| } |
| customComponentMap.baz = { |
| data: function () { |
| return { |
| value: '' |
| } |
| }, |
| template: { |
| type: 'text', |
| attr: { value: function () { return this.value + ' baz' } } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(doc.body.pureChildren[0].type).eql('text') |
| expect(doc.body.pureChildren[0].attr).eql({ value: 'bar' }) |
| |
| vm.x = 'baz' |
| expect(doc.body.pureChildren[0].type).eql('text') |
| expect(doc.body.pureChildren[0].attr).eql({ value: 'hello baz' }) |
| |
| vm.y = 'bye' |
| setTimeout(() => { |
| expect(doc.body.pureChildren[0].type).eql('text') |
| expect(doc.body.pureChildren[0].attr).eql({ value: 'bye baz' }) |
| |
| vm.x = 'text' |
| expect(doc.body.pureChildren[0].type).eql('text') |
| expect(doc.body.pureChildren[0].attr).eql({ value: 'bye' }) |
| |
| done() |
| }) |
| }) |
| |
| it('generate sub elements with repeat dynamic types', (done) => { |
| customComponentMap.foo = { |
| data: { |
| list: [ |
| { uid: 1, type: 'bar' }, |
| { uid: 2, type: 'baz' }, |
| { uid: 3, type: 'bar' }, |
| { uid: 4, type: 'baz' } |
| ] |
| }, |
| template: { |
| type: 'div', |
| children: [{ |
| type: function () { return this.v.type }, |
| repeat: { |
| expression: function () { return this.list }, |
| trackBy: 'uid', |
| value: 'v' |
| } |
| }] |
| } |
| } |
| customComponentMap.bar = { |
| template: { |
| type: 'text', |
| attr: { value: 'bar' } |
| } |
| } |
| customComponentMap.baz = { |
| template: { |
| type: 'text', |
| attr: { value: 'baz' } |
| } |
| } |
| |
| const app = { doc, customComponentMap, differ } |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(doc.body.pureChildren.length).eql(4) |
| expect(doc.body.pureChildren.map(el => el.attr.value)).eql(['bar', 'baz', 'bar', 'baz']) |
| |
| vm.list.splice(2, 0, { uid: 5, type: 'baz' }) |
| setTimeout(() => { |
| expect(doc.body.pureChildren.length).eql(5) |
| expect(doc.body.pureChildren.map(el => el.attr.value)).eql(['bar', 'baz', 'baz', 'bar', 'baz']) |
| |
| done() |
| }) |
| }) |
| }) |
| |
| describe('generate dom actions', () => { |
| let doc, app, spy, customComponentMap, differ |
| |
| beforeEach(() => { |
| spy = sinon.spy() |
| doc = new Document('foo', '', function (actions) { |
| actions.forEach((action) => { |
| spy.apply(null, ['bar', action.method].concat(action.args)) |
| }) |
| }) |
| differ = new Differ('foo') |
| customComponentMap = {} |
| app = { doc, customComponentMap, differ } |
| }) |
| |
| afterEach(() => { |
| customComponentMap = {} |
| doc.destroy() |
| app = doc = spy = null |
| }) |
| |
| it('received create body and add element actions', () => { |
| const handler = sinon.spy() |
| |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| attr: { |
| a: 1, |
| b: 2 |
| }, |
| style: { |
| c: 3, |
| d: 4 |
| }, |
| classList: ['classA'], |
| events: { click: 'handleClick' } |
| }, |
| style: { |
| classA: { d: 5, e: 6 } |
| }, |
| methods: { |
| handleClick: handler |
| } |
| } |
| |
| new Vm('foo', customComponentMap.foo, { _app: app }) |
| const el = { |
| ref: '_root', |
| type: 'container', |
| attr: { a: 1, b: 2 }, style: { c: 3, d: 4, e: 6 }, |
| event: ['click'] |
| } |
| |
| expect(spy.args.length).eql(1) |
| expect(spy.args[0]).eql(['bar', 'createBody', el]) |
| expect(doc.body.event.click).is.a.function |
| expect(handler.args.length).eql(0) |
| doc.body.fireEvent('click') |
| expect(handler.args.length).eql(0) |
| }) |
| |
| it('received actions for a template with if & repeat', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'prev' }, |
| { |
| shown: function () { return this.x % 2 === 0 }, |
| repeat: function () { return this.list }, |
| trackBy: 'uid', |
| type: 'image', attr: { src: function () { return this.x } } |
| }, |
| { type: 'next' } |
| ] |
| }, |
| data: { |
| x: '<some image url>', |
| list: [ |
| { uid: 1, x: 1 }, { uid: 2, x: 2 }, { uid: 3 } |
| ] |
| } |
| } |
| |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| const pureChildren = doc.body.pureChildren |
| const el = { ref: '_root', type: 'container', attr: {}, style: {}} |
| const prev = { |
| ref: pureChildren[0].ref, |
| type: 'prev', attr: {}, style: {} |
| } |
| const img = { |
| ref: pureChildren[1].ref, |
| type: 'image', attr: { src: 2 }, style: {} |
| } |
| const next = { |
| ref: pureChildren[2].ref, |
| type: 'next', attr: {}, style: {} |
| } |
| |
| expect(spy.args.length).eql(4) |
| expect(spy.args[0]).eql(['bar', 'createBody', el]) |
| expect(spy.args[1]).eql(['bar', 'addElement', '_root', prev, -1]) |
| expect(spy.args[2]).eql(['bar', 'addElement', '_root', img, 1]) |
| expect(spy.args[3]).eql(['bar', 'addElement', '_root', next, -1]) |
| |
| vm.list[1].x = 3 |
| differ.flush() |
| |
| // [1, 3, undefined] |
| expect(spy.args.length).eql(5) |
| expect(spy.args[4]).eql(['bar', 'removeElement', img.ref]) |
| |
| vm.list[1].x = 12 |
| differ.flush() |
| |
| // [1, !12, undefined] |
| expect(spy.args.length).eql(6) |
| img.ref = pureChildren[1].ref |
| img.attr.src = 12 |
| expect(spy.args[5]).eql(['bar', 'addElement', '_root', img, 1]) |
| |
| vm.x = 'other string value' |
| differ.flush() |
| |
| expect(spy.args.length).eql(6) |
| |
| vm.list.push({ uid: 4, x: 4 }) |
| vm.list.push({ uid: 5 }, { uid: 6, x: 6 }) |
| differ.flush() |
| |
| // [1, !12, undefined, !4, undefined, !6] |
| const img2 = { |
| ref: pureChildren[2].ref, |
| type: 'image', attr: { src: 4 }, style: {} |
| } |
| const img3 = { |
| ref: pureChildren[3].ref, |
| type: 'image', attr: { src: 6 }, style: {} |
| } |
| expect(spy.args.length).eql(8) |
| expect(spy.args[6]).eql(['bar', 'addElement', '_root', img2, 2]) |
| expect(spy.args[7]).eql(['bar', 'addElement', '_root', img3, 3]) |
| |
| const temp1 = vm.list[1] // 12 |
| const temp2 = vm.list[5] // 6 |
| // vm.list.splice(0, 6, temp2, {uid: 7, x: 7}, temp1) |
| vm.list = [] |
| vm.list.push(temp2, { uid: 7, x: 7 }, temp1) |
| differ.flush() |
| |
| // [!6, 7, !12] |
| expect(spy.args.length).eql(10) |
| expect(spy.args[8]).eql(['bar', 'removeElement', img2.ref]) |
| expect(spy.args[9]).eql(['bar', 'moveElement', img3.ref, '_root', 1]) |
| }) |
| |
| it('received actions for element updates', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', attr: { a: 1, b: 2 }, style: { c: 3, d: 4 }, |
| children: [ |
| { type: 'image', attr: { src: function () { return this.x } }}, |
| { type: 'text', attr: { value: function () { return this.y } }} |
| ] |
| }, |
| data: { |
| x: '<some image url>', y: '<some text content>' |
| } |
| } |
| |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| const pureChildren = doc.body.pureChildren |
| const length = spy.args.length |
| |
| vm.x = '<some image url>' |
| differ.flush() |
| expect(spy.args.length - length).eql(0) |
| |
| vm.x = 'other string value' |
| differ.flush() |
| const change = [ |
| 'bar', 'updateAttrs', |
| pureChildren[0].ref, |
| { src: 'other string value' } |
| ] |
| expect(spy.args.length - length).eql(1) |
| expect(spy.args[length]).eql(change) |
| }) |
| |
| it('received no action when no virtual dom different', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', children: [ |
| { |
| type: 'text', |
| shown: function () { return this.name.length > 3 }, |
| attr: { |
| value: function () { return this.name.toUpperCase() } |
| } |
| } |
| ] |
| }, |
| data: { |
| name: 'Mike' |
| } |
| } |
| |
| const vm = new Vm('foo', customComponentMap.foo, { _app: app }) |
| |
| expect(doc.body.pureChildren.length).eql(1) |
| const text = doc.body.pureChildren[0] |
| expect(text.attr.value).eql('MIKE') |
| |
| const initCalls = spy.args.length |
| |
| vm.name = 'MiKe' |
| differ.flush() |
| |
| expect(spy.args.length).eql(initCalls) |
| |
| text.setAttr('value', 'MIKE') |
| differ.flush() |
| |
| expect(spy.args.length).eql(initCalls) |
| |
| text.setAttr('value', 'STEVE') |
| differ.flush() |
| |
| expect(spy.args.length).eql(initCalls + 1) |
| expect(spy.args[initCalls]).eql([ |
| 'bar', 'updateAttrs', text.ref, { value: 'STEVE' }]) |
| |
| vm.name = 'Steve' |
| differ.flush() |
| |
| expect(spy.args.length).eql(initCalls + 1) |
| }) |
| |
| it('received actions for components', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true }] |
| } |
| } |
| customComponentMap.bar = { |
| template: { |
| type: 'container', |
| children: [{ type: 'aaa' }, { type: 'bbb' }] |
| } |
| } |
| |
| new Vm('foo', customComponentMap.foo, { _app: app }) |
| const pureChildren = doc.body.pureChildren |
| const first = pureChildren[0] |
| const second = first.pureChildren[0] |
| const third = first.pureChildren[1] |
| expect(spy.args.length).eql(4) |
| let el = { ref: '_root', type: 'container', attr: {}, style: {}} |
| expect(spy.args[0]).eql(['bar', 'createBody', el]) |
| el = { ref: first.ref, type: 'container', attr: {}, style: {}} |
| expect(spy.args[1]).eql(['bar', 'addElement', '_root', el, -1]) |
| el = { ref: second.ref, type: 'aaa', attr: {}, style: {}} |
| expect(spy.args[2]).eql(['bar', 'addElement', first.ref, el, -1]) |
| el = { ref: third.ref, type: 'bbb', attr: {}, style: {}} |
| expect(spy.args[3]).eql(['bar', 'addElement', first.ref, el, -1]) |
| }) |
| |
| it('received actions for complicated components', () => { |
| customComponentMap.foo = { |
| data: () => { |
| return { list: [{ uid: 1, a: 1 }, { uid: 2, a: 2 }, { uid: 3, a: 3 }] } |
| }, |
| template: { |
| type: 'container', |
| children: [{ type: 'bar', component: true, attr: { |
| x: function () { return this.a }, |
| y: function () { return this.b } |
| }, repeat: function () { return this.list } }] |
| } |
| } |
| customComponentMap.bar = { |
| props: { x: Number }, |
| data: () => { |
| return { x: 1, y: 2 } |
| }, |
| template: { |
| type: 'container', |
| children: [ |
| { type: 'aaa', attr: { a: function () { return this.x } }}, |
| { type: 'bbb', attr: { b: function () { return this.y } }} |
| ] |
| } |
| } |
| |
| new Vm('foo', customComponentMap.foo, { _app: app }) |
| const pureChildren = doc.body.pureChildren |
| const first = pureChildren[0] |
| const second = pureChildren[1] |
| const third = pureChildren[2] |
| |
| /* eslint-disable indent */ |
| // expect(spy.args[0]).eql([ 'bar', 'createBody', 'container' ]) |
| expect(spy.args[0]).eql(['bar', 'createBody', { ref: '_root', type: 'container', attr: {}, style: {}}]) |
| expect(spy.args[1]).eql(['bar', 'addElement', '_root', { ref: first.ref, type: 'container', attr: {}, style: {}}, 0]) |
| expect(spy.args[2]).eql(['bar', 'addElement', first.ref, { ref: first.pureChildren[0].ref, type: 'aaa', attr: { a: 1 }, style: {}}, -1]) |
| expect(spy.args[3]).eql(['bar', 'addElement', first.ref, { ref: first.pureChildren[1].ref, type: 'bbb', attr: { b: 2 }, style: {}}, -1]) |
| expect(spy.args[4]).eql(['bar', 'addElement', '_root', { ref: second.ref, type: 'container', attr: {}, style: {}}, 1]) |
| expect(spy.args[5]).eql(['bar', 'addElement', second.ref, { ref: second.pureChildren[0].ref, type: 'aaa', attr: { a: 2 }, style: {}}, -1]) |
| expect(spy.args[6]).eql(['bar', 'addElement', second.ref, { ref: second.pureChildren[1].ref, type: 'bbb', attr: { b: 2 }, style: {}}, -1]) |
| expect(spy.args[7]).eql(['bar', 'addElement', '_root', { ref: third.ref, type: 'container', attr: {}, style: {}}, 2]) |
| expect(spy.args[8]).eql(['bar', 'addElement', third.ref, { ref: third.pureChildren[0].ref, type: 'aaa', attr: { a: 3 }, style: {}}, -1]) |
| expect(spy.args[9]).eql(['bar', 'addElement', third.ref, { ref: third.pureChildren[1].ref, type: 'bbb', attr: { b: 2 }, style: {}}, -1]) |
| /* eslint-enable indent */ |
| }) |
| |
| it('received actions for add a tree element', () => { |
| customComponentMap.foo = { |
| template: { |
| type: 'r', |
| children: [ |
| { type: 'a' }, { type: 'b', children: [ |
| { type: 'd' }, { type: 'e', append: 'tree', children: [ |
| { type: 'g' }, { type: 'h' }, { type: 'i' } |
| ] }, { type: 'f' } |
| ] }, { type: 'c' } |
| ] |
| } |
| } |
| |
| new Vm('foo', customComponentMap.foo, { _app: app }) |
| const pureChildren = doc.body.pureChildren |
| |
| expect(spy.args.length).eql(7) |
| // body, r, r.a, r.b, r.b.d, r.b.e(tree), r.b.f, r.c |
| |
| expect(spy.args[0][2].ref).eql('_root') |
| expect(spy.args[0][2].type).eql('r') |
| |
| expect(spy.args[1][3].ref).eql(pureChildren[0].ref) |
| expect(spy.args[1][3].type).eql('a') |
| expect(spy.args[1][2]).eql('_root') |
| expect(spy.args[1][4]).eql(-1) |
| |
| expect(spy.args[2][3].ref).eql(pureChildren[1].ref) |
| expect(spy.args[2][3].type).eql('b') |
| expect(spy.args[2][2]).eql('_root') |
| expect(spy.args[2][4]).eql(-1) |
| |
| expect(spy.args[3][3].ref).eql(pureChildren[1].pureChildren[0].ref) |
| expect(spy.args[3][3].type).eql('d') |
| expect(spy.args[3][2]).eql(pureChildren[1].ref) |
| expect(spy.args[3][4]).eql(-1) |
| |
| const tree = pureChildren[1].pureChildren[1] |
| expect(spy.args[4][3].ref).eql(tree.ref) |
| expect(spy.args[4][3].type).eql('e') |
| expect(spy.args[4][2]).eql(pureChildren[1].ref) |
| expect(spy.args[4][4]).eql(-1) |
| expect(spy.args[4][3].children).eql([ |
| { ref: tree.pureChildren[0].ref, type: 'g', attr: {}, style: {}}, |
| { ref: tree.pureChildren[1].ref, type: 'h', attr: {}, style: {}}, |
| { ref: tree.pureChildren[2].ref, type: 'i', attr: {}, style: {}}]) |
| |
| expect(spy.args[5][3].ref).eql(pureChildren[1].pureChildren[2].ref) |
| expect(spy.args[5][3].type).eql('f') |
| expect(spy.args[5][2]).eql(pureChildren[1].ref) |
| expect(spy.args[5][4]).eql(-1) |
| |
| expect(spy.args[6][3].ref).eql(pureChildren[2].ref) |
| expect(spy.args[6][3].type).eql('c') |
| expect(spy.args[6][2]).eql('_root') |
| expect(spy.args[6][4]).eql(-1) |
| }) |
| }) |