Jest测试通过但未捕获错误并记录到控制台

时间:2018-02-14 11:35:40

标签: reactjs jestjs

有没有办法在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()匹配器会自动捕获错误,并且不会记录。

我已经阅读过有关错误边界的内容,但这些似乎是在应用程序级别,而不是在组件级别。

我错过了一种更适合测试的方法吗?

编辑:使用以下版本:

  • react:16.2.0
  • react-dom:16.2.0
  • jest:22.2.2

2 个答案:

答案 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可以检测到的顶层。两种可能的解决方法:

Monkeypatch console.error实际抛出

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,并且包含预期的错误