WebdriverIO 5升级至7:如何程序化转换同步调用为异步调用?
WebdriverIO 5 升级至 7:同步调用转异步的程序化方案
WebdriverIO 7 彻底移除了对同步模式的默认支持(仅在 DevTools 协议下保留有限同步能力),升级时必须将所有同步调用改为 async/await 风格。以下是几种可行的程序化转换方案:
1. 用 jscodeshift 编写 AST 转换脚本
jscodeshift 是基于 AST 的代码批量转换工具,能精准识别并修改 WDIO 的同步调用。你可以自定义脚本自动给所有浏览器操作添加 await,并将包含这些操作的函数标记为 async。
示例转换脚本
export default function transformer(file, api) { const j = api.jscodeshift; const root = j(file.source); // 匹配所有 browser.xxx() 形式的调用,添加 await root.find(j.CallExpression, { callee: { object: { name: 'browser' }, property: { type: 'Identifier' } } }).replaceWith(path => j.awaitExpression(path.node)); // 匹配全局选择器 $('xxx')、$$('xxx'),添加 await root.find(j.CallExpression, { callee: { name: '$' } }).replaceWith(path => j.awaitExpression(path.node)); root.find(j.CallExpression, { callee: { name: '$$' } }).replaceWith(path => j.awaitExpression(path.node)); // 给包含 await 的普通函数添加 async 关键字 root.find(j.FunctionDeclaration).forEach(path => { const hasAwait = path.node.body.body.some(node => node.type === 'AwaitExpression'); if (hasAwait && !path.node.async) { path.node.async = true; } }); // 给包含 await 的箭头函数添加 async 关键字 root.find(j.ArrowFunctionExpression).forEach(path => { const hasAwait = (path.node.body.type === 'BlockStatement' && path.node.body.body.some(node => node.type === 'AwaitExpression')) || (path.node.body.type === 'AwaitExpression'); if (hasAwait && !path.node.async) { path.node.async = true; } }); return root.toSource(); }
使用方式
- 安装 jscodeshift:
npm install -g jscodeshift - 将脚本保存为
wdio-sync-to-async.js - 运行转换:
jscodeshift -t ./wdio-sync-to-async.js 你的测试文件目录/
2. 用 ESLint 自动修复
借助 eslint-plugin-wdio 的内置规则,可快速批量修复同步调用问题:
- 安装依赖:
npm install eslint-plugin-wdio --save-dev - 在 ESLint 配置中启用规则:
{ "plugins": ["wdio"], "rules": { "wdio/no-sync": "error" } } - 执行自动修复:
eslint . --ext .js,.ts --fix
这个方案能自动给同步调用添加 await,并提示你将函数改为 async,大部分场景可直接修复完成。
3. 编辑器正则替换(快速但需校验)
如果项目结构简单,可直接用编辑器的正则替换功能批量处理:
- 替换同步调用:搜索
browser\.([a-zA-Z0-9_]+)\(,替换为await browser.$1( - 替换全局选择器:搜索
\$(\(['"].+?['"]\)),替换为await $$1;同理处理$$ - 替换函数声明:搜索
function (\w+)\(,替换为async function $1(;搜索(\w+): \(,替换为$1: async ((针对对象方法)
注意:正则替换可能遗漏嵌套调用、循环内调用等复杂场景,转换后必须手动校验。
转换后注意事项
- 测试用例的
it/beforeEach等钩子函数必须改为async:it('测试用例', async () => { ... }) - 循环中的异步调用(比如
forEach)需改为for...of,否则无法正确等待执行完成 - 转换后务必运行所有测试,排查未覆盖的同步调用或异步逻辑问题
内容的提问来源于stack exchange,提问作者Naomy
相关产品推荐
相关产品推荐

