如何在Jasmine中使用toHaveBeenCalledWith正确匹配多行模板字符串
解决方案
这类匹配失败是多行模板字符串的行首缩进、首尾换行、行尾空格差异导致的,可根据场景选择以下处理方式:
方案1:清洗字符串后比较(不依赖缩进格式的脚本适用)
如果测试的脚本逻辑不依赖缩进、多余空格,可先对两个字符串做统一的空白清洗后再比较。
基础清洗(保留内容内部空格)
// 仅移除首尾空白、每行行首缩进,不修改内容内部的空格 const cleanScript = (str) => str.trim().replace(/^[ \t]+/gm, ''); // 测试代码 const actualScript = component.myMethod.calls.mostRecent().args[0]; const expectedScript = ` thisIsMyScript(); itDoesThings(); `; expect(cleanScript(actualScript)).toBe(cleanScript(expectedScript));
极简清洗(仅对比有效字符,风险较高)
你用到的全量替换空格的方式适合脚本内无带空格的字符串字面量的场景,注意如果脚本内包含console.log("a b")这类带空格的内容,该方式会破坏原内容导致匹配错误:
const arg = component.myMethod.calls.mostRecent().args[0].toString(); expect(arg.replace(/\s+/g, '')).toBe(scriptMock.replace(/\s+/g, ''));
方案2:按行对比(更稳妥的对比方式)
将字符串按换行拆分,逐行修剪后过滤空行,再对比内容数组,可避免破坏内容内部空格,也能过滤换行差异:
const getScriptLines = (str) => str.split('\n') .map(line => line.trim()) .filter(line => line.length); const actualLines = getScriptLines(component.myMethod.calls.mostRecent().args[0]); const expectedLines = getScriptLines(scriptMock); expect(actualLines).toEqual(expectedLines);
方案3:统一模板字符串缩进(脚本对格式敏感时适用)
如果测试的脚本依赖换行、缩进格式,可使用dedent类工具统一处理模板字符串的缩进,保证调用时和测试mock时的格式完全一致:
// 安装dedent后引入 import dedent from 'dedent'; // 业务代码调用时统一用dedent处理 myMethod(dedent` thisIsMyScript(); itDoesThings(); `); // 测试mock时也用dedent处理 const scriptMock = dedent` thisIsMyScript(); itDoesThings(); `; // 直接全等匹配即可 expect(component.myMethod).toHaveBeenCalledWith(scriptMock);
方案4:自定义测试匹配器(多同类测试场景适用)
如果项目中有大量同类测试,可给测试框架自定义匹配器复用逻辑:
// Jasmine示例,在测试前置钩子中注册匹配器 beforeEach(() => { jasmine.addMatchers({ toEqualScript: () => ({ compare: (actual, expected) => { const clean = s => s.trim().replace(/^[ \t]+/gm, ''); const pass = clean(actual) === clean(expected); return { pass, message: pass ? '' : `脚本内容不匹配\n实际:${actual}\n期望:${expected}` }; } }) }); }); // 测试时直接调用 expect(component.myMethod.calls.mostRecent().args[0]).toEqualScript(scriptMock);
内容的提问来源于stack exchange,提问作者Baronvonbirra
相关产品推荐
相关产品推荐

