[관련 학습 권장 사항: WeChat 미니 프로그램 튜토리얼]
Background
최근 팀에서는 미니 프로그램을 자동으로 테스트하는 도구를 만들 계획이며, 이를 통해 비즈니스 담당자가 운영 후 이전 작업을 자동으로 복원할 수 있기를 바랍니다. 미니 프로그램 경로 및 작업 중에 발생하는 예외를 캡처하여 이번 릴리스가 미니 프로그램의 기본 기능에 영향을 미치는지 여부를 확인합니다.

위의 설명은 간단해 보이지만 여전히 중간에 난관이 좀 있습니다. 첫 번째 난관은 사업 담당자가 미니 프로그램을 운영할 때 작업 경로를 기록하는 방법이고, 두 번째 난관은 휴대하는 방법입니다. 기록된 작업 경로를 축소합니다.
Automation SDK
작업 경로를 복원하는 방법은 무엇입니까? 이 문제의 경우 공식 SDK인 miniprogram-automator
를 사용하는 것이 좋습니다. miniprogram-automator
。
小程序自动化 SDK 为开发者提供了一套通过外部脚本操控小程序的소규모 프로그램 자동화 테스트에 대한 자세한 설명,从而实现小程序自动化测试的目的。通过该 SDK,你可以做到以下事情:
- 控制小程序跳转到指定页面
- 获取小程序页面数据
- 获取小程序页面元素状态
- 触发小程序元素绑定事件
- 往 AppService 注入代码片段
- 调用 wx 对象上任意接口
- ...
上面的描述都来自官方文档,建议阅读后面内容之前可以先看看官方文档,当然如果之前用过 puppeteer ,也可以快速上手,api 基本一致。下面简单介绍下 SDK 的使用方式。
// 引入sdkconst automator = require('miniprogram-automator')// 启动微信开发者工具automator.launch({ // 微信开发者工具安装路径下的 cli 工具 // Windows下为安装路径下的 cli.bat // MacOS下为安装路径下的 cli cliPath: 'path/to/cli', // 项目地址,即要运行的小程序的路径 projectPath: 'path/to/project', }).then(async miniProgram => { // miniProgram 为 IDE 启动后的实例 // 启动小程序里的 index 页面 const page = await miniProgram.reLaunch('/page/index/index') // 等待 500 ms await page.waitFor(500) // 获取页面元素 const element = await page.$('.main-btn') // 点击元素 await element.tap() // 关闭 IDE await miniProgram.close() })复制代码
有个地方需要提醒一下:使用 SDK 之前需要开启开发者工具的服务端口,要不然会启动失败。

捕获用户行为
有了还原操作路径的办法,接下来就要解决记录操作路径的难题了。
在小程序中,并不能像 web 中通过事件冒泡的方式在 window 中捕获所有的事件,好在小程序所以的页面和组件都必须通过 Page
、Component
方法来包装,所以我们可以改写这两个方法,拦截传入的方法,并判断第一个参数是否为 event
对象,以此来捕获所有的事件。
// 暂存原生方法const originPage = Pageconst originComponent = Component// 改写 PagePage = (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) }// 改写 ComponentComponent = (params) => { if (params.methods) { const { methods } = params const 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></view><view></view><!-- 构建后 --><view></view><view></view>复制代码
但是获取到 class 之后,又会有另一个坑,小程序的自动化测试工具并不能直接获取页面里自定义组件中的元素,必须先获取自定义组件。
<!-- Page --><toast></toast><!-- Component --><view> <text>{{text}}</text> <view></view></view>复制代码
// 如果直接查找 .toast-close 会得到 nullconst element = await page.$('.toast-close') element.tap() // Error!// 必须先通过自定义组件的 tagName 找到自定义组件// 再从自定义组件中通过 className 查找对应元素const element = await page.$('toast .toast-close') element.tap()复制代码
所以我们在构建操作的时候,还需要为元素插入 tagName。
<!-- 构建前 --><view></view><toast></toast><!-- 构建后 --><view></view><toast></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 } = evt const { id, dataset = {} } = target const { className = '' } = dataset const { value = '' } = detail // input事件触发时,输入框的值 // 记录用户行为 let query = '' if (isComponent) { // 如果是组件内的方法,需要获取当前组件的 tagName query = `${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
- 미니 프로그램을 제어하여 지정된 페이지로 이동
- 미니 프로그램 페이지 데이터 가져오기
- 미니 가져오기 프로그램 페이지 요소 상태
- 미니 프로그램 요소 바인딩 이벤트 트리거
- AppService에 코드 조각 삽입
- wx 개체에서 인터페이스 호출
- ...
// 记录用户行为的数组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 = value
last.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] = args const { scrollTop } = evt
addAction('scroll', '', scrollTop)
onPageScroll.apply(this, args)
}
originPage(params)
}复制代码
한 가지 주의할 점이 있습니다. SDK를 사용하기 전에 개발자 도구의 서비스 포트를 열어야 합니다. 그렇지 않으면 시작이 실패합니다.

