Просмотр исходного кода

test(weex): add more test cases for recycle-list (#7104)

Hanks 8 лет назад
Родитель
Сommit
46c8016562

+ 65 - 10
test/weex/cases/cases.spec.js

@@ -1,21 +1,14 @@
-import fs from 'fs'
-import path from 'path'
 import {
+  readFile,
+  readObject,
   compileVue,
+  compileWithDeps,
   createInstance,
   getRoot,
   getEvents,
   fireEvent
 } from '../helpers'
 
-function readFile (filename) {
-  return fs.readFileSync(path.resolve(__dirname, filename), 'utf8')
-}
-
-function readObject (filename) {
-  return (new Function(`return ${readFile(filename)}`))()
-}
-
 // Create one-off render test case
 function createRenderTestCase (name) {
   const source = readFile(`${name}.vue`)
@@ -72,6 +65,8 @@ describe('Usage', () => {
   describe('recycle-list', () => {
     it('text node', createRenderTestCase('recycle-list/text-node'))
     it('attributes', createRenderTestCase('recycle-list/attrs'))
+    // it('class name', createRenderTestCase('recycle-list/classname'))
+    // it('inline style', createRenderTestCase('recycle-list/inline-style'))
     it('v-if', createRenderTestCase('recycle-list/v-if'))
     it('v-else', createRenderTestCase('recycle-list/v-else'))
     it('v-else-if', createRenderTestCase('recycle-list/v-else-if'))
@@ -79,6 +74,66 @@ describe('Usage', () => {
     it('v-for-iterator', createRenderTestCase('recycle-list/v-for-iterator'))
     it('v-on', createRenderTestCase('recycle-list/v-on'))
     it('v-on-inline', createRenderTestCase('recycle-list/v-on-inline'))
+
+    it('stateless component', done => {
+      compileWithDeps('recycle-list/components/stateless.vue', [{
+        name: 'banner',
+        path: 'recycle-list/components/banner.vue'
+      }]).then(code => {
+        const id = String(Date.now() * Math.random())
+        const instance = createInstance(id, code)
+        setTimeout(() => {
+          const target = readObject('recycle-list/components/stateless.vdom.js')
+          expect(getRoot(instance)).toEqual(target)
+          done()
+        }, 50)
+      }).catch(err => {
+        expect(err).toBe(null)
+        done()
+      })
+    })
+
+    // it('stateless component with props', done => {
+    //   compileWithDeps('recycle-list/components/stateless-with-props.vue', [{
+    //     name: 'poster',
+    //     path: 'recycle-list/components/poster.vue'
+    //   }]).then(code => {
+    //     const id = String(Date.now() * Math.random())
+    //     const instance = createInstance(id, code)
+    //     setTimeout(() => {
+    //       const target = readObject('recycle-list/components/stateless-with-props.vdom.js')
+    //       expect(getRoot(instance)).toEqual(target)
+    //       done()
+    //     }, 50)
+    //   }).catch(err => {
+    //     expect(err).toBe(null)
+    //     done()
+    //   })
+    // })
+
+    // it('stateful component', done => {
+    //   compileWithDeps('recycle-list/components/stateful.vue', [{
+    //     name: 'counter',
+    //     path: 'recycle-list/components/counter.vue'
+    //   }]).then(code => {
+    //     const id = String(Date.now() * Math.random())
+    //     const instance = createInstance(id, code)
+    //     setTimeout(() => {
+    //       const target = readObject('recycle-list/components/stateful.vdom.js')
+    //       expect(getRoot(instance)).toEqual(target)
+    //       const event = getEvents(instance)[0]
+    //       fireEvent(instance, event.ref, event.type, {})
+    //       setTimeout(() => {
+    //         // TODO: check render results
+    //         // expect(getRoot(instance)).toEqual(target)
+    //         done()
+    //       })
+    //     }, 50)
+    //   }).catch(err => {
+    //     expect(err).toBe(null)
+    //     done()
+    //   })
+    // })
   })
 })
 

+ 26 - 0
test/weex/cases/recycle-list/classname.vdom.js

@@ -0,0 +1,26 @@
+({
+  type: 'recycle-list',
+  attr: {
+    listData: [
+      { type: 'A', color: 'red' },
+      { type: 'A', color: 'blue' }
+    ],
+    templateKey: 'type',
+    alias: 'item'
+  },
+  children: [{
+    type: 'cell-slot',
+    attr: { templateType: 'A' },
+    style: {
+      backgroundColor: '#FF6600'
+    },
+    children: [{
+      type: 'text',
+      attr: {
+        // not supported yet
+        // classList: ['text', { '@binding': 'item.color' }],
+        value: 'content'
+      }
+    }]
+  }]
+})

+ 37 - 0
test/weex/cases/recycle-list/classname.vue

@@ -0,0 +1,37 @@
+<template>
+  <recycle-list :list-data="longList" template-key="type" alias="item">
+    <cell-slot template-type="A" class="cell">
+      <text :class="['text', item.color]">content</text>
+    </cell-slot>
+  </recycle-list>
+</template>
+
+<style scoped>
+  .cell {
+    background-color: #FF6600;
+  }
+  .text {
+    font-size: 100px;
+    text-align: center;
+  }
+  .red {
+    color: #FF0000;
+  }
+  .blue {
+    color: #0000FF;
+  }
+</style>
+
+<script>
+  module.exports = {
+    data () {
+      return {
+        longList: [
+          { type: 'A', color: 'red' },
+          { type: 'A', color: 'blue' }
+        ]
+      }
+    }
+  }
+</script>
+

+ 19 - 0
test/weex/cases/recycle-list/components/banner.vue

@@ -0,0 +1,19 @@
+<template recyclable="true">
+  <div class="banner">
+    <text class="title">BANNER</text>
+  </div>
+</template>
+
+<style scoped>
+  .banner {
+    height: 120px;
+    justify-content: center;
+    align-items: center;
+    background-color: rgb(162, 217, 192);
+  }
+  .title {
+    font-weight: bold;
+    color: #41B883;
+    font-size: 60px;
+  }
+</style>

+ 36 - 0
test/weex/cases/recycle-list/components/counter.vue

@@ -0,0 +1,36 @@
+<template recyclable="true">
+  <div>
+    <text class="output">{{count}}</text>
+    <text class="button" @click="inc">+</text>
+  </div>
+</template>
+
+<script>
+  module.exports = {
+    props: ['start'],
+    data () {
+      return {
+        count: parseInt(this.start, 10) || 42
+      }
+    },
+    methods: {
+      inc () {
+        this.count++
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .output {
+    font-size: 150px;
+    text-align: center;
+  }
+  .button {
+    font-size: 100px;
+    text-align: center;
+    border-width: 2px;
+    border-color: #DDD;
+    background-color: #F5F5F5;
+  }
+</style>

+ 33 - 0
test/weex/cases/recycle-list/components/poster.vue

@@ -0,0 +1,33 @@
+<template>
+  <div>
+    <image class="image" :src="imageUrl"></image>
+    <text class="title">{{title}}</text>
+  </div>
+</template>
+
+<script>
+  module.exports = {
+    props: {
+      imageUrl: {
+        type: String,
+        default: 'https://gw.alicdn.com/tfs/TB1KF_ybRTH8KJjy0FiXXcRsXXa-890-1186.png'
+      },
+      title: {
+        type: String,
+        default: 'I WANT YOU!'
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .image {
+    width: 750px;
+    height: 1000px;
+  }
+  .title {
+    font-size: 80px;
+    text-align: center;
+    color: #E95659;
+  }
+</style>

+ 45 - 0
test/weex/cases/recycle-list/components/stateful.vdom.js

@@ -0,0 +1,45 @@
+({
+  type: 'recycle-list',
+  attr: {
+    listData: [
+      { type: 'A', number: 24 },
+      { type: 'A', number: 42 }
+    ],
+    templateKey: 'type',
+    alias: 'item'
+  },
+  children: [{
+    type: 'cell-slot',
+    attr: { templateType: 'A' },
+    children: [{
+      type: 'div',
+      attr: {
+        '@isComponentRoot': true,
+        '@componentProps': {
+          start: { '@binding': 'item.number' }
+        }
+      },
+      children: [{
+        type: 'text',
+        style: { fontSize: '150px', textAlign: 'center' },
+        attr: {
+          value: { '@binding': 'count' } // need confirm
+        }
+      }, {
+        type: 'text',
+        event: ['click'],
+        style: {
+          fontSize: '100px',
+          textAlign: 'center',
+          borderWidth: '2px',
+          borderColor: '#DDDDDD',
+          backgroundColor: '#F5F5F5'
+        },
+        attr: { value: '+' }
+      }]
+    }, {
+      type: 'text',
+      attr: { value: 'other' }
+    }]
+  }]
+})

+ 22 - 0
test/weex/cases/recycle-list/components/stateful.vue

@@ -0,0 +1,22 @@
+<template>
+  <recycle-list :list-data="longList" template-key="type" alias="item">
+    <cell-slot template-type="A">
+      <counter :start="item.number"></counter>
+      <text>other</text>
+    </cell-slot>
+  </recycle-list>
+</template>
+
+<script>
+  // require('./counter.vue')
+  module.exports = {
+    data () {
+      return {
+        longList: [
+          { type: 'A', number: 24 },
+          { type: 'A', number: 42 }
+        ]
+      }
+    }
+  }
+</script>

+ 50 - 0
test/weex/cases/recycle-list/components/stateless-with-props.vdom.js

@@ -0,0 +1,50 @@
+({
+  type: 'recycle-list',
+  attr: {
+    listData: [
+      { type: 'A', poster: 'xx', title: 'x' },
+      { type: 'A', poster: 'yy', title: 'y' }
+    ],
+    templateKey: 'type',
+    alias: 'item'
+  },
+  children: [{
+    type: 'cell-slot',
+    attr: { templateType: 'A' },
+    children: [{
+      type: 'div',
+      attr: {
+        '@isComponentRoot': true,
+        '@componentProps': {
+          imageUrl: { '@binding': 'item.poster' },
+          title: { '@binding': 'item.title' }
+        }
+      },
+      children: [{
+        type: 'image',
+        style: {
+          width: '750px',
+          height: '1000px'
+        },
+        attr: {
+          src: { '@binding': 'imageUrl' }
+        }
+      }, {
+        type: 'text',
+        style: {
+          fontSize: '80px',
+          textAlign: 'center',
+          color: '#E95659'
+        },
+        attr: {
+          value: { '@binding': 'title' }
+        }
+      }]
+    }, {
+      type: 'text',
+      attr: {
+        value: 'content'
+      }
+    }]
+  }]
+})

+ 22 - 0
test/weex/cases/recycle-list/components/stateless-with-props.vue

@@ -0,0 +1,22 @@
+<template>
+  <recycle-list :list-data="longList" template-key="type" alias="item">
+    <cell-slot template-type="A">
+      <poster :image-url="item.poster" :title="item.title"></poster>
+      <text>content</text>
+    </cell-slot>
+  </recycle-list>
+</template>
+
+<script>
+  // require('./poster.vue')
+  module.exports = {
+    data () {
+      return {
+        longList: [
+          { type: 'A', poster: 'xx', title: 'x' },
+          { type: 'A', poster: 'yy', title: 'y' }
+        ]
+      }
+    }
+  }
+</script>

+ 45 - 0
test/weex/cases/recycle-list/components/stateless.vdom.js

@@ -0,0 +1,45 @@
+({
+  type: 'recycle-list',
+  attr: {
+    listData: [
+      { type: 'A' },
+      { type: 'A' }
+    ],
+    templateKey: 'type',
+    alias: 'item'
+  },
+  children: [{
+    type: 'cell-slot',
+    attr: { templateType: 'A' },
+    children: [{
+      type: 'div',
+      // not supported yet
+      // attr: {
+      //   '@isComponentRoot': true,
+      //   '@componentProps': {}
+      // },
+      // style: {
+      //   height: '120px',
+      //   justifyContent: 'center',
+      //   alignItems: 'center',
+      //   backgroundColor: 'rgb(162, 217, 192)'
+      // },
+      children: [{
+        type: 'text',
+        // style: {
+        //   fontWeight: 'bold',
+        //   color: '#41B883',
+        //   fontSize: '60px'
+        // },
+        attr: {
+          value: 'BANNER'
+        }
+      }]
+    }, {
+      type: 'text',
+      attr: {
+        value: 'content'
+      }
+    }]
+  }]
+})

+ 22 - 0
test/weex/cases/recycle-list/components/stateless.vue

@@ -0,0 +1,22 @@
+<template>
+  <recycle-list :list-data="longList" template-key="type" alias="item">
+    <cell-slot template-type="A">
+      <banner></banner>
+      <text>content</text>
+    </cell-slot>
+  </recycle-list>
+</template>
+
+<script>
+  // require('./banner.vue')
+  module.exports = {
+    data () {
+      return {
+        longList: [
+          { type: 'A' },
+          { type: 'A' }
+        ]
+      }
+    }
+  }
+</script>

+ 28 - 0
test/weex/cases/recycle-list/inline-style.vdom.js

@@ -0,0 +1,28 @@
+({
+  type: 'recycle-list',
+  attr: {
+    listData: [
+      { type: 'A', color: '#606060' },
+      { type: 'A', color: '#E5E5E5' }
+    ],
+    templateKey: 'type',
+    alias: 'item'
+  },
+  children: [{
+    type: 'cell-slot',
+    attr: { templateType: 'A' },
+    style: {
+      backgroundColor: '#FF6600'
+    },
+    children: [{
+      type: 'text',
+      style: {
+        fontSize: '100px',
+        color: { '@binding': 'item.color' }
+      },
+      attr: {
+        value: 'content'
+      }
+    }]
+  }]
+})

+ 21 - 0
test/weex/cases/recycle-list/inline-style.vue

@@ -0,0 +1,21 @@
+<template>
+  <recycle-list :list-data="longList" template-key="type" alias="item">
+    <cell-slot template-type="A" style="background-color:#FF6600">
+      <text :style="{ fontSize: '100px', color: item.color }">content</text>
+    </cell-slot>
+  </recycle-list>
+</template>
+
+<script>
+  module.exports = {
+    data () {
+      return {
+        longList: [
+          { type: 'A', color: '#606060' },
+          { type: 'A', color: '#E5E5E5' }
+        ]
+      }
+    }
+  }
+</script>
+

+ 38 - 7
test/weex/helpers/index.js

@@ -1,3 +1,5 @@
+import fs from 'fs'
+import path from 'path'
 import * as Vue from '../../../packages/weex-vue-framework'
 import { compile } from '../../../packages/weex-template-compiler'
 import WeexRuntime from 'weex-js-runtime'
@@ -5,7 +7,15 @@ import styler from 'weex-styler'
 
 const styleRE = /<\s*style\s*\w*>([^(<\/)]*)<\/\s*style\s*>/g
 const scriptRE = /<\s*script.*>([^]*)<\/\s*script\s*>/
-const templateRE = /<\s*template\s*>([^]*)<\/\s*template\s*>/
+const templateRE = /<\s*template\s*([^>]*)>([^]*)<\/\s*template\s*>/
+
+export function readFile (filename) {
+  return fs.readFileSync(path.resolve(__dirname, '../cases/', filename), 'utf8')
+}
+
+export function readObject (filename) {
+  return (new Function(`return ${readFile(filename)}`))()
+}
 
 console.debug = () => {}
 
@@ -39,21 +49,28 @@ export function compileVue (source, componentName) {
     }
     const scriptMatch = scriptRE.exec(source)
     const script = scriptMatch ? scriptMatch[1] : ''
-    const { render, staticRenderFns } = compile(templateRE.exec(source)[1])
+    const templateMatch = templateRE.exec(source)
+    const compileOptions = {}
+    if (/\s*recyclable\=?/i.test(templateMatch[1])) {
+      compileOptions.recyclable = true
+    }
+    const res = compile(templateMatch[2], compileOptions)
 
+    const name = 'test_case_' + (Math.random() * 99999999).toFixed(0)
     const generateCode = styles => (`
-      var test_case = Object.assign({
+      var ${name} = Object.assign({
         style: ${JSON.stringify(styles)},
-        render: function () { ${render} },
-        staticRenderFns: ${parseStatic(staticRenderFns)},
+        render: function () { ${res.render} },
+        ${res['@render'] ? ('"@render": function () {' + res['@render'] + '},') : ''}
+        staticRenderFns: ${parseStatic(res.staticRenderFns)},
       }, (function(){
         var module = { exports: {} };
         ${script};
         return module.exports;
       })());
     ` + (componentName
-        ? `Vue.component('${componentName}', test_case);\n`
-        : `test_case.el = 'body';new Vue(test_case);`)
+        ? `Vue.component('${componentName}', ${name});\n`
+        : `${name}.el = 'body';new Vue(${name});`)
     )
 
     let cssText = ''
@@ -71,6 +88,20 @@ export function compileVue (source, componentName) {
   })
 }
 
+export function compileWithDeps (entryPath, deps) {
+  return new Promise((resolve, reject) => {
+    if (Array.isArray(deps)) {
+      Promise.all(deps.map(dep => {
+        return compileVue(readFile(dep.path), dep.name).catch(reject)
+      })).then(depCodes => {
+        compileVue(readFile(entryPath)).then(entryCode => {
+          resolve(depCodes.join('\n') + entryCode)
+        }).catch(reject)
+      }).catch(reject)
+    }
+  })
+}
+
 function isObject (object) {
   return object !== null && typeof object === 'object'
 }