@marvelapp/react-ab-test
Advanced tools
Comparing version 2.2.0 to 2.3.0
@@ -9,2 +9,8 @@ 'use strict'; | ||
var _calculateActiveVariant = require('./calculateActiveVariant'); | ||
var _calculateActiveVariant2 = _interopRequireDefault(_calculateActiveVariant); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var values = {}; | ||
@@ -177,2 +183,7 @@ var experiments = {}; | ||
PushtellEventEmitter.prototype.calculateActiveVariant = function (experimentName, userIdentifier, defaultVariantName) { | ||
var variant = (0, _calculateActiveVariant2.default)(experimentName, userIdentifier, defaultVariantName); | ||
return variant; | ||
}; | ||
PushtellEventEmitter.prototype.getActiveVariant = function (experimentName) { | ||
@@ -206,3 +217,2 @@ return values[experimentName]; | ||
exports.default = new PushtellEventEmitter(); | ||
; | ||
exports.default = new PushtellEventEmitter(); |
@@ -27,6 +27,10 @@ "use strict"; | ||
var _crc = require("fbjs/lib/crc32"); | ||
var _store = require("./store"); | ||
var _crc2 = _interopRequireDefault(_crc); | ||
var _store2 = _interopRequireDefault(_store); | ||
var _calculateActiveVariant = require("./calculateActiveVariant"); | ||
var _calculateActiveVariant2 = _interopRequireDefault(_calculateActiveVariant); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -40,26 +44,2 @@ | ||
var store = void 0; | ||
var noopStore = { | ||
getItem: function getItem() {}, | ||
setItem: function setItem() {} | ||
}; | ||
if (typeof window !== 'undefined' && 'localStorage' in window) { | ||
try { | ||
var key = '__pushtell_react__'; | ||
window.localStorage.setItem(key, key); | ||
if (window.localStorage.getItem(key) !== key) { | ||
store = noopStore; | ||
} else { | ||
window.localStorage.removeItem(key); | ||
store = window.localStorage; | ||
} | ||
} catch (e) { | ||
store = noopStore; | ||
} | ||
} else { | ||
store = noopStore; | ||
} | ||
_emitter2.default.addActiveVariantListener(function (experimentName, variantName, skipSave) { | ||
@@ -69,3 +49,3 @@ if (skipSave) { | ||
} | ||
store.setItem('PUSHTELL-' + experimentName, variantName); | ||
_store2.default.setItem('PUSHTELL-' + experimentName, variantName); | ||
}); | ||
@@ -89,58 +69,4 @@ | ||
_emitter2.default.emitWin(_this.props.name); | ||
}, _this.getSelectedVariant = function () { | ||
/* | ||
Choosing a weighted variant: | ||
For C, A, B with weights 2, 4, 8 | ||
variants = A, B, C | ||
weights = 4, 8, 2 | ||
weightSum = 14 | ||
weightedIndex = 9 | ||
AAAABBBBBBBBCC | ||
========^ | ||
Select B | ||
*/ | ||
// Sorted array of the variant names, example: ["A", "B", "C"] | ||
var variants = _emitter2.default.getSortedVariants(_this.props.name); | ||
// Array of the variant weights, also sorted by variant name. For example, if | ||
// variant C had weight 2, variant A had weight 4, and variant B had weight 8 | ||
// return [4, 8, 2] to correspond with ["A", "B", "C"] | ||
var weights = _emitter2.default.getSortedVariantWeights(_this.props.name); | ||
// Sum the weights | ||
var weightSum = weights.reduce(function (a, b) { | ||
return a + b; | ||
}, 0); | ||
// A random number between 0 and weightSum | ||
var weightedIndex = typeof _this.props.userIdentifier === 'string' ? Math.abs((0, _crc2.default)(_this.props.userIdentifier) % weightSum) : Math.floor(Math.random() * weightSum); | ||
// Iterate through the sorted weights, and deduct each from the weightedIndex. | ||
// If weightedIndex drops < 0, select the variant. If weightedIndex does not | ||
// drop < 0, default to the last variant in the array that is initially assigned. | ||
var selectedVariant = variants[variants.length - 1]; | ||
for (var index = 0; index < weights.length; index++) { | ||
weightedIndex -= weights[index]; | ||
if (weightedIndex < 0) { | ||
selectedVariant = variants[index]; | ||
break; | ||
} | ||
} | ||
_emitter2.default.setActiveVariant(_this.props.name, selectedVariant); | ||
return selectedVariant; | ||
}, _this.getLocalStorageValue = function () { | ||
if (typeof _this.props.userIdentifier === "string") { | ||
return _this.getSelectedVariant(); | ||
} | ||
var activeValue = _emitter2.default.getActiveVariant(_this.props.name); | ||
if (typeof activeValue === "string") { | ||
return activeValue; | ||
} | ||
var storedValue = store.getItem('PUSHTELL-' + _this.props.name); | ||
if (typeof storedValue === "string") { | ||
_emitter2.default.setActiveVariant(_this.props.name, storedValue, true); | ||
return storedValue; | ||
} | ||
if (typeof _this.props.defaultVariantName === 'string') { | ||
_emitter2.default.setActiveVariant(_this.props.name, _this.props.defaultVariantName); | ||
return _this.props.defaultVariantName; | ||
} | ||
return _this.getSelectedVariant(); | ||
}, _this.getActiveVariant = function () { | ||
return (0, _calculateActiveVariant2.default)(_this.props.name, _this.props.userIdentifier, _this.props.defaultVariantName); | ||
}, _temp), _possibleConstructorReturn(_this, _ret); | ||
@@ -152,3 +78,3 @@ } | ||
value: function render() { | ||
return _react2.default.createElement(_CoreExperiment2.default, _extends({}, this.props, { value: this.getLocalStorageValue })); | ||
return _react2.default.createElement(_CoreExperiment2.default, _extends({}, this.props, { value: this.getActiveVariant })); | ||
} | ||
@@ -155,0 +81,0 @@ }]); |
@@ -14,3 +14,3 @@ { | ||
"main": "index.js", | ||
"version": "2.2.0", | ||
"version": "2.3.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.", | ||
@@ -17,0 +17,0 @@ "directories": { |
@@ -43,2 +43,3 @@ # A/B Testing React Components | ||
- [Weighting Variants](#weighting-variants) | ||
- [Force variant calculation before rendering experiment](#force-variant-calculation-before-rendering-experiment) | ||
- [Debugging](#debugging) | ||
@@ -61,2 +62,3 @@ - [Server Rendering](#server-rendering) | ||
- [`emitter.getActiveVariant(experimentName)`](#emittergetactivevariantexperimentname) | ||
- [`emitter.calculateActiveVariant(experimentName [, userIdentifier, defaultVariantName])`](#emittercalculateactivevariantexperimentname--useridentifier-defaultvariantname) | ||
- [`emitter.getSortedVariants(experimentName)`](#emittergetsortedvariantsexperimentname) | ||
@@ -88,3 +90,3 @@ - [`Subscription`](#subscription) | ||
```bash | ||
yarn install @marvelapp/react-ab-test | ||
yarn add @marvelapp/react-ab-test | ||
``` | ||
@@ -240,2 +242,19 @@ | ||
### Force variant calculation before rendering experiment | ||
There are some scenarios where you may want the active variant of an experiment to be calculated before the experiment is rendered. | ||
To do so, use [emitter.calculateActiveVariant()](#emittercalculateactivevariantexperimentname--useridentifier-defaultvariantname). Note that this method must | ||
be called after [emitter.defineVariants()](#emitterdefinevariantsexperimentname-variantnames--variantweights) | ||
```js | ||
import { emitter } from '@marvelapp/react-ab-test'; | ||
// Define variants in advance | ||
emitter.defineVariants('My Example', ['A', 'B', 'C']); | ||
emitter.calculateActiveVariant('My Example', 'userId'); | ||
// Active variant will be defined even if the experiment is not rendered | ||
const activeVariant = emitter.getActiveVariant('My Example'); | ||
``` | ||
### Debugging | ||
@@ -558,2 +577,22 @@ | ||
#### `emitter.calculateActiveVariant(experimentName [, userIdentifier, defaultVariantName])` | ||
Force calculation of active variant, even if the experiment is not displayed yet. | ||
Note: This method must be called after `emitter.defineVariants` | ||
* **Return Type:** `string` | ||
* **Parameters:** | ||
* `experimentName` - Name of the experiment. | ||
* **Required** | ||
* **Type:** `string` | ||
* **Example:** `"My Example"` | ||
* `userIdentifier` - Distinct user identifier. When defined, this value is hashed to choose a variant if `defaultVariantName` or a stored value is not present. Useful for [server side rendering](#server-rendering). | ||
* **Optional** | ||
* **Type:** `string` | ||
* **Example:** `"7cf61a4521f24507936a8977e1eee2d4"` | ||
* `defaultVariantName` - Name of the default variant. When defined, this value is used to choose a variant if a stored value is not present. This property may be useful for [server side rendering](#server-rendering) but is otherwise not recommended. | ||
* **Optional** | ||
* **Type:** `string` | ||
* **Example:** `"A"` | ||
#### `emitter.getSortedVariants(experimentName)` | ||
@@ -560,0 +599,0 @@ |
69224
13
797
784