Angular测试套件多次运行触发Maximum call stack size exceeded报错
这个栈溢出问题是Angular 10搭配Karma 6.3版本的典型已知问题,和测试用例本身的无限循环、变量泄漏无关,本质是测试运行时的上下文没有在每次重跑、每个用例执行完后正常清理,导致调用栈随运行次数持续累加,最终超过V8引擎的栈上限。
触发你这个场景的两个核心泄漏点:
browser-source-map-support的source map映射缓存不会在测试重跑时重置,每次重跑都会在上一次的映射栈基础上再嵌套一层- Angular 10默认没有开启TestBed的自动销毁逻辑,加上你Karma配置里关闭了Jasmine的上下文清理,Zone.js追踪的异步任务栈、组件实例引用会一直残留在内存里,逐层推高调用栈深度
这也能解释你观察到的现象:用例越少,需要累加的次数越多才会触发栈溢出,任意单测文件都能复现问题。
按顺序改配置即可,改完就能解决:
1. 修改Karma的clearContext配置
你当前配置里client.clearContext设为了false,这个配置是为了兼容老版本的html测试报告器,在Karma 6版本下会直接阻止Jasmine在每个spec执行完成后清理运行上下文,直接导致栈残留。把这个值改为true:
client: { clearContext: true, // 改为true,自动清理spec执行上下文 jasmine: { random: true, }, },
如果修改后测试页面的结果展示异常,把karma-jasmine-html-reporter升级到1.7.0以上版本即可兼容,不需要回滚这个配置。
2. 开启Angular测试模块的自动销毁
Angular 10默认关闭了测试模块执行完自动销毁的逻辑,这是Zone.js栈残留的核心原因。打开项目的src/test.ts文件,在TestBed初始化的位置添加销毁配置:
// 原有初始化逻辑 getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting(), // 添加下面这个teardown配置 { teardown: { destroyAfterEach: true } } );
这个配置会让每个spec执行完成后自动销毁关联的测试模块、解绑所有事件订阅、清理Zone上下文引用,从根源上避免栈累加。
3. (可选)Chrome启动参数兜底
如果你的测试套件规模很大、存在大量递归组件的测试用例,可以给Chrome启动参数添加栈大小扩容配置,避免偶发的栈溢出:
customLaunchers: { ChromeDebugging: { base: "Chrome", flags: [ "--remote-debugging-port=9333", "--js-flags=--stack-size=2000" // 将默认栈大小从约1MB提升到2MB ], }, },
如果改完以上配置还有偶发问题,可以先临时移除karma-coverage-istanbul-reporter验证:低于3.0.3版本的覆盖率插桩代码也会存在调用栈残留问题,升级对应依赖版本即可解决。
内容的提问来源于stack exchange,提问作者user2475269

