JavaScript如何判断参数可展开?Jest测试参数传递优化需求
问题解答
核心概念澄清
JavaScript里没有内置的isMutable()方法,也没有专门的属性标志用来判断一个值是否“可展开”——因为**“可展开”和“可变”是完全独立的概念**:
- 可变/不可变描述的是值本身能否被修改(比如字符串不可变、数组可变);
- 展开运算符
...的适用范围是可迭代对象(数组、Set、Map、类数组对象等)或普通对象(ES2018+),和值是否可变没有直接关联。
针对你的场景的解决方案
你的核心需求是简化测试代码,让expectation.args既可以传单个值,也可以传数组(不用强制包裹数组)。这里不需要复杂的“可展开”判断,只需要区分数组和非数组即可:
修改封装函数
export const expectToHaveBeenNthCalledWith = (functionHandler, expectation) => { // 如果args是数组就展开,否则包装成数组再传递 const callArgs = Array.isArray(expectation.args) ? expectation.args : [expectation.args]; expect(functionHandler).toHaveBeenNthCalledWith( expectation.callIndex, ...callArgs ); };
简化后的测试代码
现在你可以直接传单个参数,无需包裹数组:
describe("expectTo", () => { it('assert Nth call with argument', () => { const functionCaller = (functionCall, arg_1, arg_2) => { functionCall(arg_1); functionCall(arg_2); } const string_1 = "ackbar"; const string_2 = "Boba Fett"; // 直接传单个值,不用数组包裹 const expectation_1 = {"callIndex": 1, "args": string_1}; const expectation_2 = {"callIndex": 2, "args": string_2}; const f = jest.fn(); functionCaller(f, string_1, string_2); expectToHaveBeenNthCalledWith(f, expectation_1); expectToHaveBeenNthCalledWith(f, expectation_2); }); });
扩展:支持更多可迭代类型(可选)
如果你的场景需要支持Set、Map等可迭代对象(而非单个值),可以写一个工具函数判断可迭代对象(注意排除字符串,因为字符串虽可迭代,但展开会拆成单个字符,通常不是预期行为):
// 判断是否是可迭代对象且不是字符串 function isIterableNonString(obj) { return obj != null && typeof obj !== 'string' && typeof obj[Symbol.iterator] === 'function'; } // 更新封装函数 export const expectToHaveBeenNthCalledWith = (functionHandler, expectation) => { let callArgs; if (isIterableNonString(expectation.args)) { callArgs = [...expectation.args]; // 转成数组再展开 } else { callArgs = [expectation.args]; // 单个值包装成数组 } expect(functionHandler).toHaveBeenNthCalledWith( expectation.callIndex, ...callArgs ); };
内容的提问来源于stack exchange,提问作者Bruno Peixoto
相关产品推荐
相关产品推荐

