Skip to content

Instantly share code, notes, and snippets.

@iammerrick
Last active February 2, 2023 19:58
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save iammerrick/dc7fc474083938d559ec to your computer and use it in GitHub Desktop.
Save iammerrick/dc7fc474083938d559ec to your computer and use it in GitHub Desktop.

Redux Chaos Monkey

This is a proof of concept which allows you to replay system events in a random order each time to make sure your UI can tolerate variable states.

I'm not sure if this is worthy of its on open source project with additional features like changing play back time, whitelisting/blacklisting actions etc but figured I'd put this out there to see if it piques anyones interest.

See a video of this in action here: [https://www.youtube.com/watch?v=wkoukONfwmA](Video on YouTube).

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, compose } from 'redux';
import { connect, Provider} from 'react-redux';
import { createDevTools, ActionCreators } from 'redux-devtools';
const { reset, performAction } = ActionCreators;
/**
* Developer Tools
*/
const Havoc = connect((state) => state, {
reset,
performAction
})(class extends React.Component {
constructor(){
super(...arguments);
this.havoc = this.havoc.bind(this);
}
havoc() {
const goHam = (list) => {
const keys = Object.keys(list);
const random = keys[Math.floor(Math.random() * keys.length)];
if (keys.length === 0) return null;
if (list[random].action.type !== '@@INIT') {
this.props.performAction(list[random].action);
}
const remaining = keys.reduce((acc, key) => {
if (key === random) return acc;
acc[key] = list[key];
return acc;
}, {});
setTimeout(() => goHam(remaining), 500);
};
this.props.reset();
goHam(this.props.actionsById);
}
render() {
return (
<div style={{ backgroundColor: '#eee' }}>
<button onClick={this.havoc}>Wreak Chaos</button>
{Object.keys(this.props.actionsById).map((action) => {
return <div key={action}>{this.props.actionsById[action].action.type}</div>;
})}
</div>
);
}
});
Havoc.update = () => {};
const DeveloperTools = createDevTools(<Havoc />);
const finalCreateStore = compose(
DeveloperTools.instrument()
)(createStore);
/**
* Constants
*/
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
/**
* Store
*/
const store = finalCreateStore((state = { count: 0 }, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
case DECREMENT:
return { count: state.count - 1 };
default:
return state;
}
});
/**
* Actions
*/
const increment = () => {
return {
type: INCREMENT
};
};
const decrement = () => {
return {
type: DECREMENT
};
};
/**
* Selectors
*/
const selectCount = (state) => {
return state.count;
};
/**
* Components
*/
const Counter = connect((state) => ({
count: selectCount(state)
}), {
increment,
decrement
})(class extends React.Component {
render() {
return (
<div>
<button onClick={this.props.increment}>+</button>
<button onClick={this.props.decrement}>-</button>
{this.props.count}
</div>
);
}
});
ReactDOM.render(
<Provider store={store}>
<div>
<Counter />
<DeveloperTools />
</div>
</Provider>
, document.getElementById('viewport'));
@ccorcos
Copy link

ccorcos commented Jan 7, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment