有没有办法在Jest中测试组件中的自定义错误而不会在控制台中抛出Uncaught错误?
这里我有一个简单的按钮组件:
import React from 'react';
export default class Button extends React.Component {
render() {
if (!this.props.type) {
throw new Error('Button requires a type prop');
}
return (
<button className={`btn btn-${this.props.type}`}>Button</button>
);
}
}
在不提供type属性的情况下使用组件时,我希望抛出自定义错误。我还有以下Jest测试:
import React from 'react';
import ReactDOM from 'react-dom';
import Button from './button';
it('throws an error if the type prop is not defined', () => {
const buttonType = undefined;
const container = document.createElement('div');
expect(() => {
ReactDOM.render(<Button type={buttonType} />, container);
}).toThrow('Button requires a type prop');
});
单元测试通过,但控制台产生的错误类似于:
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Uncaught [Error: Button requires a type prop]
The above error occurred in the <Button> component:
in Button (at button.spec.js:20)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/docs/error-boundaries.html to learn more about error boundaries.
通常在Jasmine中,.toThrow()匹配器会自动捕获错误,并且不会记录。
我已经阅读过有关错误边界的内容,但这些似乎是在应用程序级别,而不是在组件级别。
我错过了一种更适合测试的方法吗?
编辑:使用以下版本:
答案 0 :(得分:4)
我遇到了类似的问题,来自jsdom的虚拟控制台打印错误而不是抛出它。据我所知,Jest或任何其他测试框架无法阻止代码打印到控制台。
我已经通过将负责打印的监听器替换为控制台来解决这个问题。以下代码在一个文件中运行,该文件在Jest配置中的fru%C4%B1t
中配置。
setupFiles
正如您所看到的,在我们的案例中,打印到控制台的错误(多次,因为它是副作用,而不是我们测试的主要目的)是一个未实现的&#39 ;错误。所以这个代码只会吞下那些错误。
此解决方案并不理想,但它会使日志更清洁。
PS:如果你想降低吞咽的风险,那么真实的&#39;错误,您可以在测试套件的// There should be a single listener which simply prints to the
// console. We will wrap that listener in our own listener.
const listeners = window._virtualConsole.listeners("jsdomError");
const originalListener = listeners && listeners[0];
window._virtualConsole.removeAllListeners("jsdomError");
window._virtualConsole.addListener("jsdomError", (error) => {
if (error.type !== "not implemented" && originalListener) {
originalListener(error);
}
// swallow
});
方法中使用此技巧,并使用before
方法重置原始行为。
答案 1 :(得分:0)
问题确实是React的错误处理阻止了该错误冒泡到Jasmine可以检测到的顶层。两种可能的解决方法:
console.error = msg => { throw new Error(msg); };
这显然是hack,如果React更改为使用其他方法进行错误报告,则该破解将被破坏。 stijndepestel的答案是一种更可靠的方法。
let errorInfo = null;
class ErrorBoundary extends React.PureComponent {
state = {hasError: false};
componentDidCatch(err, info) {
errorInfo = [err, info]
this.setState({hasError: true});
}
render() {
if (!this.state.hasError)
return React.Children.only(this.props.children);
return 'Errored';
}
}
然后,您可以将测试包装在这样的处理程序中,然后断言errorInfo
不为null,并且包含预期的错误