You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Webdriver.io脚本中提取含嵌套属性的capabilities.browserName?

解决Webdriver.io脚本中嵌套Capabilities的浏览器名称提取问题

问题场景

提取Webdriver.io脚本里的capabilities.browserName时,现有正则在capabilities包含嵌套对象(如proxy)的情况下失效,只能提取到最后一个浏览器名称(如firefox),无法正确处理带嵌套结构的capabilities。

示例Webdriver.io脚本:

const { remote } = require('webdriverio');
var assert = require('assert');

;(async () => {
        const browser = await multiremote({
            capabilities: {
                browserName: 'chrome',
            },
            capabilities: {
                browserName: 'firefox'
            }
    })
    await browser.url('https://www.google.com');
    var title = await browser.getTitle();
    assert.equal(title, 'Google');
    await browser.deleteSession()
})()

嵌套结构的capabilities示例:

capabilities: {
   browserName: 'chrome',
   proxy: {
     proxyType: 'PAC',
     proxyAutoconfigUrl: 'http://localhost:8888',
   }
},

现有代码问题分析

原提取代码中的正则/\scapabilities\s*?:\s*?\{[^}]+\}/gi存在缺陷:[^}]+会匹配任意非}的字符,遇到嵌套对象的}时会提前终止匹配,导致只能捕获到嵌套对象的第一层内容,无法完整提取整个capabilities对象,最终JSON解析失败或数据缺失。

原提取代码:

var browsers = str.match(/\scapabilities\s*?:\s*?\{[^}]+\}/gi); // find capabilities
console.log(browsers.length); // check length
for(let i=0; i < browsers.length; i++){
    let b = browsers[i].replace(/\scapabilities\s*?:\s*?/, '') // remove capabilities: part
                       .replace(/'/g, '&quot;' ) // convert single quote to double quote
                       .replace(/\s/g, '') // remove spaces, new lines, tabs etc.
                       .replace(/(\w+:)|(\w+ :)/g, function(matchedStr) { // wrap words in double quote as keys are not wrapped
                            return '&quot;' + matchedStr.substring(0, matchedStr.length - 1) + '&quot;:';
                          });

    let browser = JSON.parse(b); // parse the string to convert to object
    console.log(browser.browserName); // Success !!!
}

解决方案

方案1:改进正则(支持嵌套花括号匹配)

使用支持递归匹配花括号的正则,完整捕获包含嵌套结构的capabilities对象。修改后的正则可以正确匹配多层嵌套的{}结构。

修改后的提取代码:

// 匹配包含嵌套花括号的capabilities块
var browsers = str.match(/\scapabilities\s*?:\s*?(\{(?:[^{}]+|(?1))*\})/gi);
console.log(browsers.length);

for(let i=0; i < browsers.length; i++){
    let b = browsers[i]
            .replace(/\scapabilities\s*?:\s*?/, '')
            .replace(/'/g, '"') // 单引号转双引号
            .replace(/(\w+)(?=\s*:)/g, '"$1"'); // 给未加引号的key添加双引号

    try {
        let browser = JSON.parse(b);
        console.log(browser.browserName);
    } catch (e) {
        console.error('解析失败:', e);
    }
}

方案2:使用JS AST解析(更可靠)

对于复杂的JS脚本结构,正则容易出现边界情况,推荐用AST解析工具(如acorn)直接解析脚本的抽象语法树,精准提取multiremote参数中的所有capabilities对象。

步骤:

  1. 安装依赖:npm install acorn
  2. 使用以下代码解析:
const acorn = require('acorn');

// 解析脚本字符串为AST
const ast = acorn.parse(str, { ecmaVersion: 'latest' });

// 遍历AST找到multiremote的调用
function findMultiremoteCapabilities(node) {
    if (node.type === 'CallExpression' && node.callee.name === 'multiremote') {
        const args = node.arguments[0];
        if (args.type === 'ObjectExpression') {
            // 提取所有capabilities属性
            return args.properties
                .filter(prop => prop.key.name === 'capabilities')
                .map(prop => {
                    // 将AST节点转换为对象(复杂场景可使用acorn-walk或escodegen优化)
                    const obj = {};
                    prop.value.properties.forEach(p => {
                        obj[p.key.name] = p.value.type === 'Literal' ? p.value.value : null;
                        // 递归处理嵌套对象
                        if (p.value.type === 'ObjectExpression') {
                            const nestedObj = {};
                            p.value.properties.forEach(np => {
                                nestedObj[np.key.name] = np.value.value;
                            });
                            obj[p.key.name] = nestedObj;
                        }
                    });
                    return obj;
                });
        }
    }
    // 递归遍历子节点
    for (const key in node) {
        if (node[key] && typeof node[key] === 'object') {
            const result = findMultiremoteCapabilities(node[key]);
            if (result) return result;
        }
    }
    return null;
}

const capabilitiesList = findMultiremoteCapabilities(ast);
capabilitiesList.forEach(cap => console.log(cap.browserName));

说明

  • 方案1适合结构相对简单的脚本,修改成本低;
  • 方案2更稳定,能处理任意复杂的JS结构,适合大规模或复杂脚本的提取需求。

内容的提问来源于stack exchange,提问作者Aamir Mahmood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:12:47