wechat-miniprogram / miniprogram-simulate Goto Github PK
View Code? Open in Web Editor NEW小程序自定义组件测试工具集
License: MIT License
小程序自定义组件测试工具集
License: MIT License
您好,由于小程序的Picker是半封装的,用起来不够友好,所以我在其基础上又加了一层封装。但是现在不知道该怎么单元测试,不知道如何模拟用户改变原生Picker的状态,比如滑动column、点击确定等,不知道您能否提供一个思路呢。
我的wxml中有
使用simulate.load加载控件的时候提示imgRoot.wxs not found
对miniprogram-compiler/bin部分的二进制文件很感兴趣,是官方来的吗
<!-- /components/component.wxml -->
<import src="../../templates/child1/index.wxml" />
<import src="child2.wxml" />
<view>
<template is="child1" />
<template is="child2" />
</view>
<!-- /templates/child1/index.wxml -->
<template name="child1">
<view class="child1" />
</template>
<!-- /components/child2.wxml -->
<template name="child2">
<view class="child2" />
</template>
rootComponent.querySelector('.child1'); // undefined
rootComponent.querySelector('.child2');
在 child2 中引用 child1 也是一样的问题。
情况是组件A
usingComponents: {
"B": "../../B/index"
}
会报invalid template错误
把组件B移动到A目录下就不会有问题了。
我在使用 karma + jasmine 的时候,测试脚本报错 simulate is not defined
,我看文档上说需要用 node_modules/miniprogram-simulate/build.js
来注册 simulate 到 window 上,但是我并没有看到有这个 build.js 文件
这是我的 karma 配置
const path = require('path')
const webpackConfig = {
module: {
rules: [],
},
node: {
__dirname: false,
},
devtool: '#inline-source-map',
}
module.exports = {
frameworks: ['jasmine'],
basePath: path.resolve(__dirname),
files: [
'node_modules/miniprogram-simulate/build.js',
'script/*.spec.js',
],
preprocessors: {
'script/*.spec.js': ['webpack', 'dirname', 'sourcemap'],
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true,
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-mocha-reporter',
'karma-sourcemap-loader',
'karma-filemap-preprocessor',
'karma-dirname-preprocessor',
],
browsers: ['Chrome'],
reporters: ['progress', 'mocha'],
colors: {
success: 'blue',
info: 'bgGreen',
warning: 'cyan',
error: 'bgRed',
},
singleRun: true,
plugins: base.plugins.concat([
'karma-chrome-launcher',
]),
}
在自定义组件章节上有使用Component构造器构造页面的说明,所以理论上这个测试工具是否也可以用来测试页面?有没有相关指引文档?
// 测试代码
let checkVal = null;
let tplId = simulate.load({
template: `
<protocol class="comp" bindcheck="bindCheck>
协议内容
</protocol>
`,
usingComponents: {
'protocol': protocolId
},
methods: {
// 没有起效
bindCheck(e) {
checkVal = e.detail.checked
}
}
});
// protocol组件实现
const comp = {
// .....
methods: {
bindCheck() {
// 这里有输出,triggerEvent有被调用,但外层没有触发对应事件
console.log('trigger')
this.setData({ checked: !this.data.checked });
this.triggerEvent('check', { checked: this.data.checked });
}
}
};
函数作用域中无法正常使用behaviors 定义的对象,这个和实际小程序的运行不一致!
<view class="parent">
<view class="child" />
</view>
const parentComponent = rootComponent.querySelector('.parent');
const childComponent = parentComponent.querySelector('.child'); // undefined
// but rootComponent.querySelector('.child'); // Component instance
这是测试文案
u-icon 组件没有渲染
如果自定义组件的逻辑覆盖了Component的options
function CustomComponent(options) {
options.options = {};
Component(options);
}
miniprogram-simulate/src/index.js
Line 25 in e36a17d
由于没有了classPrefix值, 导致wxss的样式加载失败。
这里应该做递归的merge处理,而不是粗暴的合并。
wxss文件形如
@import '../common/common.wxss';
@import '../sub/sub.wxss';
.index {
color: green;
}
使用代码中的正则表达式进行匹配时
const reg = /@import\s+(?:(?:"([^"]+)")|(?:'([^"]+)'));/ig
由于贪婪匹配规则,第一次就会匹配为
../common/common.wxss';\r\n@import '../sub/sub.wxss
则第二个import文件无法正确匹配。
建议修改为
const reg = /^@import\s+(?:(?:"([^"]+)")|(?:'([^']+)'));$/gmi
使用m声明多行模式,用^和$匹配行头行尾,这样每个文件都能匹配到了
现在是编译过的版本,感谢感谢~
clone官方示例,运行 npm run karma ,报错
Error: invalid componentPath: /Users/WWW/miniprogram-simulate/test/comp5/comp/comp
因为原生小程序代码只要开启 ES6 转 ES5
选项就可以通过 import
方式引入代码, 所以一直没有加上 Babel
但是使用该测试工具集测试含有 import
语句的组件时, 就会报如下错误:
import util from '../../utils/util';
^^^^
SyntaxError: Unexpected identifier
更新 miniprogram-simulate 和其依赖的 miniprogram-compiler 到最新版本即可,这里必须使用官方的编译器,参考 demo:https://github.com/wechat-miniprogram/miniprogram-simulate/tree/master/test/comp7
Originally posted by @JuneAndGreen in #35 (comment)
a.js:
Component({})
a.wxml:
<B></B>
a.json:
{
"component": true,
"usingComponents": {
"B": "../B/b"
}
}
b.js:
Component({})
b.wxml:
<view>component b</view>
b.json:
{
"component": true
}
A-test.js:
const path = require('path')
const simulate = require('miniprogram-simulate')
describe('components/A', () => {
test('base', () => {
const id = simulate.load(path.resolve(__dirname, '../A/a'))
const comp = simulate.render(id)
const parent = document.createElement('parent')
comp.attach(parent)
// log 结果:“dom: <b></b>”
// b 组件应该被渲染吧?
console.log('dom: ', comp.dom.innerHTML)
})
})
// chiild.js
<view class="child"></view>
//index.test.js
childid = simulate.load(child),
id = simulate.load({
template: <child title="xxx"></child>
,
usingComponents: {
child: childid
}
});
comp = simulate.render(id);
comp.querySelector('.child');
class为child的 dom元素无法获取到,打印出的comp.dom.innerHTML是存在的,<child><wx-view class="child--child"></wx-view></child>
通过comp.querySelector('.child--child')页无法获取到
版本号为:
"j-component":的版本号为:"^1.1.2",
"miniprogram-simulate": 的版本号为:"^1.0.2"
现象为:
当wxss中使用@Important引入其他wxss后,会报语法错误 CssSyntaxError: :9:1: Unexpected }
在测试用例中触发按钮点击,回调方法,在方法中调用selectComponent
会报错
TypeError: Cannot read property '__methodCaller' of null
107 | const res = data.res;
108 | const authParam = res.auth_param;
> 109 | const eid = this.selectComponent('#eid');
| ^
110 | // this.$comps.eid.openModal(authParam, type);
111 | eid.openModal(authParam, type);
112 | },
版本号为:
"j-component":的版本号为:"^1.1.2",
"miniprogram-simulate": 的版本号为:"^1.0.1"
部分代码如下:
describe('badge render', () => {
it('default', () => {
const componentId =simulate.load('index', 'comp')
const component =simulate.render(componentId, {})
const parent = document.createElement('parent-wrapper')
component.attach(parent)
expect(component).toMatchSnapshot()
})
it('dot', () => {
const componentId = simulate.load('index', 'comp')
const component =simulate.render(componentId, {dot: true})
const parent = document.createElement('parent-wrapper-dot')
component.attach(parent)
expect(component).toMatchSnapshot()
})
})
结果为:
先调用一次render之后再调用render的时候,id为undefined,会报错。
Component({
// ....
methods: {
test2() {
this.setData({ a: 1, inited: true });
},
test() {
this.setData({ a: 1, inited: true });
},
}
});
// test
test('test', () => {
// ....
const instance = comp.instance;
comp.instance.test2();
comp.instance.test();
});
测试用例正常通过无报错
TypeError: Cannot read property 'parentNode' of undefined
22 | },
23 | test() {
> 24 | this.setData({ a: 1, inited: false });
| ^
25 | },
查看了issue #9
其中的方法没有用 并且也没有说清最后如何解决
版本信息:
jest
: "^24.9.0",
miniprogram-simulate
: "^1.0.8"
miniprogram-compiler
: "^0.1.1"
请问可能会是什么原因呢 麻烦查看一下
谢谢!
官方示例karma-coverage测试代码覆盖率为空。
(用jest测覆盖率也有问题,官方测试覆盖率为 src 下的代码,并不是test目录组件代码)
以下为配置:
reporters: ['progress', 'coverage'], coverageReporter: { type: 'html', dir: 'coverage/' },
希望官方修复下
如题,单元测试时,组件的wxml文件中引用了wxs文件,报错
`编译 .wxml 文件错误:index.wxml:1:1:../../wxs/index.wxs not found from index.wxml
5 | // 此处必须使用这种拼接的写法,否则会找不到文件路径
6 | // 必须使用dist文件夹下的组件,使用src文件夹下面的代码不会加载样式文件
> 7 | const id = simulate.load(path.join(__dirname, '../../dist/components/coupon-wx/index'));
| ^
8 | const comp = simulate.render(id); // 渲染成自定义组件树实例
9 |
10 | const parent = document.createElement('parent-wrapper'); // 创建父亲节点
at wxmlToJS (node_modules/miniprogram-compiler/src/wcc.js:110:11)
at Object.wxmlToJs (node_modules/miniprogram-compiler/src/index.js:24:27)
at Object.getWxml (node_modules/miniprogram-simulate/src/compile.js:29:52)
at register (node_modules/miniprogram-simulate/src/index.js:98:30)
at Object.load (node_modules/miniprogram-simulate/src/index.js:141:16)
at Object.<anonymous> (test/components/coupon-wx.test.js:7:23)`
setData({ a: 1}, () => {
...
})
现在还不支持 setData 的回调吗
其它api都好模拟,唯独request复杂许多,特别是针对微信请求新开发一个请求库的时候,比如我仓库的axios for小程序库。
自己模拟的话感觉这个测试觉得有些自欺欺人,建议将小程序开发者工具的wx.request实现源码剥离放出来(可能需要跨部门协商?)
代码:
// dialog.js
Component({
properties: {
visible: {
type: Boolean,
value: false
}
}
})
// dialog.wxml
<view wx:if="{{visible}}">内容</view>
// dialog.test.js
const component = simulate.render(dialog, {visible: true}) // 这里会报 Cannot read property 'parentNode' of undefined
这个考虑支持吗?
如题
FAIL test/components/formid.spec.js
● formid component › should go to page when submit
TypeError: Cannot read property 'removeChild' of null
35 | it('should go to page when submit', (done) => {
36 | var expectedPage = '/mock/page',
> 37 | comp = simulate.render(comId, {
| ^
38 | page: expectedPage
39 | })
40 |
at document.querySelectorAll.forEach.style (node_modules/[email protected]@miniprogram-simulate/src/wxss.js:103:22)
at Proxy.forEach (<anonymous>)
at Object.insert (node_modules/[email protected]@miniprogram-simulate/src/wxss.js:102:44)
at Object.render (node_modules/[email protected]@miniprogram-simulate/src/index.js:141:10)
at Object.render (test/components/formid.spec.js:37:23)
触发按钮点击会回调对应的事件回调方法,但是方法里面是异步的逻辑
希望可以在异步流程完成之后在页面元素是否正确
const btn = comp.querySelector('.');
reqBtn.dispatchEvent('tap', {});
// 等待事件
await simulate.sleep(10);
// 这里还要等待对应的回调方法执行完成
// 检查状态
自定义组件中使用内置behaviors,behaviors: ['wx://component-export'] , 单测报错
TypeError: Cannot read property '_unprepared' of undefined;
现在支持使用内置 behaviors嘛?
const comp = simulate.render(id, {
observerCall: true
}); // 渲染自定义组件
observerCall: {
type: Boolean,
value: false,
observer(val) {
this.setData({
observerCalled: true
});
}
},
之后打印data属性,发现没有observerCalled
属性
由于wxss处理的时候正则的有问题导致,添加前缀错误,进而影响csso压缩。
@-webkit-keyframes headShake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
6.5% {
-webkit-transform: translateX(-6px) rotateY(-9deg);
transform: translateX(-6px) rotateY(-9deg);
}
18.5% {
-webkit-transform: translateX(5px) rotateY(7deg);
transform: translateX(5px) rotateY(7deg);
}
31.5% {
-webkit-transform: translateX(-3px) rotateY(-5deg);
transform: translateX(-3px) rotateY(-5deg);
}
43.5% {
-webkit-transform: translateX(2px) rotateY(3deg);
transform: translateX(2px) rotateY(3deg);
}
50% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
.main {
}
// 举例来说,这是一个组件的properties
properties: {
title: {
type: String,
value: '设置title 属性改变这里的值 3',
observer: function(newVal, oldVal) { //数据监听
console.log('Properties observer starting ... ')
console.log(newVal, oldVal)
}
}
}
// 如果传入的值是String 类型,则不能正确触发上面的 observer
let comp = simulate.render(myid, {
title: 'MyName'
})
// 但是如果传入的值是数组,则可以正确触发 observer 事件
let comp = simulate.render(myid, {
title: ['MyName']
})
Windows下git直接获取项目,用webstorm打开项目后,install依赖。然后跑all test.
只有一条case不对
` Error: expect(received).toBe(expected) // Object.is equality
at Object.toBe (D:\GitWS\miniprogram-simulate\test\unit\wxss.test.js:6:72)
at Object.asyncJestTest (D:\GitWS\miniprogram-simulate\node_modules\jest-jasmine2\build\jasmine_async.js:108:37)
at resolve (D:\GitWS\miniprogram-simulate\node_modules\jest-jasmine2\build\queue_runner.js:56:12)
at new Promise (<anonymous>)
at mapper (D:\GitWS\miniprogram-simulate\node_modules\jest-jasmine2\build\queue_runner.js:43:19)
at promise.then (D:\GitWS\miniprogram-simulate\node_modules\jest-jasmine2\build\queue_runner.js:87:41)
at processTicksAndRejections (internal/process/next_tick.js:81:5)`
点击查看不同,Click to see the differences
在Comparison Failure页面显示:
Contents have differences only in line separators.
Excepted 是LF, Actual是CRLF
尝试:
修改了Webstorm里的settings->editor->code style->line separators 为Unix and OS X(\n)
仍然有错误。
重新编辑了所有对比部门的换行,还是有错误。
请问:
有谁遇到类似的问题么?是如何解决的?
组件内部使用 boundingClientRect 获取了某个节点的位置信息,但是使用miniprogram-simulate测试组件内的方法时,获取到的节点信息宽高都是0
无论我如何修改路径都是报错:invalid componentPath:
我的代码:(路径绝对是正确的,请问是什么原因造成的呢)
const id = simulate.load(path.join(__dirname, '../components/index')) // 加载自定义组件,返回组件 id
// const id = simulate.load('/components/index')
test('computed property changes', () => {
let funcTriggeringCount = 0
const innerComponentId = _.load({
template: '<view>{{a}}+{{b}}={{c}}</view>',
behaviors: [computedBehavior],
properties: {
a: {
type: Number,
value: -1,
},
b: String,
},
computed: {
c(data) {
funcTriggeringCount++
return data.a + data.b
}
},
})
const outerComponentId = _.load({
usingComponents: {
inner: innerComponentId,
},
data: {
a: 1,
b: 2,
},
template: '<inner a="{{a}}" b="{{b}}"></inner>',
})
const component = _.render(outerComponentId)
expect(_.match(component.dom, '<inner><wx-view>1+2=3</wx-view></inner>')).toBe(true)
// 比较有疑问的是为什么这里是2
expect(funcTriggeringCount).toBe(2)
component.setData({a: 100, b: 200})
expect(_.match(component.dom, '<inner><wx-view>100+200=300</wx-view></inner>')).toBe(true)
expect(funcTriggeringCount).toBe(3)
})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.