From 232dd85f853d69fe3648a92be0d56f7359bc9210 Mon Sep 17 00:00:00 2001 From: Hanks Date: Mon, 30 Oct 2017 19:29:16 -0500 Subject: [PATCH] test(weex): support testing the virtual dom generated form *.vue files (#6944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compile the *.vue file into js code, then run it in Weex context, and compare the generate virtual dom. It’s a black-box testing for `weex-template-compiler`, `weex-styler`,`weex-vue-framework` and `weex-js-runtime`. --- package.json | 3 +- test/weex/cases/cases.spec.js | 72 ++++++++++++++++++++++ test/weex/cases/event/click.after.vdom.js | 10 +++ test/weex/cases/event/click.before.vdom.js | 10 +++ test/weex/cases/event/click.vue | 20 ++++++ test/weex/cases/render/sample.vdom.js | 17 +++++ test/weex/cases/render/sample.vue | 23 +++++++ test/weex/helpers/index.js | 71 ++++++++++++++++++++- 8 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 test/weex/cases/cases.spec.js create mode 100644 test/weex/cases/event/click.after.vdom.js create mode 100644 test/weex/cases/event/click.before.vdom.js create mode 100644 test/weex/cases/event/click.vue create mode 100644 test/weex/cases/render/sample.vdom.js create mode 100644 test/weex/cases/render/sample.vue diff --git a/package.json b/package.json index 09af3ed7f70..085e2890989 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,8 @@ "typescript": "^2.5.2", "uglify-js": "^3.0.15", "webpack": "^2.6.1", - "weex-js-runtime": "^0.23.0" + "weex-js-runtime": "^0.23.0", + "weex-styler": "^0.3.0" }, "config": { "commitizen": { diff --git a/test/weex/cases/cases.spec.js b/test/weex/cases/cases.spec.js new file mode 100644 index 00000000000..291600dfb24 --- /dev/null +++ b/test/weex/cases/cases.spec.js @@ -0,0 +1,72 @@ +import fs from 'fs' +import path from 'path' +import { + compileVue, + 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`) + const target = readObject(`${name}.vdom.js`) + return done => { + compileVue(source).then(code => { + const id = String(Date.now() * Math.random()) + const instance = createInstance(id, code) + setTimeout(() => { + expect(getRoot(instance)).toEqual(target) + done() + }, 50) + }).catch(err => { + expect(err).toBe(null) + done() + }) + } +} + +// Create event test case, will trigger the first bind event +function createEventTestCase (name) { + const source = readFile(`${name}.vue`) + const before = readObject(`${name}.before.vdom.js`) + const after = readObject(`${name}.after.vdom.js`) + return done => { + compileVue(source).then(code => { + const id = String(Date.now() * Math.random()) + const instance = createInstance(id, code) + setTimeout(() => { + expect(getRoot(instance)).toEqual(before) + const event = getEvents(instance)[0] + fireEvent(instance, event.ref, event.type, {}) + setTimeout(() => { + expect(getRoot(instance)).toEqual(after) + done() + }, 50) + }, 50) + }).catch(err => { + expect(err).toBe(null) + done() + }) + } +} + +describe('Usage', () => { + describe('render', () => { + it('sample', createRenderTestCase('render/sample')) + }) + + describe('event', () => { + it('click', createEventTestCase('event/click')) + }) +}) + diff --git a/test/weex/cases/event/click.after.vdom.js b/test/weex/cases/event/click.after.vdom.js new file mode 100644 index 00000000000..eab1a36e7a3 --- /dev/null +++ b/test/weex/cases/event/click.after.vdom.js @@ -0,0 +1,10 @@ +({ + type: 'div', + event: ['click'], + children: [{ + type: 'text', + attr: { + value: '43' + } + }] +}) diff --git a/test/weex/cases/event/click.before.vdom.js b/test/weex/cases/event/click.before.vdom.js new file mode 100644 index 00000000000..de278b3a100 --- /dev/null +++ b/test/weex/cases/event/click.before.vdom.js @@ -0,0 +1,10 @@ +({ + type: 'div', + event: ['click'], + children: [{ + type: 'text', + attr: { + value: '42' + } + }] +}) diff --git a/test/weex/cases/event/click.vue b/test/weex/cases/event/click.vue new file mode 100644 index 00000000000..508782c59e7 --- /dev/null +++ b/test/weex/cases/event/click.vue @@ -0,0 +1,20 @@ + + + diff --git a/test/weex/cases/render/sample.vdom.js b/test/weex/cases/render/sample.vdom.js new file mode 100644 index 00000000000..6e213a506d9 --- /dev/null +++ b/test/weex/cases/render/sample.vdom.js @@ -0,0 +1,17 @@ +({ + type: 'div', + style: { + justifyContent: 'center' + }, + children: [{ + type: 'text', + attr: { + value: 'Yo' + }, + style: { + color: '#41B883', + fontSize: '233px', + textAlign: 'center' + } + }] +}) diff --git a/test/weex/cases/render/sample.vue b/test/weex/cases/render/sample.vue new file mode 100644 index 00000000000..0251b3d6fba --- /dev/null +++ b/test/weex/cases/render/sample.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/test/weex/helpers/index.js b/test/weex/helpers/index.js index ca4b3436b60..653ded34c16 100644 --- a/test/weex/helpers/index.js +++ b/test/weex/helpers/index.js @@ -1,6 +1,11 @@ import * as Vue from '../../../packages/weex-vue-framework' import { compile } from '../../../packages/weex-template-compiler' import WeexRuntime from 'weex-js-runtime' +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*>/ console.debug = () => {} @@ -10,6 +15,10 @@ export function strToRegExp (str) { return new RegExp(str.replace(matchOperatorsRe, '\\$&')) } +function parseStatic (fns) { + return '[' + fns.map(fn => `function () { ${fn} }`).join(',') + ']' +} + export function compileAndStringify (template) { const { render, staticRenderFns } = compile(template) return { @@ -18,8 +27,48 @@ export function compileAndStringify (template) { } } -function parseStatic (fns) { - return '[' + fns.map(fn => `function () { ${fn} }`).join(',') + ']' +/** + * Compile *.vue file into js code + * @param {string} source raw text of *.vue file + * @param {string} componentName whether compile to a component + */ +export function compileVue (source, componentName) { + return new Promise((resolve, reject) => { + if (!templateRE.test(source)) { + return reject('No Template!') + } + const scriptMatch = scriptRE.exec(source) + const script = scriptMatch ? scriptMatch[1] : '' + const { render, staticRenderFns } = compile(templateRE.exec(source)[1]) + + const generateCode = styles => (` + var test_case = Object.assign({ + style: ${JSON.stringify(styles)}, + render: function () { ${render} }, + staticRenderFns: ${parseStatic(staticRenderFns)}, + }, (function(){ + var module = { exports: {} }; + ${script}; + return module.exports; + })()); + ` + (componentName + ? `Vue.component('${componentName}', test_case);\n` + : `test_case.el = 'body';new Vue(test_case);`) + ) + + let cssText = '' + let styleMatch = null + while ((styleMatch = styleRE.exec(source))) { + cssText += `\n${styleMatch[1]}\n` + } + styler.parse(cssText, (error, result) => { + if (error) { + return reject(error) + } + resolve(generateCode(result.jsonStyle)) + }) + resolve(generateCode({})) + }) } function isObject (object) { @@ -47,6 +96,24 @@ export function getRoot (instance) { return omitUseless(instance.document.body.toJSON()) } +// Get all binding events in the instance +export function getEvents (instance) { + const events = [] + const recordEvent = node => { + if (!node) { return } + if (Array.isArray(node.event)) { + node.event.forEach(type => { + events.push({ ref: node.ref, type }) + }) + } + if (Array.isArray(node.children)) { + node.children.forEach(recordEvent) + } + } + recordEvent(instance.document.body.toJSON()) + return events +} + export function fireEvent (instance, ref, type, event = {}) { const el = instance.document.getRef(ref) if (el) {