测试 API
wxa-runner 在浏览器页面上提供 window.__wxa_test_api__,用来读取页面状态、mock 原生 API、拦截请求、直接跳转页面。 Playwright 的 fixture 就是基于它实现的。
用 Playwright 时推荐用 fixture,写起来更简单。不想多装一个包,或者用的是其他测试工具时,再直接调用这里的 API。
在 Playwright 中直接使用
先装上命令行和类型:
pnpm add -D @playwright/test wxa-runner @open-wxa/wxa-runner-core用 Playwright 自带的 webServer 启动开发服务器。跑测试时加 --no-watch,不热更新,运行环境和真机一致:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: {
command: 'npx wxa-runner dev . --no-watch --port 3000',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI
},
use: { baseURL: 'http://localhost:3000', channel: 'chrome' }
});在用例里打开页面,等小程序启动完成,再通过 page.evaluate 调用测试 API:
/// <reference types="@open-wxa/wxa-runner-core/test-api" />
import { test, expect } from '@playwright/test';
test('提交后跳转到结果页', async ({ page }) => {
// 打开指定页面,等小程序启动完成
await page.goto('/?path=pages/form/form');
await page.waitForFunction(() => window.__wxa_test_api__);
await page.evaluate(() => window.__wxa_test_api__.ready);
// 每个页面是一个 iframe,iframe[data-current] 始终是当前页
const current = page.frameLocator('iframe[data-current]');
await current.locator('#submit').click();
const result = await page.evaluate(() =>
window.__wxa_test_api__.waitForPage('pages/result/result')
);
expect(result.query).toEqual({ status: 'ok' });
});
// 运行时错误、调用了未实现的 API 都不会让测试失败,要自己检查
test.afterEach(async ({ page }) => {
const errors = await page.evaluate(
() => window.__wxa_test_api__.errors()
);
expect(errors).toEqual([]);
});完整示例见 tests/e2e/showcase.test.ts。
成员
| 成员 | 作用 |
|---|---|
ready | 小程序启动完成后 resolve 的 Promise |
currentPage() / pageStack() | 当前页 / 整个页面栈,每页有 path、query、webviewId、frameName(可用于 page.frame({ name })) |
waitForPage(path, timeout?) | 等到指定页面成为当前页,默认超时 10 秒 |
pageData(path?) | 页面的 data(拷贝)。不传 path 时读当前页;页面不在页面栈里时为 null |
callPageMethod(name, ...args) | 调用当前页的方法,返回方法的返回值(返回 Promise 时等它完成)。参数要能 JSON 序列化 |
mock(api, impl) / unmock(api?) | 覆盖原生 API,写法同 setup 的 mock。unmock() 不传参数时撤销全部 |
route(pattern, handler) / unroute(pattern?) | 拦截 wx.request,写法同 setup 的 network.routes,后添加的优先。unroute() 不传参数时删除全部 |
requests(pattern?) / clearRequests() | 小程序发出的 wx.request:方法、地址、请求头、请求体 data、拦截它的规则 routedBy。被拦截的和真正发出的都有,只保留最近 1000 个 |
navigateTo / navigateBack / redirectTo / reLaunch / switchTab | 直接跳转页面,同 wx 上的同名 API |
getStorage(key) / clearStorage() | 读取 / 清空小程序的存储 |
errors() | 逻辑层、渲染层的运行时错误,以及业务代码调用过的未实现 API(api 为 API 名称,每个 API 记一次) |
mock、route 整页刷新后失效。详细说明见类型注释(WxaTestApi)。
启动前声明 mock 和拦截
App.onLaunch、首页 onLoad 里就调用的 API,等 ready 之后再 mock 已经晚了。除了写进 setup, 还可以在页面脚本执行前定义 window.__wxa_before_launch__。wxa-runner 在 setup 之后、小程序启动前调用它,等它完成后才启动小程序; 这里的 mock 会覆盖 setup 里的同名 mock:
await page.addInitScript(() => {
window.__wxa_before_launch__ = api => {
api.mock('login', { code: 'test_code' });
api.route('POST **/api/auth/login', {
body: { token: 'test-token' }
});
};
});
await page.goto('/');函数可以是 async 的。抛错时模拟器显示错误,小程序不启动。fixture 的「打开页面前 mock」就是这样实现的。
类型
上面示例第一行的引用为 window.__wxa_test_api__ 提供类型,也可以写进 tsconfig 的 compilerOptions.types。 需要把 @open-wxa/wxa-runner-core 加为开发依赖。
编写 mock 时用到的 ApiHandler、WxaTestApi 等类型可以从 @open-wxa/wxa-runner-core 导入。
注意事项
- 没有实现的
wxAPI 仍返回成功,以免打断业务代码,但会在errors()里记一条;基础库内部调用的原生接口不记。用到的要 mock 掉 wx.request不能 mock,要用route或 setup 的network.routes拦截- 跳转后的选择器、text 组件的文字等,和用 fixture 时一样,见在 Playwright 中测试

