Add try/catch protection for statePlugin interfaces

This commit is contained in:
Kyle Shockey
2018-01-03 13:56:29 -06:00
parent b749ea737d
commit c601f9b0ca
2 changed files with 323 additions and 116 deletions

View File

@@ -571,116 +571,6 @@ describe("bound system", function(){
// Then
expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props")
})
it("should catch errors thrown inside of React Component Class render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var 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 render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends PureComponent {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var 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 stateless component functions", function() {
// Given
// eslint-disable-next-line react/require-render-return
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
})
it("should catch errors thrown inside of container components", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent", true)
const renderedComponent = render(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
})
describe("afterLoad", function() {
@@ -793,4 +683,299 @@ describe("bound system", function(){
expect(res).toEqual("so selective")
})
})
describe("error catching", function() {
it("should encapsulate thrown errors in an afterLoad method", function() {
// Given
const ThrowyPlugin = {
afterLoad(system) {
throw new Error("afterLoad BREAKS STUFF!")
},
statePlugins: {
doge: {
selectors: {
wow: () => (system) => {
return "so selective"
}
}
}
}
}
const system = new System({
plugins: []
})
// When
expect(function() {
system.register([ThrowyPlugin])
// var resSystem = system.getSystem()
}).toNotThrow()
})
it("should encapsulate thrown errors in an action creator", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func() {
throw new Error("this action creator THROWS!")
}
}
}
}
}
})
expect(function() {
// TODO: fix existing action error catcher that creates THROWN ERR actions
system.getSystem().throwActions.func()
}).toNotThrow()
})
it("should encapsulate thrown errors in a reducer", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func: () => {
return {
type: "THROW_FUNC",
payload: "BOOM!"
}
}
},
reducers: {
"THROW_FUNC": (state, action) => {
throw new Error("this reducer EXPLODES!")
}
}
}
}
}
})
expect(function() {
system.getSystem().throwActions.func()
}).toNotThrow()
})
it("should encapsulate thrown errors in a selector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => {
throw new Error("this selector THROWS!")
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
it("should encapsulate thrown errors in a complex selector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => system => {
throw new Error("this selector THROWS!")
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
it("should encapsulate thrown errors in a wrapAction", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func: () => {
return {
type: "THROW_FUNC",
payload: "this original action does NOT throw"
}
}
},
wrapActions: {
func: (ori) => (...args) => {
throw new Error("this wrapAction UNRAVELS EVERYTHING!")
}
}
}
}
}
})
expect(system.getSystem().throwActions.func).toNotThrow()
})
it("should encapsulate thrown errors in a wrapSelector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => {
return 123
}
},
wrapSelectors: {
func: (ori) => (...props) => {
return ori(...props)
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
describe("components", function() {
it("should catch errors thrown inside of React Component Class render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var 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 render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends PureComponent {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var 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 stateless component functions", function() {
// Given
// eslint-disable-next-line react/require-render-return
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
})
it("should catch errors thrown inside of container components", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent", true)
const renderedComponent = render(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
})
})
})