ホームページ > 記事 > WeChat アプレット > 小規模プログラムの自動テストについて詳しく解説
[関連する学習の推奨事項: WeChat ミニ プログラム チュートリアル ]
チームは自動化されたミニ プログラムを実行する予定ですこのツールにより、業務担当者はミニ プログラムの操作後に以前の操作パスを自動的に復元し、操作中に発生する例外をキャプチャして、このリリースがミニ プログラムの基本機能に影響を与えるかどうかを判断できるようになると期待されています。
上記の説明は簡単なように見えますが、途中でまだ難しい点があります。最初の困難は、業務担当者が操作を行う際に、操作をどのように記録するかです。ミニプログラムのパス、2 番目の困難は、記録された操作パスを復元する方法です。
この問題に対する操作パスを復元する方法については、公式 SDK を推奨します: miniprogram-auTomator
。
ミニ プログラム オートメーション SDK は、外部スクリプトを通じてミニ プログラムを制御する一連のソリューションを開発者に提供し、それによってミニ プログラムの自動テストの目的を達成します。この SDK を通じて、次のことを行うことができます。
上記の説明はすべて公式ドキュメントからのものです。以下の内容を読む前に公式ドキュメントを読むことをお勧めします。もちろん、これまでに 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() })复制代码
注意する必要があることが 1 つあります。SDK を使用する前に、開発者ツールのサービス ポートを開く必要があります。そうしないと、起動に失敗します。
#ユーザーの行動をキャプチャする操作パスを復元する方法を使用して、次のステップは、ユーザーの行動を記録するという問題を解決することです。操作パス。 ミニ プログラムでは、Web のようにイベント バブリングを通じてウィンドウ内のすべてのイベントをキャプチャすることはできません。幸いなことに、ミニ プログラムのすべてのページとコンポーネントはPage を渡す必要があります。
Component メソッドをラップするため、これら 2 つのメソッドを書き換えて、受信メソッドをインターセプトし、最初のパラメーターがすべてのイベントをキャプチャする
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) } }复制代码イベント タイプを決定した後は、どの要素がクリックされたかを明確にする必要がありますが、ミニ プログラムの落とし穴は、イベント オブジェクトの target 属性に要素のクラス名がないことです。ただし、要素は取得できます。 要素を正確に取得するには、構築にステップを追加し、wxml ファイルを変更し、
を変更する必要があります。すべての要素の class 属性を
data-className にコピーします。
<!-- 构建前 --><view></view><view></view><!-- 构建后 --><view></view><view></view>复制代码しかし、クラスを取得した後、別の落とし穴があります。ミニ プログラムの自動テスト ツールは、ページ内のカスタム コンポーネントの要素を直接取得できません。最初にカスタム コンポーネントを取得する必要があります。
<!-- 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 メソッドを直接プロキシすることができます。
// 记录用户行为的数组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) }复制代码ここに最適化ポイントがあり、スクロール操作を記録したときに、最後の操作もスクロール操作であったかどうかを判断できます。同じ操作であれば、変更するだけで済みます。スクロール距離は 2 つなので、2 番目のスクロールは 1 つのステップで実行できます。入力イベントについても同様で、入力値まで1ステップで到達できます。 ユーザー動作の復元ユーザー操作が完了すると、ユーザー動作の JSON テキストがコンソールに出力されます。JSON テキストをコピーした後、自動化ツールを通じて実行できます。 。
// 引入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() })复制代码これはユーザーの操作動作を単純に復元しただけであり、実際の操作ではネットワーク リクエストやローカルストレージのモックも関係しますが、ここでは説明しません。同時に、jest ツールにアクセスして、ユースケースを簡単に作成することもできます。
一見難しいニーズでも、慎重に調査する限り、対応するソリューションを常に見つけることができます。さらに、WeChat ミニ プログラムの自動化ツールには本当に多くの落とし穴があります。問題が発生した場合は、まずミニ プログラム コミュニティにアクセスして問題を見つけることができます。ほとんどの落とし穴は前任者によって踏まれています。また、いくつかの落とし穴もあります。現時点では解決できず、他の方法で解決するしかない問題は避けてください。最後に、世界からバグがなくなることを願っています。
関連する学習に関する推奨事項: WeChat パブリック アカウント開発チュートリアル
以上が小規模プログラムの自動テストについて詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。