UNPKG

@crasman/google-optimize-experiment

Version:

Shared module for AB testing via Google Optimize Experiments.

142 lines (123 loc) 4.11 kB
/** * Registers an implementation callback for an experiment to Google Optimize JavaScript API * and provides an option to fallback to default variant on timeout. * * API documentation: * {@link https://support.google.com/optimize/answer/9059383} * * @class GoogleOptimizeExperiment * * @example * const experiment = new GoogleOptimizeExperiment({ * callback: (variant) => variant.hidden = false, * callbackTimeout: 1000, * experimentId: 'JrXRqt5hRlCe29fqwiWkUg', * variants: [...document.getElementsByClassName('variant')], * }); */ class GoogleOptimizeExperiment { /** * Creates an instance of GoogleOptimizeExperiment. * @param {object} params - object containing configuration parameters * @param {function(variant, variantIndex)} [params.callback=() => {}] - Function to call back with variant and its index. * @param {string} [params.callbackEventName='optimize.callback'] - Name of the custom event that activates the experiment. * @param {number} [params.callbackTimeout] - Time in milliseconds to timeout and to fall back to default variant. * @param {string} params.experimentId - ID of experiment. * @param {number} [params.fallbackVariantIndex=1] - Index of variant to fall back to on timeout. * @param {HTMLElement[]} [params.variants=[]] - Variants to test. * @memberof GoogleOptimizeExperiment */ constructor({ callback = () => {}, callbackEventName = 'optimize.callback', callbackTimeout, experimentId, fallbackVariantIndex = 1, variants = [] }) { this.callback = callback; this.callbackEventName = callbackEventName; this.callbackTimeout = callbackTimeout; this.experimentId = experimentId; this.fallbackVariantIndex = fallbackVariantIndex; this.variants = variants; this.variantIndex = -1; this.callbackWrapper = this.callbackWrapper.bind(this); if (this.callbackTimeout) { this.callbackTimeoutId = setTimeout(() => { this.unregisterCallback(); this.variantIndex = this.fallbackVariantIndex; this.callback(this.variantIndex, this.experimentId); }, this.callbackTimeout); } this.registerCallback(); } /** * Gets active variant. * * @memberof GoogleOptimizeExperiment */ get variant() { return this.variantIndex in this.variants ? this.variants[this.variantIndex] : null; } /** * @memberof GoogleOptimizeExperiment * @param {any} _ ignore */ set variant(_) {} /** * Handles callback from the API and calls the provided callback function with active variant and its index. * * @param {string} variantIndex - the selected variant * @param {string} experimentId - the active experiment id * @param {string} optimizeId - the active optimize account * @memberof GoogleOptimizeExperiment */ callbackWrapper(variantIndex, experimentId, optimizeId) { if (this.callbackTimeoutId) clearTimeout(this.callbackTimeoutId); this.variantIndex = parseInt(variantIndex); this.callback(this.variantIndex, experimentId, optimizeId); } /** * Clears callback timeout and unregisters callback from the API. * * @memberof GoogleOptimizeExperiment */ cleanup() { if (this.callbackTimeoutId) clearTimeout(this.callbackTimeoutId); this.unregisterCallback(); } /** * Registers implementation callback for an experiment to the API. * * @memberof GoogleOptimizeExperiment */ registerCallback() { gtag('event', this.callbackEventName, { name: this.experimentId, callback: this.callbackWrapper }); } /** * Unregisters implementation callback for an experiment from the API. * * @memberof GoogleOptimizeExperiment */ unregisterCallback() { gtag('event', this.callbackEventName, { name: this.experimentId, callback: this.callbackWrapper, remove: true }); } } /** * Pushes arguments to data layer. */ function gtag() { if (!('dataLayer' in window)) { window.dataLayer = []; } window.dataLayer.push(arguments); } export { GoogleOptimizeExperiment };