UNPKG

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
'use strict'; 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);