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

使用jasmine-browser-runner与Ext.js3.2.1时Firefox WebDriver报循环对象值错误

jasmine-browser-runner + Ext.js 3.2.1 在Firefox中触发“Cyclic object value”错误的问题与解决

问题描述

jasmine-browser-runner在Chrome中运行正常,但在Firefox中执行含Ext.js 3.2.1的测试时,直接抛出JavascriptError: Cyclic object value错误,导致测试完全无法进行。

环境信息

  • jasmine-browser-runner:最新版本
  • Firefox:多版本测试均复现
  • Chrome:相同代码/测试无问题
  • selenium-webdriver:jasmine-browser-runner默认依赖
  • Ext.js:3.2.1版本(核心问题来源)
  • 操作系统:全平台(Linux已验证)

最小复现步骤

  1. 配置jasmine运行文件:
// jasmine-config.js
module.exports = {
  srcFiles: [
    'path/to/ext-js-3.2.1/ext-base-debug.js',  // 包含问题方法createInterceptor
    'path/to/ext-js-3.2.1/ext-all-debug.js'   // 大量调用该方法
  ],
  specFiles: [
    'test/simple.spec.js'
  ]
};
  1. 编写最简测试用例:
// test/simple.spec.js
describe('Simple Test with Ext.js', function() {
  it('should pass', function() {
    expect(true).toBe(true);
  });
});
  1. Chrome运行(成功):
npx jasmine-browser-runner runSpecs --config=jasmine-config.js --browser=chrome
# 测试正常通过
  1. Firefox运行(失败):
npx jasmine-browser-runner runSpecs --config=jasmine-config.js --browser=firefox
# 抛出错误:JavascriptError: Cyclic object value

错误详情

JavascriptError: Cyclic object value: function(fcn, scope){
    var method = this;
    return !Ext.isFunction(fcn) ?
            this :
            function() {
                var me = this,
                    args = arguments;
                fcn.target = me;      // Ext.js创建的循环引用
                fcn.method = method;  // Ext.js创建的循环引用
                return (fcn.apply(scope || me || window, args) !== false) ?
                        method.apply(me || window, args) :
                        null;
            };
}
    at Object.throwDecodedError (selenium-webdriver/lib/error.js:523:15)
    at parseHttpResponse (selenium-webdriver/lib/http.js:524:13)

RemoteStacktrace:
    cloneObject@chrome://remote/content/marionette/json.sys.mjs:46:11
    cloneJSON@chrome://remote/content/marionette/json.sys.mjs:207:12
    json.clone@chrome://remote/content/marionette/json.sys.mjs:212:22
    receiveMessage@chrome://remote/content/marionette/actors/MarionetteCommandsChild.sys.mjs:289:19
    request@http://localhost:8890/__src__/path/to/ext-js/ext-and-extensions-debug.js:84625:22

根因分析

  1. Ext.js 3.2.1扩展了Function.prototype,其中createInterceptor等方法会生成循环引用:
// 来自ext-base-debug.js约863行
Function.prototype.createInterceptor = function(fcn, scope){
    var method = this;           // 形成循环引用
    return function() {
        fcn.target = this;       // 给传入函数添加指向当前上下文的引用
        fcn.method = method;     // 给传入函数添加指向原方法的引用
    };
};
  1. Chrome的DevTools Protocol在序列化对象时能自动处理循环引用;而Firefox的Marionette Protocol使用严格JSON序列化,遇到循环引用直接抛出错误。
  2. jasmine-browser-runner在提取测试结果时,需要序列化整个JavaScript执行上下文,Firefox的Marionette无法处理Ext.js留下的循环引用,导致失败。

解决方案

方案1:修补Ext.js的循环引用问题

直接修改Ext.js的createInterceptor方法,避免给函数实例添加循环引用属性:

// 在引入Ext.js后立即执行以下代码,覆盖原方法
Function.prototype.createInterceptor = function(fcn, scope){
    var method = this;
    return !Ext.isFunction(fcn) ?
            this :
            function() {
                var me = this,
                    args = arguments;
                // 移除循环引用的赋值操作,改用局部变量传递上下文
                var result = fcn.apply(scope || me || window, args);
                return result !== false ? method.apply(me || window, args) : null;
            };
};

如果无法修改原Ext.js文件,可以在测试启动前注入这段代码,覆盖原方法。

方案2:配置jasmine-browser-runner,限制序列化范围

jasmine-browser-runner默认会序列化整个执行上下文,我们可以自定义测试结果提取逻辑,只获取必要的测试结果,避免序列化包含循环引用的对象。
修改jasmine配置,添加自定义修复脚本:

// jasmine-config.js
module.exports = {
  srcFiles: [
    'path/to/ext-js-3.2.1/ext-base-debug.js',
    'path/to/ext-js-3.2.1/ext-all-debug.js',
    'path/to/custom-jasmine-fix.js' // 自定义修复脚本
  ],
  specFiles: [
    'test/simple.spec.js'
  ]
};
// custom-jasmine-fix.js
// 重写jasmine的结果报告逻辑,只返回必要数据
jasmine.getEnv().addReporter({
  jasmineDone: function(result) {
    // 只提取测试结果的核心数据,避免序列化整个上下文
    var simplifiedResult = {
      totalSpecsDefined: result.totalSpecsDefined,
      failedCount: result.failedCount,
      passedCount: result.totalSpecsDefined - result.failedCount
    };
    // 将简化后的结果传递给runner,避免循环引用问题
    window.__jasmine_test_results__ = simplifiedResult;
  }
});

同时需要调整jasmine-browser-runner的结果提取逻辑,读取window.__jasmine_test_results__的值而非默认的全上下文数据。

方案3:使用Firefox的Chrome DevTools Protocol(实验性)

Firefox 79+支持Chrome DevTools Protocol(CDP),可以强制jasmine-browser-runner使用CDP而非Marionette:

# 启动Firefox时启用CDP
npx jasmine-browser-runner runSpecs --config=jasmine-config.js --browser=firefox --firefox-options='{"args": ["-remote-debugging-port=9222"]}'

注意:该方式可能存在兼容性问题,需根据项目情况测试验证。

针对疑问的解答

  1. jasmine-browser-runner是否可配置结果提取逻辑?
    可以。通过自定义jasmine reporter,只提取测试结果的核心数据,避免序列化包含循环引用的执行上下文。如方案2所示,重写报告逻辑,将简化后的结果存储在全局变量中,再由runner读取。

  2. Marionette是否应像CDP一样处理循环引用?
    目前Marionette的设计严格遵循JSON规范,不支持循环引用序列化。虽然针对遗留框架可考虑优化,但短期内官方不会改变这一行为,建议通过代码修补或自定义逻辑解决问题。

  3. 是否可让jasmine-browser-runner为Firefox使用其他协议?
    可以尝试强制使用Chrome DevTools Protocol(方案3),但该方式属于实验性用法,部分功能可能受限,需根据项目情况测试验证。

内容的提问来源于stack exchange,提问作者Tanishq Bhadouria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 07:44:52