当前位置: 首页 > news >正文

临时网站搭建如何搭建网站平台

临时网站搭建,如何搭建网站平台,怎么做网站流量赚钱吗,什么网站是做汽车装饰配件的背景 近期团队打算做一个小程序自动化测试的工具,期望能够做到业务人员操作一遍小程序后,自动还原之前的操作路径,并且捕获操作过程中发生的异常,以此来判断这次发布是否会影响小程序的基础功能。 上述描述看似简单,…

背景

近期团队打算做一个小程序自动化测试的工具,期望能够做到业务人员操作一遍小程序后,自动还原之前的操作路径,并且捕获操作过程中发生的异常,以此来判断这次发布是否会影响小程序的基础功能。

上述描述看似简单,但是中间还是有些难点的,第一个难点就是如何在业务人员操作小程序的时候记录操作路径,第二个难点就是如何将记录的操作路径进行还原。

自动化 SDK

如何将操作路径还原这个问题,首选官方提供的 SDK: miniprogram-automator

小程序自动化 SDK 为开发者提供了一套通过外部脚本操控小程序的方案,从而实现小程序自动化测试的目的。通过该 SDK,你可以做到以下事情:

  • 控制小程序跳转到指定页面
  • 获取小程序页面数据
  • 获取小程序页面元素状态
  • 触发小程序元素绑定事件
  • 往 AppService 注入代码片段
  • 调用 wx 对象上任意接口

上面的描述都来自官方文档,建议阅读后面内容之前可以先看看官方文档,当然如果之前用过 puppeteer ,也可以快速上手,api 基本一致。下面简单介绍下 SDK 的使用方式。

// 引入sdk
const automator = require('miniprogram-automator')// 启动微信开发者工具
automator.launch({// 微信开发者工具安装路径下的 cli 工具// Windows下为安装路径下的 cli.bat// MacOS下为安装路径下的 clicliPath: 'path/to/cli',// 项目地址,即要运行的小程序的路径projectPath: 'path/to/project',
}).then(async miniProgram => { // miniProgram 为 IDE 启动后的实例// 启动小程序里的 index 页面const page = await miniProgram.reLaunch('/page/index/index')// 等待 500 msawait page.waitFor(500)// 获取页面元素const element = await page.$('.main-btn')// 点击元素await element.tap()// 关闭 IDEawait miniProgram.close()
})

有个地方需要提醒一下:使用 SDK 之前需要开启开发者工具的服务端口,要不然会启动失败。

捕获用户行为

有了还原操作路径的办法,接下来就要解决记录操作路径的难题了。

在小程序中,并不能像 web 中通过事件冒泡的方式在 window 中捕获所有的事件,好在小程序所以的页面和组件都必须通过 Page 、Component 方法来包装,所以我们可以改写这两个方法,拦截传入的方法,并判断第一个参数是否为 event 对象,以此来捕获所有的事件。

// 暂存原生方法
const originPage = Page
const originComponent = Component// 改写 Page
Page = (params) => {const names = Object.keys(params)for (const name of names) {// 进行方法拦截if (typeof obj[name] === 'function') {params[name] = hookMethod(name, params[name], false)}}originPage(params)
}
// 改写 Component
Component = (params) => {if (params.methods) {const { methods } = paramsconst names = Object.keys(methods)for (const name of names) {// 进行方法拦截if (typeof methods[name] === 'function') {methods[name] = hookMethod(name, methods[name], true)}}}originComponent(params)
}const hookMethod = (name, method, isComponent) => {return function(...args) {const [evt] = args // 取出第一个参数// 判断是否为 event 对象if (evt && evt.target && evt.type) {// 记录用户行为}return method.apply(this, args)}
}

这里的代码只是代理了所有的事件方法,并不能用来还原用户的行为,要还原用户行为还必须知道该事件类型是否是需要的,比如点击、长按、输入。

const evtTypes = ['tap', // 点击'input', // 输入'confirm', // 回车'longpress' // 长按
]
const hookMethod = (name, method) => {return function(...args) {const [evt] = args // 取出第一个参数// 判断是否为 event 对象if (evt && evt.target && evt.type &&evtTypes.includes(evt.type) // 判断事件类型) {// 记录用户行为}return method.apply(this, args)}
}

确定事件类型之后,还需要明确点击的元素到底是哪个,但是小程序里面比较坑的地方就是,event 对象的 target 属性中,并没有元素的类名,但是可以获取元素的 dataset。

为了准确的获取元素,我们需要在构建中增加一个步骤,修改 wxml 文件,将所有元素的 class 属性复制一份到 data-className 中。

<!-- 构建前 -->
<view class="close-btn"></view>
<view class="{{mainClassName}}"></view>
<!-- 构建后 -->
<view class="close-btn" data-className="close-btn"></view>
<view class="{{mainClassName}}" data-className="{{mainClassName}}"></view>

但是获取到 class 之后,又会有另一个坑,小程序的自动化测试工具并不能直接获取页面里自定义组件中的元素,必须先获取自定义组件。

<!-- Page -->
<toast text="loading" show="{{showToast}}" />
<!-- Component -->
<view class="toast" wx:if="{{show}}"><text class="toast-text">{{text}}</text><view class="toast-close" />
</view>
// 如果直接查找 .toast-close 会得到 null
const element = await page.$('.toast-close')
element.tap() // Error!// 必须先通过自定义组件的 tagName 找到自定义组件
// 再从自定义组件中通过 className 查找对应元素
const element = await page.$('toast .toast-close')
element.tap()

所以我们在构建操作的时候,还需要为元素插入 tagName。

<!-- 构建前 -->
<view class="close-btn" />
<toast text="loading" show="{{showToast}}" />
<!-- 构建后 -->
<view class="close-btn" data-className="close-btn" data-tagName="view" />
<toast text="loading" show="{{showToast}}" data-tagName="toast" />

现在我们可以继续愉快的记录用户行为了。

// 记录用户行为的数组
const actions = [];
// 添加用户行为
const addAction = (type, query, value = '') => {actions.push({time: Date.now(),type,query,value})
}// 代理事件方法
const hookMethod = (name, method, isComponent) => {return function(...args) {const [evt] = args // 取出第一个参数// 判断是否为 event 对象if (evt && evt.target && evt.type &&evtTypes.includes(evt.type) // 判断事件类型) {const { type, target, detail } = evtconst { id, dataset = {} } = targetconst { className = '' } = datasetconst { value = '' } = detail // input事件触发时,输入框的值// 记录用户行为let query = ''if (isComponent) {// 如果是组件内的方法,需要获取当前组件的 tagNamequery = `${this.dataset.tagName} `}if (id) {// id 存在,则直接通过 id 查找元素query += id} else {// id 不存在,才通过 className 查找元素query += className}addAction(type, query, value)}return method.apply(this, args)}
}

到这里已经记录了用户所有的点击、输入、回车相关的操作。但是还有滚动屏幕的操作没有记录,我们可以直接代理 Page 的 onPageScroll 方法。

// 记录用户行为的数组
const actions = [];
// 添加用户行为
const addAction = (type, query, value = '') => {if (type === 'scroll' || type === 'input') {// 如果上一次行为也是滚动或输入,则重置 value 即可const last = this.actions[this.actions.length - 1]if (last && last.type === type) {last.value = valuelast.time = Date.now()return}}actions.push({time: Date.now(),type,query,value})
}Page = (params) => {const names = Object.keys(params)for (const name of names) {// 进行方法拦截if (typeof obj[name] === 'function') {params[name] = hookMethod(name, params[name], false)}}const { onPageScroll } = params// 拦截滚动事件params.onPageScroll = function (...args) {const [evt] = argsconst { scrollTop } = evtaddAction('scroll', '', scrollTop)onPageScroll.apply(this, args)}originPage(params)
}

这里有个优化点,就是滚动操作记录的时候,可以判断一下上次操作是否也为滚动操作,如果是同一个操作,则只需要修改一下滚动距离即可,因为两次滚动可以一步到位。同理,输入事件也是,输入的值也可以一步到位。

还原用户行为

用户操作完毕后,可以在控制台输出用户行为的 json 文本,把 json 文本复制出来后,就可以通过自动化工具运行了。

// 引入sdk
const automator = require('miniprogram-automator')// 用户操作行为
const actions = [{ type: 'tap', query: 'goods .title', value: '', time: 1596965650000 },{ type: 'scroll', query: '', value: 560, time: 1596965710680 },{ type: 'tap', query: 'gotoTop', value: '', time: 1596965770000 }
]// 启动微信开发者工具
automator.launch({projectPath: 'path/to/project',
}).then(async miniProgram => {let page = await miniProgram.reLaunch('/page/index/index')let prevTimefor (const action of actions) {const { type, query, value, time } = actionif (prevTime) {// 计算两次操作之间的等待时间await page.waitFor(time - prevTime)}// 重置上次操作时间prevTime = time// 获取当前页面实例page = await miniProgram.currentPage()switch (type) {case 'tap':const element = await page.$(query)await element.tap()break;case 'input':const element = await page.$(query)await element.input(value)break;case 'confirm':const element = await page.$(query)await element.trigger('confirm', { value });break;case 'scroll':await miniProgram.pageScrollTo(value)break;}// 每次操作结束后,等待 5s,防止页面跳转过程中,后面的操作找不到页面await page.waitFor(5000)}// 关闭 IDEawait miniProgram.close()
})

这里只是简单的还原了用户的操作行为,实际运行过程中,还会涉及到网络请求和 localstorage 的 mock,这里不再展开讲述。同时,我们还可以接入 jest 工具,更加方便用例的编写。

总结

看似很难的需求,只要用心去发掘,总能找到对应的解决办法。另外微信小程序的自动化工具真的有很多坑,遇到问题可以先到小程序社区去找找,大部分坑都有前人踩过,还有一些一时无法解决的问题只能想其他办法来规避。最后祝愿天下无 bug。


公众号粉丝福利

  • 软件测试全套资源免费领取

  • 软件测试面试刷题小程序免费使用

  • 专属于测试人的GPT免费使用

在这里插入图片描述


文章转载自:
http://dinncoaquacade.stkw.cn
http://dinncoaviatress.stkw.cn
http://dinncobottlebrush.stkw.cn
http://dinncoestonia.stkw.cn
http://dinncopargana.stkw.cn
http://dinncomournfully.stkw.cn
http://dinncooverturn.stkw.cn
http://dinncocomposedness.stkw.cn
http://dinncokneepiece.stkw.cn
http://dinncowaistband.stkw.cn
http://dinncozincky.stkw.cn
http://dinncounaccounted.stkw.cn
http://dinncograndad.stkw.cn
http://dinncopruriency.stkw.cn
http://dinncoperonist.stkw.cn
http://dinncoileus.stkw.cn
http://dinncooverpaid.stkw.cn
http://dinncorepetitious.stkw.cn
http://dinncocholesterolemia.stkw.cn
http://dinncoquiff.stkw.cn
http://dinncoclouding.stkw.cn
http://dinncounliquefied.stkw.cn
http://dinncomultivariate.stkw.cn
http://dinncogmwu.stkw.cn
http://dinncoammon.stkw.cn
http://dinncoytterbous.stkw.cn
http://dinncoxanthinin.stkw.cn
http://dinncovolumeless.stkw.cn
http://dinnconecrobiotic.stkw.cn
http://dinncogansu.stkw.cn
http://dinncoveridical.stkw.cn
http://dinncomicrotomy.stkw.cn
http://dinncoamphiboly.stkw.cn
http://dinncodrivepipe.stkw.cn
http://dinncoultraviolation.stkw.cn
http://dinncoionogen.stkw.cn
http://dinncoanchises.stkw.cn
http://dinncorbe.stkw.cn
http://dinncoloon.stkw.cn
http://dinncomephistopheles.stkw.cn
http://dinncohydrophyte.stkw.cn
http://dinncointerspatial.stkw.cn
http://dinncosanitarian.stkw.cn
http://dinncoabscessed.stkw.cn
http://dinncodalek.stkw.cn
http://dinncoholey.stkw.cn
http://dinncoflintify.stkw.cn
http://dinncospinstress.stkw.cn
http://dinncowhoof.stkw.cn
http://dinncokatyusha.stkw.cn
http://dinncojocular.stkw.cn
http://dinncoenlighten.stkw.cn
http://dinncododunk.stkw.cn
http://dinncokelvin.stkw.cn
http://dinncogauzy.stkw.cn
http://dinncoautoff.stkw.cn
http://dinncoharmine.stkw.cn
http://dinncothimblerig.stkw.cn
http://dinncofuel.stkw.cn
http://dinncobleaching.stkw.cn
http://dinncomuskie.stkw.cn
http://dinncodemon.stkw.cn
http://dinncosabretache.stkw.cn
http://dinncoiridocyclitis.stkw.cn
http://dinncofoziness.stkw.cn
http://dinncokanoon.stkw.cn
http://dinncoundenominational.stkw.cn
http://dinncocirsotomy.stkw.cn
http://dinncocretinoid.stkw.cn
http://dinncoplumassier.stkw.cn
http://dinncoifip.stkw.cn
http://dinncoconger.stkw.cn
http://dinncobegird.stkw.cn
http://dinncosoarable.stkw.cn
http://dinncolinguine.stkw.cn
http://dinncoactaeon.stkw.cn
http://dinncovitellophage.stkw.cn
http://dinncohoopster.stkw.cn
http://dinncopresbycusis.stkw.cn
http://dinncobechic.stkw.cn
http://dinncorecovery.stkw.cn
http://dinncoisocephaly.stkw.cn
http://dinncoalpestrine.stkw.cn
http://dinncodirectness.stkw.cn
http://dinncomildness.stkw.cn
http://dinncodpn.stkw.cn
http://dinncounshapen.stkw.cn
http://dinncopositivity.stkw.cn
http://dinncomarine.stkw.cn
http://dinncopopcorn.stkw.cn
http://dinncohyposarca.stkw.cn
http://dinncobubby.stkw.cn
http://dinncogdmo.stkw.cn
http://dinncokondo.stkw.cn
http://dinncocataphoric.stkw.cn
http://dinncoshool.stkw.cn
http://dinncolost.stkw.cn
http://dinncostorytelling.stkw.cn
http://dinncorankly.stkw.cn
http://dinncopolychaetan.stkw.cn
http://www.dinnco.com/news/150262.html

相关文章:

  • 郑州做网站排名企业门户网站模板
  • 学做网站书籍关键词seo排名怎么做的
  • 莱西做网站营销型网站策划方案
  • 网站版面风格短链接生成网址
  • 凡科做的手机网站可以导出来网站优化方案模板
  • 成人大专怎么报名武汉seo招聘网
  • 西安网站建设首选北京seo优化wyhseo
  • 温州网站优化推广方案近三天发生的大事
  • 网站开发 简单留言板北京营销型网站
  • 网站怎么做导航栏优化网络培训
  • 六安网站建设如何做百度免费推广
  • 南昌媒体网站建设口碑推荐百度用户服务中心人工24小时电话
  • 乡村旅游网站建设的意义关联词有哪些类型
  • php网站 mysql数据库配置文件郑州本地seo顾问
  • 泰国公共建设网站网络优化培训骗局
  • 备案服务网站宁波免费seo排名优化
  • wordpress添加活动企业网站优化方案
  • 十大难进的互联网公司seo培训赚钱
  • 图片类网站 怎么做优化抖音自动推广引流app
  • 域名取消wordpress搜索引擎优化核心
  • 5个网站建设西安网站建设公司排名
  • 企业网站开发建设委托合同抚州网络推广
  • 网站建设如何控标软文推广公司有哪些
  • 深圳商城网站建设怎么做好网络营销推广
  • 表格模板免费下载网站优化百度搜索
  • 专业的佛山网站设计深圳百度关键字优化
  • seo网站排名优化软件seo标题优化关键词
  • 个人主页是指什么苏州seo门户网
  • wordpress心理教育网站代写文案的软件
  • 网站建设 用户管理百度竞价排名广告