简介
@Gajus 的回答绝对帮助了我(所以,感谢 Gajus)。但是,我想我会提供一个答案:
- 使用更最新的 React (v15.4.1)
- 使用 Jest(React 自带)
- 允许为单个道具测试多个道具值
-
更通用
总结
就像 Gajus 和其他人在这里建议的方法一样,我建议的基本方法也是确定 React 是否使用 console.error 来响应不可接受的测试道具值。具体来说,这种方法涉及对每个测试道具值执行以下操作:
-
模拟和清除
console.error(以确保之前对 console.error 的调用不会干扰),
-
使用正在考虑的测试道具值创建组件,并且
-
确认
console.error 是否按预期被解雇。
testPropTypes 函数
以下代码可以放在测试中,也可以作为单独的导入/必需模块/文件:
const testPropTypes = (component, propName, arraysOfTestValues, otherProps) => {
console.error = jest.fn();
const _test = (testValues, expectError) => {
for (let propValue of testValues) {
console.error.mockClear();
React.createElement(component, {...otherProps, [propName]: propValue});
expect(console.error).toHaveBeenCalledTimes(expectError ? 1 : 0);
}
};
_test(arraysOfTestValues[0], false);
_test(arraysOfTestValues[1], true);
};
调用函数
任何检查propTypes 的测试都可以使用三个或四个参数调用testPropTypes:
-
component,被 prop 修改的 React 组件;
-
propName,字符串待测道具名称;
-
arraysOfTestValues,要测试的道具的所有所需测试值的数组:
- 第一个子数组包含所有可接受的测试道具值,而
- 第二个子数组包含所有不可接受的测试道具值;和
-
可选地,otherProps,一个包含 此组件的任何其他所需道具的道具名称/值对的对象。
需要otherProps 对象来确保 React 不会对 console.error 进行不相关的调用,因为其他必需的 props 会无意中丢失。只需为任何必需的道具包含一个可接受的值,例如{requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue}.
功能逻辑
该函数执行以下操作:
它设置了一个模拟 console.error,这是 React 用来报告不正确类型的道具的。
-
对于 每个测试道具值的子数组,只要它遍历每个子数组中的每个测试道具值以测试道具类型:
- 两个子数组中的第一个应该是可接受的测试道具值的列表。
- 第二个应该是不可接受的测试道具值。
在每个单独的测试道具值的循环中,console.error 模拟首先被清除,因此可以假定检测到的任何错误消息都来自此测试。
然后使用测试道具值以及当前未测试的任何其他必要的必需道具创建组件的实例。
-
最后,检查是否已触发警告,如果您的测试尝试使用不适当或缺少的道具创建组件,则应该发生这种情况。
测试可选道具和必需道具
请注意,从 React 的角度来看,将 null(或 undefined)分配给 prop 值本质上与不为该 prop 提供任何值相同。根据定义,这对于可选道具是可以接受的,但对于必需道具是不可接受的。因此,通过将null 放置在可接受或不可接受值的数组中,您可以分别测试该道具是可选的还是必需的。
示例代码
MyComponent.js(只是propTypes):
MyComponent.propTypes = {
myProp1: React.PropTypes.number, // optional number
myProp2: React.PropTypes.oneOfType([ // required number or array of numbers
React.PropTypes.number,
React.PropTypes.arrayOf(React.PropTypes.number)
]).isRequired
MyComponent.test.js:
describe('MyComponent', () => {
it('should accept an optional number for myProp1', () => {
const testValues = [
[0, null], // acceptable values; note: null is acceptable
['', []] // unacceptable values
];
testPropTypes(MyComponent, 'myProp1', testValues, {myProp2: 123});
});
it('should require a number or an array of numbers for myProp2', () => {
const testValues = [
[0, [0]], // acceptable values
['', null] // unacceptable values; note: null is unacceptable
];
testPropTypes(MyComponent, 'myProp2', testValues);
});
});
此方法的限制(重要)
目前,如何使用这种方法存在一些重大限制,如果过度使用,可能会导致一些难以追踪的测试错误。 this other SO question/answer 解释了这些限制的原因和影响。总之,对于简单的 prop 类型,例如 myProp1,您可以根据需要测试尽可能多的不可接受的非null 测试 prop 值只要它们都是不同的数据类型。对于一些复杂的道具类型,比如myProp2,您只能测试一个单个不可接受的非null道具值任何类型。请参阅其他问题/答案以进行更深入的讨论。