사용자 행동 캡처🎜🎜작업 경로 복원 방법으로 다음 단계는 녹음 문제를 해결하는 것입니다. 작업 경로. 🎜🎜미니 프로그램에서는 웹처럼 이벤트 버블링을 통해 창에 있는 모든 이벤트를 캡처할 수는 없습니다. 다행히 미니 프로그램의 모든 페이지와 구성 요소는 페이지
, 를 통과해야 합니다. 래핑할 구성 요소
메서드를 사용하여 이 두 메서드를 다시 작성하고 들어오는 메서드를 가로채고 첫 번째 매개변수가 모든 이벤트를 캡처하는 event
개체인지 확인합니다. 🎜// 引入sdkconst 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 prevTime for (const action of actions) { const { type, query, value, time } = action if (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)
} // 关闭 IDE
await miniProgram.close()
})复制代码
🎜여기의 코드는 모든 이벤트 메소드만을 나타내며 사용자의 행동을 복원하는 데 사용할 수 없습니다. 사용자의 행동을 복원하려면 클릭, 길게 누르기, 입력 등 이벤트 유형이 필요한지 여부도 알아야 합니다. 🎜rrreee🎜이벤트 유형을 결정한 후에도 어떤 요소가 클릭되었는지 명확히 해야 합니다. 그러나 미니 프로그램의 함정은 이벤트 개체의 대상 속성에 해당 요소의 클래스 이름이 없지만 해당 요소의 데이터 세트가 있다는 것입니다. 요소를 얻을 수 있습니다. 🎜🎜
🎜🎜🎜🎜요소를 정확하게 얻으려면 구성 단계를 추가하고 wxml 파일을 수정한 다음 class
속성을 복사해야 합니다. data-className
의 모든 요소. 🎜rrreee🎜하지만 클래스를 얻은 후에는 또 다른 함정이 있습니다. 미니 프로그램의 자동화된 테스트 도구는 페이지의 사용자 정의 구성 요소를 직접 얻을 수 없습니다. 먼저 사용자 정의 구성 요소를 얻어야 합니다. 🎜rrreeerrreee🎜따라서 작업을 빌드할 때 요소에 tagName도 삽입해야 합니다. 🎜rrreee🎜이제 사용자 행동을 계속해서 즐겁게 기록할 수 있습니다. 🎜rrreee🎜지금까지 사용자의 클릭, 입력, 엔터 관련 작업이 모두 기록되었습니다. 그러나 스크롤 화면 작업은 기록되지 않습니다. Page의 onPageScroll
메서드를 직접 프록시할 수 있습니다. 🎜rrreee🎜 여기에 최적화 포인트가 있습니다. 즉, 스크롤 작업을 기록할 때 마지막 작업도 스크롤 작업인지 판단할 수 있습니다. 동일한 작업이라면 스크롤 거리만 수정하면 되기 때문입니다. 두 개의 스크롤을 한 번에 수행할 수 있습니다. 입력 이벤트도 마찬가지이며, 입력값도 한 단계로 도달할 수 있습니다. 🎜🎜사용자 행동 복원🎜🎜사용자 작업이 완료된 후 사용자 행동의 json 텍스트를 콘솔에 출력할 수 있습니다. json 텍스트를 복사한 후 자동화 도구를 통해 실행할 수 있습니다. 🎜rrreee🎜이것은 사용자의 작업 동작을 간단히 복원하는 것일 뿐입니다. 실제 작업 중에는 네트워크 요청 및 로컬 저장소 모의 작업도 포함되므로 여기서는 설명하지 않습니다. 동시에 Jest 도구에 액세스하여 사용 사례를 더 쉽게 작성할 수도 있습니다. 🎜요약
어려워 보이는 요구 사항에 대해 주의 깊게 탐색하는 한 언제든지 해당 솔루션을 찾을 수 있습니다. 또한 WeChat 미니 프로그램의 자동화 도구에는 정말 많은 함정이 있습니다. 문제가 발생하면 먼저 미니 프로그램 커뮤니티에 가서 대부분의 함정을 찾을 수 있습니다. 현재 해결할 수 없는 문제는 피할 수 있는 다른 방법만 찾을 수 있습니다. 마지막으로, 버그 없는 세상이 되었으면 좋겠습니다.
관련 학습 권장사항: WeChat 공개 계정 개발 튜토리얼
위 내용은 소규모 프로그램 자동화 테스트에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.
