Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@marvelapp/react-ab-test

Package Overview
Dependencies
Maintainers
13
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@marvelapp/react-ab-test - npm Package Compare versions

Comparing version 2.3.0 to 3.0.0-beta.0

lib/hook.js

1

index.js

@@ -5,2 +5,3 @@ module.exports = {

emitter: require('./lib/emitter').default,
useExperiment: require('./lib/hook').default,
experimentDebugger: require('./lib/debugger'),

@@ -7,0 +8,0 @@ mixpanelHelper: require('./lib/helpers/mixpanel').default,

127

lib/CoreExperiment.js

@@ -7,4 +7,2 @@ 'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');

@@ -18,5 +16,5 @@

var _warning = require('fbjs/lib/warning');
var _hook = require('./hook');
var _warning2 = _interopRequireDefault(_warning);
var _hook2 = _interopRequireDefault(_hook);

@@ -27,104 +25,37 @@ var _emitter = require('./emitter');

var _Variant = require('./Variant');
var _Variant2 = _interopRequireDefault(_Variant);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var filterVariants = function filterVariants(name, children) {
var variants = {};
_react2.default.Children.forEach(children, function (element) {
if (!_react2.default.isValidElement(element) || element.type.displayName !== "Pushtell.Variant") {
var error = new Error("Pushtell Experiment children must be Pushtell Variant components.");
error.type = "PUSHTELL_INVALID_CHILD";
throw error;
}
variants[element.props.name] = element;
_emitter2.default.addExperimentVariant(name, element.props.name);
});
_emitter2.default.emit("variants-loaded", name);
return variants;
};
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
var CoreExperiment = function CoreExperiment(props) {
var variants = (0, _react.useMemo)(function () {
return filterVariants(props.name, props.children);
}, [props.name, props.children]);
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _useExperiment = (0, _hook2.default)(props.name, props.userIdentifier, props.defaultVariantName),
selectVariant = _useExperiment.selectVariant;
var CoreExperiment = function (_Component) {
_inherits(CoreExperiment, _Component);
return selectVariant(variants, []);
};
function CoreExperiment(props) {
_classCallCheck(this, CoreExperiment);
var _this = _possibleConstructorReturn(this, (CoreExperiment.__proto__ || Object.getPrototypeOf(CoreExperiment)).call(this));
_this.win = function () {
_emitter2.default.emitWin(_this.props.name);
};
_this.state = {};
_this.displayName = "Pushtell.CoreExperiment";
var children = {};
_react2.default.Children.forEach(props.children, function (element) {
if (!_react2.default.isValidElement(element) || element.type.displayName !== "Pushtell.Variant") {
var error = new Error("Pushtell Experiment children must be Pushtell Variant components.");
error.type = "PUSHTELL_INVALID_CHILD";
throw error;
}
children[element.props.name] = element;
_emitter2.default.addExperimentVariant(props.name, element.props.name);
});
_emitter2.default.emit("variants-loaded", props.name);
_this.state.variants = children;
return _this;
}
_createClass(CoreExperiment, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.props.value || nextProps.children !== this.props.children) {
var value = typeof nextProps.value === "function" ? nextProps.value() : nextProps.value;
var children = {};
_react2.default.Children.forEach(nextProps.children, function (element) {
children[element.props.name] = element;
});
this.setState({
value: value,
variants: children
});
}
}
}, {
key: 'componentWillMount',
value: function componentWillMount() {
var _this2 = this;
var value = typeof this.props.value === "function" ? this.props.value() : this.props.value;
if (!this.state.variants[value]) {
if ("production" !== process.env.NODE_ENV) {
(0, _warning2.default)(true, 'Experiment “' + this.props.name + '” does not contain variant “' + value + '”');
}
}
_emitter2.default._incrementActiveExperiments(this.props.name);
_emitter2.default.setActiveVariant(this.props.name, value);
_emitter2.default._emitPlay(this.props.name, value);
this.setState({
value: value
});
this.valueSubscription = _emitter2.default.addActiveVariantListener(this.props.name, function (experimentName, variantName) {
_this2.setState({
value: variantName
});
});
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
_emitter2.default._decrementActiveExperiments(this.props.name);
this.valueSubscription.remove();
}
}, {
key: 'render',
value: function render() {
return this.state.variants[this.state.value] || null;
}
}]);
return CoreExperiment;
}(_react.Component);
CoreExperiment.propTypes = {
name: _propTypes2.default.string.isRequired,
value: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.func]).isRequired
userIdentifier: _propTypes2.default.string,
defaultVariantName: _propTypes2.default.string,
children: _propTypes2.default.node
};
exports.default = CoreExperiment;
;
exports.default = CoreExperiment;

@@ -133,4 +133,4 @@ 'use strict';

}, {
key: 'componentWillMount',
value: function componentWillMount() {
key: 'componentDidMount',
value: function componentDidMount() {
this.activeSubscription = _emitter2.default.addListener("active", this.updateExperiments);

@@ -137,0 +137,0 @@ this.inactiveSubscription = _emitter2.default.addListener("inactive", this.updateExperiments);

@@ -7,4 +7,2 @@ "use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

@@ -32,6 +30,2 @@

var _calculateActiveVariant = require("./calculateActiveVariant");
var _calculateActiveVariant2 = _interopRequireDefault(_calculateActiveVariant);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -68,4 +62,2 @@

_emitter2.default.emitWin(_this.props.name);
}, _this.getActiveVariant = function () {
return (0, _calculateActiveVariant2.default)(_this.props.name, _this.props.userIdentifier, _this.props.defaultVariantName);
}, _temp), _possibleConstructorReturn(_this, _ret);

@@ -77,3 +69,7 @@ }

value: function render() {
return _react2.default.createElement(_CoreExperiment2.default, _extends({}, this.props, { value: this.getActiveVariant }));
return _react2.default.createElement(
_CoreExperiment2.default,
this.props,
this.props.children
);
}

@@ -88,5 +84,6 @@ }]);

defaultVariantName: _propTypes2.default.string,
userIdentifier: _propTypes2.default.string
userIdentifier: _propTypes2.default.string,
children: _propTypes2.default.node
};
Experiment.displayName = "Pushtell.Experiment";
exports.default = Experiment;

@@ -14,3 +14,3 @@ {

"main": "index.js",
"version": "2.3.0",
"version": "3.0.0-beta.0",
"description": "A/B testing React components and debug tools. Isomorphic with a simple, universal interface. Well documented and lightweight. Tested in popular browsers and Node.js. Includes helpers for Mixpanel and Segment.com.",

@@ -21,7 +21,7 @@ "directories": {

"peerDependencies": {
"react": ">=0.14.0 <17.0.0"
"react": ">=16.8.0 <17.0.0"
},
"dependencies": {
"fbemitter": "^2.0.2",
"fbjs": "^0.8.0",
"fbemitter": "^2.1.1",
"fbjs": "^1.0.0",
"prop-types": "^15.6.0"

@@ -39,4 +39,4 @@ },

"doctoc": "^1.3.1",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.1",

@@ -48,8 +48,8 @@ "es6-promise": "^4.2.4",

"eslint-plugin-react": "^7.7.0",
"fbemitter": "^2.0.2",
"fbjs": "^0.8.0",
"fbemitter": "^2.1.1",
"fbjs": "^1.0.0",
"jest": "^22.4.0",
"node-localstorage": "^1.3.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react": "^16.8.0",
"react-dom": "^16.8.0",
"uuid": "^3.2.1"

@@ -60,4 +60,4 @@ },

"build": "doctoc . --github --title '<h1>Table of Contents</h1>'; babel src --out-dir lib;",
"lint": "eslint .",
"lint:fix": "eslint --fix ."
"lint": "eslint --ignore-path .gitignore .",
"lint:fix": "eslint --ignore-path .gitignore --fix ."
},

@@ -68,3 +68,4 @@ "jest": {

"enzyme-to-json/serializer"
]
],
"testURL": "http://example.com"
},

@@ -71,0 +72,0 @@ "repository": {

@@ -97,14 +97,46 @@ # A/B Testing React Components

Using useExperiment Hook
```js
import React from 'react';
import { useExperiment } from '@marvelapp/react-ab-test';
// Hook usage pattern requires registration of experiments
emitter.defineVariants("My Example", ["A", "B"]);
const App = () => {
const { selectVariant, emitWin } = useExperiment("My Example");
const variant = selectVariant({
A: <div>Section A</div>
B: <div>Section B</div>
});
return (
<div>
{variant}
<button onClick={emitWin}>CTA</button>
</div>
);
};
```
Using Experiment Component
```js
import React from 'react';
import { Experiment, Variant, emitter } from '@marvelapp/react-ab-test';
class App extends Component {
experimentRef = React.createRef();
onButtonClick(e) {
this.refs.experiment.win();
this.experimentRef.current.win();
}
render() {
return (
<div>
<Experiment ref="experiment" name="My Example">
<Experiment ref={this.experimentRef} name="My Example">
<Variant name="A">

@@ -128,3 +160,3 @@ <div>Section A</div>

// Called when a 'win' is emitted, in this case by this.refs.experiment.win()
// Called when a 'win' is emitted, in this case by this.experimentRef.current.win()
emitter.addWinListener(function(experimentName, variantName) {

@@ -201,3 +233,3 @@ console.log(

// Called when a 'win' is emitted, in this case by this.refs.experiment.win()
// Called when a 'win' is emitted, in this case by emitter.emitWin('My Example')
emitter.addWinListener(function(experimentName, variantName) {

@@ -226,3 +258,3 @@ console.log(

<div>
<Experiment ref="experiment" name="My Example">
<Experiment name="My Example">
<Variant name="A">

@@ -279,3 +311,3 @@ <div>Section A</div>

<div>
<Experiment ref="experiment" name="My Example">
<Experiment name="My Example">
<Variant name="A">

@@ -316,3 +348,2 @@ <div>Section A</div>

<Experiment
ref="experiment"
name="My Example"

@@ -671,4 +702,7 @@ userIdentifier={this.props.userIdentifier}

class App extends React.Component {
experimentRef = React.createRef();
onButtonClick(e) {
emitter.emitWin('My Example');
this.experimentRef.current.win();
// mixpanelHelper sends the 'Experiment Win' event, equivalent to:

@@ -684,3 +718,3 @@ // mixpanel.track('Experiment Win', {Experiment: "My Example", Variant: "A"})

<div>
<Experiment ref="experiment" name="My Example">
<Experiment ref={this.experimentRef} name="My Example">
<Variant name="A">

@@ -732,4 +766,6 @@ <div>Section A</div>

class App extends React.Component {
experimentRef = React.createRef();
onButtonClick(e) {
emitter.emitWin('My Example');
this.experimentRef.current.win();
// segmentHelper sends the 'Experiment Won' event, equivalent to:

@@ -745,3 +781,3 @@ // segment.track('Experiment Won', {experimentName: "My Example", variationName: "A"})

<div>
<Experiment ref="experiment" name="My Example">
<Experiment ref={this.experimentRef} name="My Example">
<Variant name="A">

@@ -748,0 +784,0 @@ <div>Section A</div>

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc