redux-ab-test
Version:
A/B testing React components with Redux and debug tools. Isomorphic with a simple, universal interface. Well documented and lightweight. Tested in popular browsers and Node.js. Includes helpers for React, Redux, and Segment.io
227 lines (186 loc) • 7.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.mapStateToProps = undefined;
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactRedux = require('react-redux');
var _reactImmutableProptypes = require('react-immutable-proptypes');
var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
var _selectVariation = require('../../utils/select-variation');
var _selectVariation2 = _interopRequireDefault(_selectVariation);
var _logger = require('./logger');
var _loadedComponent = require('./loaded-component');
var _loadedComponent2 = _interopRequireDefault(_loadedComponent);
var _selectors = require('./selectors');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var Experiment = function (_React$Component) {
(0, _inherits3['default'])(Experiment, _React$Component);
function Experiment() {
(0, _classCallCheck3['default'])(this, Experiment);
return (0, _possibleConstructorReturn3['default'])(this, (Experiment.__proto__ || (0, _getPrototypeOf2['default'])(Experiment)).apply(this, arguments));
}
(0, _createClass3['default'])(Experiment, [{
key: 'render',
value: function () {
function render() {
var _props = this.props,
name = _props.name,
defaultVariationName = _props.defaultVariationName,
isEnabled = _props.isEnabled,
isLoading = _props.isLoading,
experimentsByName = _props.experimentsByName,
reduxAbTest = _props.reduxAbTest,
children = _props.children;
var enabled = isEnabled();
var loading = isLoading();
var childrenByName = (0, _selectors.groupChildrenByName)(children);
(0, _logger.logger)(__filename + ': Rendering Experiment name=\'' + name + '\', enabled=\'' + enabled + '\', loading=\'' + loading + '\', children.names=' + (0, _keys2['default'])(childrenByName));
// The default output is default variation's children,
// when the experiment is disabled / loading / invalid.
var defaultOutput = childrenByName[defaultVariationName] && childrenByName[defaultVariationName].children;
//
// Render the disabled / loading states
//
if (!enabled) {
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is disabled');
var getDisabledState = this.props.getDisabledState;
if (getDisabledState) {
return getDisabledState();
}
return _react2['default'].createElement(
'span',
null,
defaultOutput
);
}
if (loading) {
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is loading');
var getLoadingState = this.props.getLoadingState;
if (getLoadingState) {
return getLoadingState();
}
return _react2['default'].createElement(
'span',
null,
defaultOutput
);
}
//
// Get the experiment && variation from the input props:
//
var experiment = null;
var variation = null;
experiment = experimentsByName[name];
variation = experiment && (0, _selectVariation2['default'])({
experiment: experiment,
active: reduxAbTest.get('active'),
defaultVariationName: defaultVariationName
});
if (!experiment && forceRender) {
// Force the experiment object into existance to allow the component to render
// This should be used for ad-hock experiment
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is forced to render');
experiment = Immutable.Map({ name: name });
variation = Immutable.Map({ name: defaultVariationName });
}
if (!experiment) {
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is enabled, but not in the store');
return _react2['default'].createElement(
'span',
null,
defaultOutput
);
}
if (!variation) {
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is enabled, but no variation is available');
return _react2['default'].createElement(
'span',
null,
defaultOutput
);
}
var variationName = variation.get('name', '');
// Valdiate the variation selected exists
if (!childrenByName[variationName]) {
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' has no child with the name=\'' + variationName + '\'');
return _react2['default'].createElement(
'span',
null,
defaultOutput
);
}
//
// Render the component wrapper with the attached experiment
//
(0, _logger.logger)(__filename + ': Experiment name=\'' + name + '\' is enabled');
return _react2['default'].createElement(
_loadedComponent2['default'],
{
experimentName: name,
variationName: variationName,
experiment: experiment,
variation: variation
},
children
);
}
return render;
}()
}]);
return Experiment;
}(_react2['default'].Component);
Experiment.propTypes = {
// Name of the experiment
name: _react2['default'].PropTypes.string.isRequired,
defaultVariationName: _react2['default'].PropTypes.string.isRequired,
// Selector for the experiment
isEnabled: _react2['default'].PropTypes.func.isRequired,
// React element to render:
children: _selectors.requireChildrenAreVariations,
// Optional selectors for additional control
isLoading: _react2['default'].PropTypes.func,
forceRender: _react2['default'].PropTypes.bool,
// Optional components for loading state:
getLoadingState: _react2['default'].ProptTypes.func,
getDisabledState: _react2['default'].ProptTypes.func,
//
// Redux store props:
//
experimentsByName: _react2['default'].PropTypes.object.isRequired,
reduxAbTest: _reactImmutableProptypes2['default'].map.isRequired
};
Experiment.defaultProps = {
isLoading: function () {
function isLoading() {
return false;
}
return isLoading;
}(),
getLoadingState: null,
getDisabledState: null,
forceRender: false
};
var mapStateToProps = exports.mapStateToProps = function () {
function mapStateToProps(state) {
return {
reduxAbTest: state,
experimentsByName: (0, _selectors.groupExperimentsByName)(state)
};
}
return mapStateToProps;
}();
exports['default'] = (0, _reactRedux.connect)(mapStateToProps)(Experiment);
;