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

@the-control-group/react-split-test

Package Overview
Dependencies
Maintainers
7
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@the-control-group/react-split-test - npm Package Compare versions

Comparing version 0.9.1 to 1.0.0

70

lib/Experiment.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const variationPromiseCache = new Map();
export default class Experiment extends Component {

@@ -9,7 +11,21 @@ static propTypes = {

session: PropTypes.bool,
onParticipate: PropTypes.func
onParticipate: PropTypes.func,
variationDecider: PropTypes.func
};
static defaultProps = {
onParticipate: () => {}
onParticipate: () => {},
/**
* Stub A/B decider
* @param {React.node} experimentChildren - React children nodes of the experiment
* @return {Promise<variation id>} Selected variation ID
*/
variationDecider: experimentChildren => {
const variations = [];
React.Children.forEach(experimentChildren, c => {
if(c.props.isVariation) variations.push(c.props.id);
});
return Promise.resolve(variations[Math.floor(Math.random() * variations.length)]);
}
};

@@ -36,24 +52,44 @@

let selectedVariation;
if(cachedData) {
selectedVariation = cachedData.selectedVariation;
return cachedData.selectedVariation;
} else {
const variations = [];
React.Children.forEach(this.props.children, c => {
if(c.props.isVariation) variations.push(c.props.id);
});
// Cache promises so only one decision is made per experiment ID
let variationDecider;
if(variationPromiseCache.has(this.props.id)) {
variationDecider = variationPromiseCache.get(this.props.id);
} else {
variationDecider = this.props.variationDecider(this.props.children);
variationPromiseCache.set(this.props.id, variationDecider);
}
selectedVariation = variations[Math.floor(Math.random() * variations.length)];
variationDecider
.then(selectedVariation => {
const experimentData = {
id: this.props.id,
selectedVariation
};
const experimentData = {
id: this.props.id,
selectedVariation
};
// Since this is async, we need to check if another component with the same experiment
// has already made this decision in a potential race condition
let raceData;
try {
raceData = JSON.parse(this.storage.getItem(this.cacheKey));
} catch(e) {
// No/invalid data
}
this.props.onParticipate(experimentData);
if(!raceData) {
this.storage.setItem(this.cacheKey, JSON.stringify(experimentData));
this.props.onParticipate(experimentData);
// Remove the initial promise from the cache since subsequent renders/mounts will work off of the cache
variationPromiseCache.delete(this.props.id);
}
this.storage.setItem(this.cacheKey, JSON.stringify(experimentData));
this.setState({
selectedVariation: raceData ? raceData.selectedVariation : selectedVariation
});
});
return null;
}
return selectedVariation;
}

@@ -60,0 +96,0 @@

export { default as Experiment } from './Experiment';
export { default as Variation } from './Variation';
export function clearExperimentCache() {
// These only work for persisted variations
export function getCachedVariation(id) {
return JSON.parse(localStorage.getItem(`@tcg-split-test:${id}`));
}
export function clearExperimentCache(id) {
localStorage.removeItem(`@tcg-split-test:${id}`);
}
export function clearAllExperimentCaches() {
Object.keys(localStorage).forEach(k => /^@tcg-split-test:/.test(k) && localStorage.removeItem(k));
}
{
"name": "@the-control-group/react-split-test",
"version": "0.9.1",
"version": "1.0.0",
"description": "A/B Split Testing Component for React",

@@ -34,20 +34,20 @@ "files": [

"devDependencies": {
"@babel/cli": "^7.0.0-rc.1",
"@babel/core": "^7.0.0-rc.1",
"@babel/plugin-proposal-class-properties": "^7.0.0-rc.1",
"@babel/preset-env": "^7.0.0-rc.1",
"@babel/preset-react": "^7.0.0-rc.1",
"babel-eslint": "^8.2.6",
"babel-loader": "^8.0.0-beta.4",
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"cpx": "^1.5.0",
"eslint": "^5.3.0",
"eslint-plugin-react": "^7.10.0",
"eslint": "^6.5.1",
"eslint-plugin-react": "^7.16.0",
"html-webpack-plugin": "^3.2.0",
"prop-types": "^15.6.2",
"react": "^16.4.2",
"react-devtools": "^3.2.3",
"react-dom": "^16.4.2",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
"react-devtools": "^4.2.0",
"react-dom": "^16.10.2",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.2"
},

@@ -54,0 +54,0 @@ "peerDependencies": {

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