我一直在尝试(没有成功)为通过componentDidCatch生命周期方法处理错误的ErrorBoundary
组件编写测试用例。
尽管<ErrorBoundry>
组件中的子组件产生了错误,但<ErrorBoundry>
不会呈现有关代码中的错误的信息,而是错误组件的内容(如果它可以正常工作)。
组件在生产/开发中按预期工作,但在由Jest / Enzyme执行测试时不会。
测试错误:
PASS src/ErrorBoundary.test.js
● Console
console.error node_modules/fbjs/lib/warning.js:33
Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components.
in input (at ErrorBoundary.test.js:11)
in div (at ErrorBoundary.test.js:10)
in ComponentWithError (at ErrorBoundary.test.js:26)
in ErrorBoundry (created by WrapperComponent)
in WrapperComponent
console.log src/ErrorBoundary.test.js:29
<ErrorBoundry>
<ComponentWithError>
<div>
<input type="text" value={{...}} />
</div>
</ComponentWithError>
</ErrorBoundry>
ErrorBoundry.js:
import React, { Component } from 'react'
import Raven from 'raven-js'
import { Segment, Button } from 'semantic-ui-react'
export default class ErrorBoundry extends Component {
state = {
hasError: false
}
componentDidCatch(error, info) {
this.setState({ hasError: true })
Raven.captureException(error, { extra: info });
}
render() {
if(this.state.hasError) {
return (
<div className='error-boundry'>
<Segment>
<h2> Oh no! Somethin went wrong </h2>
<p>Our team has been notified, but click
<Button onClick={() => Raven.lastEventId() && Raven.showReportDialog()}>
here </Button> to fill out a report.
</p>
</Segment>
</div>
);
} else {
return this.props.children;
}
}
}
ErrorBoundry.test.js:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import renderer from 'react-test-renderer'
import { shallow, mount } from 'enzyme'
import ErrorBoundary from './ErrorBoundary'
class ComponentWithError extends Component {
render() {
return (
<div>
<input type = "text" value = {null}/>
</div>
);
}
}
describe('<ErrorBoundary> window',()=> {
it('should match the snapshot', () => {
const tree = renderer.create(<ErrorBoundary>Test</ErrorBoundary> ).toJSON()
expect(tree).toMatchSnapshot()
})
it('displays error message on error generated by child', () => {
const wrapper = mount(
<ErrorBoundary >
<ComponentWithError />
</ErrorBoundary>
)
console.log(wrapper.debug() )
})
})
答案 0 :(得分:5)
经过进一步的研究后,我发现这是一个必须由Enzyme解决的开放性问题。 https://github.com/airbnb/enzyme/issues/1255
我已按如下方式实施:
function ProblemChild() {
throw new Error('Error thrown from problem child');
return <div>Error</div>; // eslint-disable-line
}
describe('<ErrorBoundary> window',()=> {
it('displays error message on error generated by child', () => {
const spy = sinon.spy(ErrorBoundary.prototype, 'componentDidCatch')
mount(<ErrorBoundary><ProblemChild /></ErrorBoundary>)
chaiExpect(ErrorBoundary.prototype.componentDidCatch).to.have.property('callCount', 1)
})
})
建议的解决方法无论如何都适用
<ErrorBoundary>
测试控制台显示警告:
PASS src/ErrorBoundary.test.js
● Console
console.error node_modules/react-dom/cjs/react-dom.development.js:9627
The above error occurred in the <ProblemChild> component:
in ProblemChild (at ErrorBoundary.test.js:37)
in ErrorBoundry (created by WrapperComponent)
in WrapperComponent
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundry.
答案 1 :(得分:0)
自hasError
生命周期方法ComponentDidCatch
状态发生更改以来,添加@AndreasKöberle的评论,您还可以使用酶setState。
您也无需mount
评论shallow would do
。
it('displays error message on error generated by child', () => {
const wrapper = shallow(
<ErrorBoundary >
<ComponentWithError />
</ErrorBoundary>
);
wrapper.setState({ hasError: true });
console.log(wrapper.debug() );
});
答案 2 :(得分:0)
酶现在有simulateError
助手。
所以这对我来说很好:
const Something = () => null;
describe('ErrorBoundary', () => {
it('should display an ErrorMessage if wrapped component throws', () => {
const wrapper = mount(
<ErrorBoundary>
<Something />
</ErrorBoundary>
);
const error = new Error('test');
wrapper.find(Something).simulateError(error);
/* The rest fo your test */
}
}