feat(error-handling): introduce unified and configurable error handling (#7761)

Refs #7778
This commit is contained in:
Vladimir Gorej
2022-01-24 16:12:13 +01:00
committed by GitHub
parent 4f2287fe53
commit 8b1c4a7c1a
19 changed files with 629 additions and 295 deletions

View File

@@ -179,7 +179,7 @@ describe("auth plugin - actions", () => {
describe("tokenRequest", function () {
it("should send the code verifier when set", () => {
const testCodeVerifierForAuthorizationCodeFlows = (flowAction) => {
const testCodeVerifierForAuthorizationCodeFlows = (flowAction) => {
const data = {
auth: {
schema: {

View File

@@ -0,0 +1,253 @@
import React from "react"
import { mount } from "enzyme"
import sinon from "sinon"
import { Provider } from "react-redux"
import noop from "lodash/noop"
import System from "core/system"
import ViewPlugin from "core/plugins/view"
import SafeRenderPlugin from "core/plugins/safe-render"
describe("safe-render", function() {
const DisableComponentDidCatchPlugin = () => ({
fn: {
componentDidCatch: noop,
}
})
it("should catch errors thrown inside of React Component class render method", function() {
class BrokenComponent extends React.Component {
render() {
return null
}
}
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<SafeBrokenComponent />)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of PureComponent class render method", function() {
class BrokenComponent extends React.PureComponent {
render() {
return null
}
}
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<SafeBrokenComponent />)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of function component", function() {
const BrokenComponent = () => null
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<SafeBrokenComponent />)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of container created from React Component class", function() {
class BrokenComponent extends React.Component {
render() {
return null
}
}
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent", true)
const wrapper = mount(
<Provider store={system.getStore()}>
<SafeBrokenComponent />
</Provider>
)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of container created from function component", function() {
const BrokenComponent = () => null
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent", true)
const wrapper = mount(
<Provider store={system.getStore()}>
<SafeBrokenComponent />
</Provider>
)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should render custom Fallback component", function() {
const BrokenComponent = () => null
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const FallbackPlugin = () => ({
components: {
Fallback: () => "fallback component",
},
})
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
FallbackPlugin,
DisableComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<SafeBrokenComponent />)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(wrapper.text()).toEqual("fallback component")
})
it("should call custom componentDidCatch hook", function() {
const BrokenComponent = () => null
const componentDidCatch = sinon.spy()
const BrokenComponentPlugin = () => {
return {
components: {
BrokenComponent,
}
}
}
const ComponentDidCatchPlugin = () => ({
fn: {
componentDidCatch,
},
})
const system = new System({
plugins: [
ViewPlugin,
BrokenComponentPlugin,
SafeRenderPlugin({
fullOverride: true,
componentList: ["BrokenComponent"],
}),
ComponentDidCatchPlugin,
]
})
const SafeBrokenComponent = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<SafeBrokenComponent />)
wrapper.find(BrokenComponent).simulateError(new Error("error"))
expect(componentDidCatch.calledOnce).toBe(true)
})
})

View File

@@ -911,142 +911,5 @@ describe("bound system", function(){
expect(system.getSystem().throwSelectors.func).not.toThrow()
})
describe("components", function() {
it("should catch errors thrown inside of React Component Class render methods", function() {
// Given
class BrokenComponent extends React.Component {
// eslint-disable-next-line react/require-render-return
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
let Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of pure component", function() {
// Given
class BrokenComponent extends PureComponent {
// eslint-disable-next-line react/require-render-return
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
let Component = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<Component />)
// Then
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of stateless component function", function() {
// Given
// eslint-disable-next-line react/require-render-return
const BrokenComponent = () => { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
const Component = system.getSystem().getComponent("BrokenComponent")
const wrapper = mount(<Component />)
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of container created from class component", function() {
// Given
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
const Component = system.getSystem().getComponent("BrokenComponent", true)
const wrapper = render(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of container created from stateless component function", function() {
// Given
const BrokenComponent = () => { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
const Component = system.getSystem().getComponent("BrokenComponent", true)
const wrapper = mount(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(wrapper.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
})
})
})