From b6c7d7c3518fcc82d0c2aaa7ac8cf437dbdfdedd Mon Sep 17 00:00:00 2001 From: Patrick Shih Date: Thu, 4 Jun 2020 16:18:49 -0700 Subject: [PATCH 1/2] expose edge --- integrations/optimizely/HISTORY.md | 5 +++++ integrations/optimizely/lib/index.js | 24 ++++++++++++++++------ integrations/optimizely/package.json | 3 ++- integrations/optimizely/test/index.test.js | 23 +++++++++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/integrations/optimizely/HISTORY.md b/integrations/optimizely/HISTORY.md index ebdb0e517..ddc8fa56b 100644 --- a/integrations/optimizely/HISTORY.md +++ b/integrations/optimizely/HISTORY.md @@ -1,3 +1,8 @@ +3.6.0 / 2020-06-04 +================== + + * Exposed `window.optimizelyEdge` so customers with Performance Edge are able to track Performance Edge related experiments in Segment. + 3.5.0 / 2019-12-28 ================== diff --git a/integrations/optimizely/lib/index.js b/integrations/optimizely/lib/index.js index 8c18d286d..c4689ce6e 100644 --- a/integrations/optimizely/lib/index.js +++ b/integrations/optimizely/lib/index.js @@ -9,8 +9,9 @@ var values = require('@ndhoule/values'); var foldl = require('@ndhoule/foldl'); var each = require('@ndhoule/each'); var integration = require('@segment/analytics.js-integration'); -var push = require('global-queue')('optimizely', { wrap: false }); var tick = require('next-tick'); +var push = require('global-queue')('optimizely', { wrap: false }); +var pushEdge = require('global-queue')('optimizelyEdge', { wrap: false }); /** * Expose `Optimizely` integration. @@ -47,10 +48,17 @@ var optimizelyContext = { Optimizely.prototype.initialize = function() { var self = this; // Flag source of integration (requested by Optimizely) - push({ - type: 'integration', - OAuthClientId: '5360906403' - }); + if (window.optimizelyEdge) { + pushEdge({ + type: 'integration', + OAuthClientId: '5360906403' + }); + } else { + push({ + type: 'integration', + OAuthClientId: '5360906403' + }); + } // Initialize listeners for both Classic and New Optimizely // crazying binding because that's just how javascript works // We're caling this on the next tick to be safe so we don't hold up @@ -116,7 +124,11 @@ Optimizely.prototype.track = function(track) { tags: eventProperties }; - push(payload); + if (window.optimizelyEdge) { + pushEdge(payload); + } else { + push(payload); + } var optimizelyClientInstance = window.optimizelyClientInstance; if (optimizelyClientInstance && optimizelyClientInstance.track) { diff --git a/integrations/optimizely/package.json b/integrations/optimizely/package.json index 128b01bed..834ab155b 100644 --- a/integrations/optimizely/package.json +++ b/integrations/optimizely/package.json @@ -1,7 +1,7 @@ { "name": "@segment/analytics.js-integration-optimizely", "description": "The Optimizely analytics.js integration.", - "version": "3.5.0", + "version": "3.6.0", "keywords": [ "analytics.js", "analytics.js-integration", @@ -46,6 +46,7 @@ "karma-sauce-launcher": "^2.0.2", "karma-spec-reporter": "^0.0.32", "karma-summary-reporter": "^1.6.0", + "lerna": "^3.15.0", "mocha": "^6.1.4", "watchify": "^3.11.1" } diff --git a/integrations/optimizely/test/index.test.js b/integrations/optimizely/test/index.test.js index 81253a299..59a327e04 100644 --- a/integrations/optimizely/test/index.test.js +++ b/integrations/optimizely/test/index.test.js @@ -1070,6 +1070,29 @@ describe('Optimizely', function() { analytics.stub(window.optimizely, 'push'); }); + describe('when the experiment running is from Edge', function() { + beforeEach(function() { + window.optimizelyEdge = []; + analytics.stub(window.optimizelyEdge, 'push'); + }); + afterEach(function() { + delete window.optimizelyEdge; + }); + it('should send an event to window.optimizelyEdge, not window.optimizely', function() { + analytics.track('event'); + analytics.called(window.optimizelyEdge.push, { + type: 'event', + eventName: 'event', + tags: {} + }); + analytics.didNotCall(window.optimizely.push, { + type: 'event', + eventName: 'event', + tags: {} + }); + }); + }); + it('should send an event', function() { analytics.track('event'); analytics.called(window.optimizely.push, { From 19b11c6393c75f75703740b7e2a12bebf0318493 Mon Sep 17 00:00:00 2001 From: Patrick Shih Date: Mon, 15 Jun 2020 17:53:20 -0700 Subject: [PATCH 2/2] a record of progress, will be rebased on top of nikhil's branch --- c.json | 13 + integrations/optimizely/HISTORY.md | 2 +- integrations/optimizely/lib/index.js | 1385 +++++----- integrations/optimizely/package.json | 1 - integrations/optimizely/test/index.test.js | 2680 ++++++++++---------- yarn.lock | 8 +- 6 files changed, 2143 insertions(+), 1946 deletions(-) create mode 100644 c.json diff --git a/c.json b/c.json new file mode 100644 index 000000000..283244e88 --- /dev/null +++ b/c.json @@ -0,0 +1,13 @@ +{ + "npmClient": "yarn", + "useWorkspaces": true, + "version": "independent", + "packages": [ + "integrations/*" + ], + "publish": { + "ignoreChanges": [ + "*.md" + ] + } +} diff --git a/integrations/optimizely/HISTORY.md b/integrations/optimizely/HISTORY.md index ddc8fa56b..3ff86422e 100644 --- a/integrations/optimizely/HISTORY.md +++ b/integrations/optimizely/HISTORY.md @@ -1,7 +1,7 @@ 3.6.0 / 2020-06-04 ================== - * Exposed `window.optimizelyEdge` so customers with Performance Edge are able to track Performance Edge related experiments in Segment. + * Track conversion events using `window.optimizelyEdge` instead of `window.optimizely` if Optimizely Performance Edge is running on the page. 3.5.0 / 2019-12-28 diff --git a/integrations/optimizely/lib/index.js b/integrations/optimizely/lib/index.js index c4689ce6e..62086f393 100644 --- a/integrations/optimizely/lib/index.js +++ b/integrations/optimizely/lib/index.js @@ -1,642 +1,743 @@ -'use strict'; - -/** - * Module dependencies. - */ - -var keys = require('@ndhoule/keys'); -var values = require('@ndhoule/values'); -var foldl = require('@ndhoule/foldl'); -var each = require('@ndhoule/each'); -var integration = require('@segment/analytics.js-integration'); -var tick = require('next-tick'); -var push = require('global-queue')('optimizely', { wrap: false }); -var pushEdge = require('global-queue')('optimizelyEdge', { wrap: false }); - -/** - * Expose `Optimizely` integration. - */ - -var Optimizely = (module.exports = integration('Optimizely') - .option('trackCategorizedPages', true) - .option('trackNamedPages', true) - .option('variations', false) // send data via `.identify()` - .option('listen', true) // send data via `.track()` - .option('nonInteraction', false) - .option('sendRevenueOnlyForOrderCompleted', true) - .option('customExperimentProperties', {}) - .option('customCampaignProperties', {})); - -/** - * The name and version for this integration. - */ - -var optimizelyContext = { - name: 'optimizely', - version: '2.0.0' -}; - -/** - * Initialize. - * - * https://www.optimizely.com/docs/api#function-calls - * https://jsfiddle.net/ushmw723/ <- includes optimizely snippets for capturing campaign and experiment data - * - * @api public - */ - -Optimizely.prototype.initialize = function() { - var self = this; - // Flag source of integration (requested by Optimizely) - if (window.optimizelyEdge) { - pushEdge({ - type: 'integration', - OAuthClientId: '5360906403' - }); - } else { - push({ - type: 'integration', - OAuthClientId: '5360906403' - }); - } - // Initialize listeners for both Classic and New Optimizely - // crazying binding because that's just how javascript works - // We're caling this on the next tick to be safe so we don't hold up - // initializing the integration even though the function below is designed to be async, - // just want to be extra safe - tick(function() { - Optimizely.initOptimizelyIntegration({ - referrerOverride: self.setEffectiveReferrer.bind(self), - sendExperimentData: self.sendClassicDataToSegment.bind(self), - sendCampaignData: self.sendNewDataToSegment.bind(self) - }); - }); - - this.ready(); -}; - -/** - * Track. The Optimizely X Web event API accepts a single payload object. - * It works with Classic Optimizely as well. - * - * Optimizely X: https://developers.optimizely.com/x/solutions/javascript/reference/index.html#function_setevent - * - * The new-style X API is forward compatible from Optimizely Classic to Optimizely X. - * - Classic will correctly consume the tags object to identify the revenue - * - In bundled mode, it will be forwarded along to the X API with the entire payload - * - * If the Optimizely X Fullstack JavaScript SDK is being used we should pass along - * the event to it. Any properties in the track object will be passed along as event tags. - * If the userId is not passed into the options object of the track call, we'll - * attempt to use the userId of the track event, which is set using the analytics.identify call. - * - * https://developers.optimizely.com/x/solutions/sdks/reference/?language=javascript#tracking - * - * @api public - * @param {Track} track - */ - -Optimizely.prototype.track = function(track) { - var opts = this.options; - var eventProperties = track.properties(); - - // Optimizely expects revenue only passed through Order Completed events - if (eventProperties.revenue && opts.sendRevenueOnlyForOrderCompleted) { - if (track.event() === 'Order Completed') { - eventProperties.revenue = Math.round(eventProperties.revenue * 100); - } else if (track.event() !== 'Order Completed') { - delete eventProperties.revenue; - } - // This is legacy Segment-Optimizely behavior, - // which passes revenue whenever it is present - } else if ( - opts.sendRevenueOnlyForOrderCompleted === false && - eventProperties.revenue - ) { - eventProperties.revenue = Math.round(eventProperties.revenue * 100); - } - - // Use the new-style API (which is compatible with Classic and X) - var eventName = track.event().replace(/:/g, '_'); // can't have colons so replacing with underscores - var payload = { - type: 'event', - eventName: eventName, - tags: eventProperties - }; - - if (window.optimizelyEdge) { - pushEdge(payload); - } else { - push(payload); - } - - var optimizelyClientInstance = window.optimizelyClientInstance; - if (optimizelyClientInstance && optimizelyClientInstance.track) { - var optimizelyOptions = track.options('Optimizely'); - var userId = - optimizelyOptions.userId || track.userId() || this.analytics.user().id(); - var attributes = - optimizelyOptions.attributes || - track.traits() || - this.analytics.user().traits(); - if (userId) { - optimizelyClientInstance.track( - eventName, - userId, - attributes, - payload.tags - ); - } - } -}; - -/** - * Page. - * - * https://www.optimizely.com/docs/api#track-event - * - * @api public - * @param {Page} page - */ - -Optimizely.prototype.page = function(page) { - var category = page.category(); - var name = page.fullName(); - var opts = this.options; - - // categorized pages - if (category && opts.trackCategorizedPages) { - this.track(page.track(category)); - } - - // named pages - if (name && opts.trackNamedPages) { - this.track(page.track(name)); - } -}; - -/** - * sendClassicDataToSegment (Optimizely Classic) - * - * This function is executed for each experiment created in Classic Optimizely that is running on the page. - * This function will also be executed for any experiments activated at a later stage since initOptimizelyIntegration - * attached listeners on the page - * - * @api private - * @param {Object} experimentState: contains all information regarding experiments - * @param {Object} experimentState.experiment: the experiment running on the page - * @param {String} experimentState.experiment.name: name of the experiment - * @param {String} experimentState.experiment.id: ID of the experiment - * @param {String} experimentState.experiment.referrer: available if effective referrer if experiment is a redirect - * @param {Array} experimentState.variations: the variations the current user on page is seeing - * @param {String} experimentState.variations[].name: the name of the variation - * @param {String} experimentState.variations[].id: the ID of the variation - * @param {Object} experimentState.sections: the sections for the experiment (only defined for multivariate experiments) keyed by sectionId - * @param {String} experimentState.sections[sectionId].name: the name of section - * @param {Array} experimentState.sections[sectionId].variation_ids: the IDs of the variations in the section - * - */ - -Optimizely.prototype.sendClassicDataToSegment = function(experimentState) { - var experiment = experimentState.experiment; - var variations = experimentState.variations; - var sections = experimentState.sections; - var context = { integration: optimizelyContext }; // backward compatibility - - // Reformatting this data structure into hash map so concatenating variation ids and names is easier later - var variationsMap = foldl( - function(results, variation) { - var res = results; - res[variation.id] = variation.name; - return res; - }, - {}, - variations - ); - - // Sorting for consistency across browsers - var variationIds = keys(variationsMap).sort(); - var variationNames = values(variationsMap).sort(); - - // Send data via `.track()` - if (this.options.listen) { - var props = { - experimentId: experiment.id, - experimentName: experiment.name, - variationId: variationIds.join(), // eg. '123' or '123,455' - variationName: variationNames.join(', ') // eg. 'Variation X' or 'Variation 1, Variation 2' - }; - - // If this was a redirect experiment and the effective referrer is different from document.referrer, - // this value is made available. So if a customer came in via google.com/ad -> tb12.com -> redirect experiment -> Belichickgoat.com - // `experiment.referrer` would be google.com/ad here NOT `tb12.com`. - if (experiment.referrer) { - props.referrer = experiment.referrer; - context.page = { referrer: experiment.referrer }; - } - - // When there is a multivariate experiment - if (sections) { - // Since `sections` include all the possible sections on the page, we need to find the names of the sections - // if any of its variations were used. Experiments could display variations from multiple sections. - // The global optimizely data object does not expose a mapping between which section(s) were involved within an experiment. - // So we will build our own mapping to quickly get the section name(s) and id(s) for any displayed variation. - var activeSections = {}; - var variationIdsToSectionsMap = foldl( - function(results, section, sectionId) { - var res = results; - each(function(variationId) { - res[variationId] = { id: sectionId, name: section.name }; - }, section.variation_ids); - return res; - }, - {}, - sections - ); - for (var j = 0; j < variationIds.length; j++) { - var activeVariation = variationIds[j]; - var activeSection = variationIdsToSectionsMap[activeVariation]; - if (activeSection) - activeSections[activeSection.id] = activeSection.name; - } - - // Sorting for consistency across browsers - props.sectionId = keys(activeSections) - .sort() - .join(); // Not adding space for backward compat/consistency reasons since all IDs we've never had spaces - props.sectionName = values(activeSections) - .sort() - .join(', '); - } - - // For Google's nonInteraction flag - if (this.options.nonInteraction) props.nonInteraction = 1; - - // If customExperimentProperties is provided overide the props with it. - // If valid customExperimentProperties present it will override existing props. - var customExperimentProperties = this.options.customExperimentProperties; - var customPropsKeys = Object.keys(customExperimentProperties); - var data = window.optimizely && window.optimizely.data; - - if (data && customPropsKeys.length) { - for (var index = 0; index < customPropsKeys.length; index++) { - var segmentProp = customPropsKeys[index]; - var optimizelyProp = customExperimentProperties[segmentProp]; - if (typeof data[optimizelyProp] !== 'undefined') { - props[segmentProp] = data[optimizelyProp]; - } - } - } - - // Send to Segment - this.analytics.track('Experiment Viewed', props, context); - } - - // Send data via `.identify()` (not recommended!) - // TODO: deprecate this feature - if (this.options.variations) { - // Note: The only "breaking" behavior is that now there will be an `.identify()` call per active experiment - // Legacy behavior was that we would look up all active experiments on the page after init and send one `.identify()` call - // with all experiment/variation data as traits. - // New behavior will call `.identify()` per active experiment with isolated experiment/variation data for that single experiment - // However, since traits are cached, subsequent experiments that trigger `.identify()` calls will likely contain previous experiment data - var traits = {}; - traits['Experiment: ' + experiment.name] = variationNames.join(', '); // eg. 'Variation X' or 'Variation 1, Variation 2' - - // Send to Segment - this.analytics.identify(traits); - } -}; - -/** - * sendNewDataToSegment (Optimizely X) - * - * This function is called for each experiment created in New Optimizely that are running on the page. - * New Optimizely added a dimension called "Campaigns" that encapsulate over the Experiments. So a campaign can have multiple experiments. - * Multivariate experiments are no longer supported in New Optimizely. - * This function will also be executed for any experiments activated at a later stage since initOptimizelyIntegration - * attached listeners on the page - * - * @api private - * @param {Object} campaignState: contains all information regarding experiments and campaign - * @param {String} campaignState.id: the ID of the campaign - * @param {String} campaignState.campaignName: the name of the campaign - * @param {Array} campaignState.audiences: "Audiences" the visitor is considered part of related to this campaign - * @param {String} campaignState.audiences[].id: the id of the Audience - * @param {String} campaignState.audiences[].name: the name of the Audience - * @param {Object} campaignState.experiment: the experiment the visitor is seeing - * @param {String} campaignState.experiment.id: the id of the experiment - * @param {String} campaignState.experiment.name: the name of the experiment - * @param {String} campaignState.experiment.referrer: the effective referrer of the experiment (only defined for redirect) - * @param {Object} campaignState.variation: the variation the visitor is seeing - * @param {String} campaignState.variation.id: the id of the variation - * @param {String} campaignState.variation.name: the name of the variation - * @param {String} campaignState.isInCampaignHoldback: whether the visitor is in the Campaign holdback - */ - -Optimizely.prototype.sendNewDataToSegment = function(campaignState) { - var experiment = campaignState.experiment; - var variation = campaignState.variation; - var context = { integration: optimizelyContext }; // backward compatibility - - // Reformatting this data structure into hash map so concatenating variation ids and names is easier later - var audiencesMap = foldl( - function(results, audience) { - var res = results; - res[audience.id] = audience.name; - return res; - }, - {}, - campaignState.audiences - ); - - // Sorting for consistency across browsers - var audienceIds = keys(audiencesMap) - .sort() - .join(); // Not adding space for backward compat/consistency reasons since all IDs we've never had spaces - var audienceNames = values(audiencesMap) - .sort() - .join(', '); - - // Send data via `.track()` - if (this.options.listen) { - var props = { - campaignName: campaignState.campaignName, - campaignId: campaignState.id, - experimentId: experiment.id, - experimentName: experiment.name, - variationName: variation.name, - variationId: variation.id, - audienceId: audienceIds, // eg. '7527562222,7527111138' - audienceName: audienceNames, // eg. 'Peaky Blinders, Trust Tree' - isInCampaignHoldback: campaignState.isInCampaignHoldback - }; - - // If this was a redirect experiment and the effective referrer is different from document.referrer, - // this value is made available. So if a customer came in via google.com/ad -> tb12.com -> redirect experiment -> Belichickgoat.com - // `experiment.referrer` would be google.com/ad here NOT `tb12.com`. - if (experiment.referrer) { - props.referrer = experiment.referrer; - context.page = { referrer: experiment.referrer }; - } - - // For Google's nonInteraction flag - if (this.options.nonInteraction) props.nonInteraction = 1; - - // If customCampaignProperties is provided overide the props with it. - // If valid customCampaignProperties present it will override existing props. - var customCampaignProperties = this.options.customCampaignProperties; - var customPropsKeys = Object.keys(customCampaignProperties); - var data = window.optimizely && window.optimizely.newMockData; - if (data && customPropsKeys.length) { - for (var index = 0; index < customPropsKeys.length; index++) { - var segmentProp = customPropsKeys[index]; - var optimizelyProp = customCampaignProperties[segmentProp]; - if (typeof data[optimizelyProp] !== 'undefined') { - props[segmentProp] = data[optimizelyProp]; - } - } - } - - // Send to Segment - this.analytics.track('Experiment Viewed', props, context); - } - - // Send data via `.identify()` (not recommended!) - // TODO: deprecate this feature - if (this.options.variations) { - // Legacy: We never sent any experiment Id or variation Id - // Note: The only "breaking" behavior is that now there will be an `.identify()` per active experiment - // Legacy behavior was that we would look up all active experiments on the page after init and send one `.identify()` call - // with all experiment/variation data as traits. - // New behavior will call `.identify()` per active experiment with isolated experiment/variation data for that single experiment - var traits = {}; - traits['Experiment: ' + experiment.name] = variation.name; - - // Send to Segment - this.analytics.identify(traits); - } -}; - -/** - * setEffectiveReferrer - * - * This function is called when a redirect experiment changed the effective referrer value where it is different from the `document.referrer`. - * This is a documented caveat for any mutual customers that are using redirect experiments. - * We will set this global variable that Segment customers can lookup and pass down in their initial `.page()` call inside - * their Segment snippet. - * - * @apr private - * @param {string} referrer - */ - -Optimizely.prototype.setEffectiveReferrer = function(referrer) { - if (referrer) { - window.optimizelyEffectiveReferrer = referrer; - return referrer; - } -}; - -/** - * initOptimizelyIntegration(handlers) - * - * This function was provided by Optimizely's Engineering team. The function below once initialized can detect which version of - * Optimizely a customer is using and call the appropriate callback functions when an experiment runs on the page. - * Instead of Segment looking up the experiment data, we can now just bind Segment APIs to their experiment listener/handlers! - * - * @api private - * @param {Object} handlers - * @param {Function} referrerOverride: called if the effective refferer value differs from the current `document.referrer` due to a - * invocation of a redirect experiment on the page - * @param {Function} sendExperimentData: called for every running experiment on the page (Classic) - * @param {Function} sendCampaignData: called for every running campaign on the page (New) - */ - -Optimizely.initOptimizelyIntegration = function(handlers) { - /** - * `initClassicOptimizelyIntegration` fetches all the experiment data from the classic Optimizely client - * and calls the functions provided in the arguments with the data that needs to - * be used for sending information. It is recommended to leave this function as is - * and to create your own implementation of the functions referrerOverride and - * sendExperimentData. - * - * @param {Function} referrerOverride - This function is called if the effective referrer value differs from - * the current document.referrer value. The only argument provided is the effective referrer value. - * @param {Function} sendExperimentData - This function is called for every running experiment on the page. - * The function is called with all the relevant ids and names. - */ - var initClassicOptimizelyIntegration = function( - referrerOverride, - sendExperimentData - ) { - var data = window.optimizely && window.optimizely.data; - var state = data && data.state; - if (state) { - var activeExperiments = state.activeExperiments; - if (state.redirectExperiment) { - var redirectExperimentId = state.redirectExperiment.experimentId; - var index = -1; - for (var i = 0; i < state.activeExperiments.length; i++) { - if (state.activeExperiments[i] === redirectExperimentId) { - index = i; - break; - } - } - if (index === -1) { - activeExperiments.push(redirectExperimentId); - } - referrerOverride(state.redirectExperiment.referrer); - } - - for (var k = 0; k < activeExperiments.length; k++) { - var currentExperimentId = activeExperiments[k]; - var activeExperimentState = { - experiment: { - id: currentExperimentId, - name: data.experiments[currentExperimentId].name - }, - variations: [], - /** Segment added code */ - // we need to send sectionName for multivariate experiments - sections: data.sections - /**/ - }; - - /** Segment added code */ - // for backward compatability since we send referrer with the experiment properties - if ( - state.redirectExperiment && - currentExperimentId === state.redirectExperiment.experimentId && - state.redirectExperiment.referrer - ) { - activeExperimentState.experiment.referrer = - state.redirectExperiment.referrer; - } - /**/ - - var variationIds = - state.variationIdsMap[activeExperimentState.experiment.id]; - for (var j = 0; j < variationIds.length; j++) { - var id = variationIds[j]; - var name = data.variations[id].name; - activeExperimentState.variations.push({ - id: id, - name: name - }); - } - sendExperimentData(activeExperimentState); - } - } - }; - - /** - * This function fetches all the campaign data from the new Optimizely client - * and calls the functions provided in the arguments with the data that needs to - * be used for sending information. It is recommended to leave this function as is - * and to create your own implementation of the functions referrerOverride and - * sendCampaignData. - * - * @param {Function} referrerOverride - This function is called if the effective referrer value differs from - * the current document.referrer value. The only argument provided is the effective referrer value. - * @param {Function} sendCampaignData - This function is called for every running campaign on the page. - * The function is called with the campaignState for the activated campaign - */ - var initNewOptimizelyIntegration = function( - referrerOverride, - sendCampaignData - ) { - var newActiveCampaign = function(id, referrer) { - var state = window.optimizely.get && window.optimizely.get('state'); - if (state) { - var activeCampaigns = state.getCampaignStates({ - isActive: true - }); - var campaignState = activeCampaigns[id]; - // Segment added code: in case this is a redirect experiment - if (referrer) campaignState.experiment.referrer = referrer; - sendCampaignData(campaignState); - } - }; - - var checkReferrer = function() { - var state = window.optimizely.get && window.optimizely.get('state'); - if (state) { - var referrer = - state.getRedirectInfo() && state.getRedirectInfo().referrer; - - if (referrer) { - referrerOverride(referrer); - return referrer; // Segment added code: so I can pass this referrer value in cb - } - } - }; - - /** - * At any moment, a new campaign can be activated (manual or conditional activation). - * This function registers a listener that listens to newly activated campaigns and - * handles them. - */ - var registerFutureActiveCampaigns = function() { - window.optimizely = window.optimizely || []; - window.optimizely.push({ - type: 'addListener', - filter: { - type: 'lifecycle', - name: 'campaignDecided' - }, - handler: function(event) { - var id = event.data.campaign.id; - newActiveCampaign(id); - } - }); - }; - - /** - * If this code is running after Optimizely on the page, there might already be - * some campaigns active. This function makes sure all those campaigns are - * handled. - */ - var registerCurrentlyActiveCampaigns = function() { - window.optimizely = window.optimizely || []; - var state = window.optimizely.get && window.optimizely.get('state'); - if (state) { - var referrer = checkReferrer(); - var activeCampaigns = state.getCampaignStates({ - isActive: true - }); - for (var id in activeCampaigns) { - if ({}.hasOwnProperty.call(activeCampaigns, id)) { - // Segment modified code: need to pass down referrer in the cb for backward compat reasons - if (referrer) { - newActiveCampaign(id, referrer); - } else { - newActiveCampaign(id); - } - } - } - } else { - window.optimizely.push({ - type: 'addListener', - filter: { - type: 'lifecycle', - name: 'initialized' - }, - handler: function() { - checkReferrer(); - } - }); - } - }; - registerCurrentlyActiveCampaigns(); - registerFutureActiveCampaigns(); - }; - - initClassicOptimizelyIntegration( - handlers.referrerOverride, - handlers.sendExperimentData - ); - initNewOptimizelyIntegration( - handlers.referrerOverride, - handlers.sendCampaignData - ); -}; +// 'use strict'; + +// /** +// * Module dependencies. +// */ + +// var keys = require('@ndhoule/keys'); +// var values = require('@ndhoule/values'); +// var foldl = require('@ndhoule/foldl'); +// var each = require('@ndhoule/each'); +// var integration = require('@segment/analytics.js-integration'); +// var tick = require('next-tick'); +// var push = require('global-queue')('optimizely', { wrap: false }); +// var pushEdge = require('global-queue')('optimizelyEdge', { wrap: false }); + +// /** +// * Expose `Optimizely` integration. +// */ + +// var Optimizely = (module.exports = integration('Optimizely') +// .option('trackCategorizedPages', true) +// .option('trackNamedPages', true) +// .option('variations', false) // send data via `.identify()` +// .option('listen', true) // send data via `.track()` +// .option('nonInteraction', false) +// .option('sendRevenueOnlyForOrderCompleted', true) +// .option('customExperimentProperties', {}) +// .option('customCampaignProperties', {})); + +// /** +// * The name and version for this integration. +// */ + +// var optimizelyContext = { +// name: 'optimizely', +// version: '2.0.0' +// }; + +// /** +// * Initialize. +// * +// * https://www.optimizely.com/docs/api#function-calls +// * https://jsfiddle.net/ushmw723/ <- includes optimizely snippets for capturing campaign and experiment data +// * +// * @api public +// */ + +// Optimizely.prototype.initialize = function() { +// var self = this; +// // Flag source of integration (requested by Optimizely) +// if (window.optimizelyEdge) { +// pushEdge({ +// type: 'integration', +// OAuthClientId: '5360906403' +// }); +// } else { +// push({ +// type: 'integration', +// OAuthClientId: '5360906403' +// }); +// } +// // Initialize listeners for both Classic and New Optimizely +// // crazying binding because that's just how javascript works +// // We're caling this on the next tick to be safe so we don't hold up +// // initializing the integration even though the function below is designed to be async, +// // just want to be extra safe +// tick(function() { +// Optimizely.initOptimizelyIntegration({ +// referrerOverride: self.setEffectiveReferrer.bind(self), +// sendExperimentData: self.sendClassicDataToSegment.bind(self), +// sendCampaignData: self.sendNewDataToSegment.bind(self), +// sendEdgeExperimentData: self.sendEdgeExperimentData.bind(self) +// }); +// }); + +// this.ready(); +// }; + +// /** +// * Track. The Optimizely X Web event API accepts a single payload object. +// * It works with Classic Optimizely as well. +// * +// * Optimizely X: https://developers.optimizely.com/x/solutions/javascript/reference/index.html#function_setevent +// * +// * The new-style X API is forward compatible from Optimizely Classic to Optimizely X. +// * - Classic will correctly consume the tags object to identify the revenue +// * - In bundled mode, it will be forwarded along to the X API with the entire payload +// * +// * If the Optimizely X Fullstack JavaScript SDK is being used we should pass along +// * the event to it. Any properties in the track object will be passed along as event tags. +// * If the userId is not passed into the options object of the track call, we'll +// * attempt to use the userId of the track event, which is set using the analytics.identify call. +// * +// * https://developers.optimizely.com/x/solutions/sdks/reference/?language=javascript#tracking +// * +// * @api public +// * @param {Track} track +// */ + +// Optimizely.prototype.track = function(track) { +// var opts = this.options; +// var eventProperties = track.properties(); + +// // Optimizely expects revenue only passed through Order Completed events +// if (eventProperties.revenue && opts.sendRevenueOnlyForOrderCompleted) { +// if (track.event() === 'Order Completed') { +// eventProperties.revenue = Math.round(eventProperties.revenue * 100); +// } else if (track.event() !== 'Order Completed') { +// delete eventProperties.revenue; +// } +// // This is legacy Segment-Optimizely behavior, +// // which passes revenue whenever it is present +// } else if ( +// opts.sendRevenueOnlyForOrderCompleted === false && +// eventProperties.revenue +// ) { +// eventProperties.revenue = Math.round(eventProperties.revenue * 100); +// } + +// // Use the new-style API (which is compatible with Classic and X) +// var eventName = track.event().replace(/:/g, '_'); // can't have colons so replacing with underscores +// var payload = { +// type: 'event', +// eventName: eventName, +// tags: eventProperties +// }; + +// if (window.optimizelyEdge) { +// pushEdge(payload); +// } else { +// push(payload); +// } + +// var optimizelyClientInstance = window.optimizelyClientInstance; +// if (optimizelyClientInstance && optimizelyClientInstance.track) { +// var optimizelyOptions = track.options('Optimizely'); +// var userId = +// optimizelyOptions.userId || track.userId() || this.analytics.user().id(); +// var attributes = +// optimizelyOptions.attributes || +// track.traits() || +// this.analytics.user().traits(); +// if (userId) { +// optimizelyClientInstance.track( +// eventName, +// userId, +// attributes, +// payload.tags +// ); +// } +// } +// }; + +// /** +// * Page. +// * +// * https://www.optimizely.com/docs/api#track-event +// * +// * @api public +// * @param {Page} page +// */ + +// Optimizely.prototype.page = function(page) { +// var category = page.category(); +// var name = page.fullName(); +// var opts = this.options; + +// // categorized pages +// if (category && opts.trackCategorizedPages) { +// this.track(page.track(category)); +// } + +// // named pages +// if (name && opts.trackNamedPages) { +// this.track(page.track(name)); +// } +// }; + +// /** +// * sendClassicDataToSegment (Optimizely Classic) +// * +// * This function is executed for each experiment created in Classic Optimizely that is running on the page. +// * This function will also be executed for any experiments activated at a later stage since initOptimizelyIntegration +// * attached listeners on the page +// * +// * @api private +// * @param {Object} experimentState: contains all information regarding experiments +// * @param {Object} experimentState.experiment: the experiment running on the page +// * @param {String} experimentState.experiment.name: name of the experiment +// * @param {String} experimentState.experiment.id: ID of the experiment +// * @param {String} experimentState.experiment.referrer: available if effective referrer if experiment is a redirect +// * @param {Array} experimentState.variations: the variations the current user on page is seeing +// * @param {String} experimentState.variations[].name: the name of the variation +// * @param {String} experimentState.variations[].id: the ID of the variation +// * @param {Object} experimentState.sections: the sections for the experiment (only defined for multivariate experiments) keyed by sectionId +// * @param {String} experimentState.sections[sectionId].name: the name of section +// * @param {Array} experimentState.sections[sectionId].variation_ids: the IDs of the variations in the section +// * +// */ + +// Optimizely.prototype.sendClassicDataToSegment = function(experimentState) { +// var experiment = experimentState.experiment; +// var variations = experimentState.variations; +// var sections = experimentState.sections; +// var context = { integration: optimizelyContext }; // backward compatibility + +// // Reformatting this data structure into hash map so concatenating variation ids and names is easier later +// var variationsMap = foldl( +// function(results, variation) { +// var res = results; +// res[variation.id] = variation.name; +// return res; +// }, +// {}, +// variations +// ); + +// // Sorting for consistency across browsers +// var variationIds = keys(variationsMap).sort(); +// var variationNames = values(variationsMap).sort(); + +// // Send data via `.track()` +// if (this.options.listen) { +// var props = { +// experimentId: experiment.id, +// experimentName: experiment.name, +// variationId: variationIds.join(), // eg. '123' or '123,455' +// variationName: variationNames.join(', ') // eg. 'Variation X' or 'Variation 1, Variation 2' +// }; + +// // If this was a redirect experiment and the effective referrer is different from document.referrer, +// // this value is made available. So if a customer came in via google.com/ad -> tb12.com -> redirect experiment -> Belichickgoat.com +// // `experiment.referrer` would be google.com/ad here NOT `tb12.com`. +// if (experiment.referrer) { +// props.referrer = experiment.referrer; +// context.page = { referrer: experiment.referrer }; +// } + +// // When there is a multivariate experiment +// if (sections) { +// // Since `sections` include all the possible sections on the page, we need to find the names of the sections +// // if any of its variations were used. Experiments could display variations from multiple sections. +// // The global optimizely data object does not expose a mapping between which section(s) were involved within an experiment. +// // So we will build our own mapping to quickly get the section name(s) and id(s) for any displayed variation. +// var activeSections = {}; +// var variationIdsToSectionsMap = foldl( +// function(results, section, sectionId) { +// var res = results; +// each(function(variationId) { +// res[variationId] = { id: sectionId, name: section.name }; +// }, section.variation_ids); +// return res; +// }, +// {}, +// sections +// ); +// for (var j = 0; j < variationIds.length; j++) { +// var activeVariation = variationIds[j]; +// var activeSection = variationIdsToSectionsMap[activeVariation]; +// if (activeSection) +// activeSections[activeSection.id] = activeSection.name; +// } + +// // Sorting for consistency across browsers +// props.sectionId = keys(activeSections) +// .sort() +// .join(); // Not adding space for backward compat/consistency reasons since all IDs we've never had spaces +// props.sectionName = values(activeSections) +// .sort() +// .join(', '); +// } + +// // For Google's nonInteraction flag +// if (this.options.nonInteraction) props.nonInteraction = 1; + +// // If customExperimentProperties is provided overide the props with it. +// // If valid customExperimentProperties present it will override existing props. +// var customExperimentProperties = this.options.customExperimentProperties; +// var customPropsKeys = Object.keys(customExperimentProperties); +// var data = window.optimizely && window.optimizely.data; + +// if (data && customPropsKeys.length) { +// for (var index = 0; index < customPropsKeys.length; index++) { +// var segmentProp = customPropsKeys[index]; +// var optimizelyProp = customExperimentProperties[segmentProp]; +// if (typeof data[optimizelyProp] !== 'undefined') { +// props[segmentProp] = data[optimizelyProp]; +// } +// } +// } + +// // Send to Segment +// this.analytics.track('Experiment Viewed', props, context); +// } + +// // Send data via `.identify()` (not recommended!) +// // TODO: deprecate this feature +// if (this.options.variations) { +// // Note: The only "breaking" behavior is that now there will be an `.identify()` call per active experiment +// // Legacy behavior was that we would look up all active experiments on the page after init and send one `.identify()` call +// // with all experiment/variation data as traits. +// // New behavior will call `.identify()` per active experiment with isolated experiment/variation data for that single experiment +// // However, since traits are cached, subsequent experiments that trigger `.identify()` calls will likely contain previous experiment data +// var traits = {}; +// traits['Experiment: ' + experiment.name] = variationNames.join(', '); // eg. 'Variation X' or 'Variation 1, Variation 2' + +// // Send to Segment +// this.analytics.identify(traits); +// } +// }; + +// /** +// * sendNewDataToSegment (Optimizely X) +// * +// * This function is called for each experiment created in New Optimizely that are running on the page. +// * New Optimizely added a dimension called "Campaigns" that encapsulate over the Experiments. So a campaign can have multiple experiments. +// * Multivariate experiments are no longer supported in New Optimizely. +// * This function will also be executed for any experiments activated at a later stage since initOptimizelyIntegration +// * attached listeners on the page +// * +// * @api private +// * @param {Object} campaignState: contains all information regarding experiments and campaign +// * @param {String} campaignState.id: the ID of the campaign +// * @param {String} campaignState.campaignName: the name of the campaign +// * @param {Array} campaignState.audiences: "Audiences" the visitor is considered part of related to this campaign +// * @param {String} campaignState.audiences[].id: the id of the Audience +// * @param {String} campaignState.audiences[].name: the name of the Audience +// * @param {Object} campaignState.experiment: the experiment the visitor is seeing +// * @param {String} campaignState.experiment.id: the id of the experiment +// * @param {String} campaignState.experiment.name: the name of the experiment +// * @param {String} campaignState.experiment.referrer: the effective referrer of the experiment (only defined for redirect) +// * @param {Object} campaignState.variation: the variation the visitor is seeing +// * @param {String} campaignState.variation.id: the id of the variation +// * @param {String} campaignState.variation.name: the name of the variation +// * @param {String} campaignState.isInCampaignHoldback: whether the visitor is in the Campaign holdback +// */ + +// Optimizely.prototype.sendNewDataToSegment = function(campaignState) { +// var experiment = campaignState.experiment; +// var variation = campaignState.variation; +// var context = { integration: optimizelyContext }; // backward compatibility + +// // Reformatting this data structure into hash map so concatenating variation ids and names is easier later +// var audiencesMap = foldl( +// function(results, audience) { +// var res = results; +// res[audience.id] = audience.name; +// return res; +// }, +// {}, +// campaignState.audiences +// ); + +// // Sorting for consistency across browsers +// var audienceIds = keys(audiencesMap) +// .sort() +// .join(); // Not adding space for backward compat/consistency reasons since all IDs we've never had spaces +// var audienceNames = values(audiencesMap) +// .sort() +// .join(', '); + +// // Send data via `.track()` +// if (this.options.listen) { +// var props = { +// campaignName: campaignState.campaignName, +// campaignId: campaignState.id, +// experimentId: experiment.id, +// experimentName: experiment.name, +// variationName: variation.name, +// variationId: variation.id, +// audienceId: audienceIds, // eg. '7527562222,7527111138' +// audienceName: audienceNames, // eg. 'Peaky Blinders, Trust Tree' +// isInCampaignHoldback: campaignState.isInCampaignHoldback +// }; + +// // If this was a redirect experiment and the effective referrer is different from document.referrer, +// // this value is made available. So if a customer came in via google.com/ad -> tb12.com -> redirect experiment -> Belichickgoat.com +// // `experiment.referrer` would be google.com/ad here NOT `tb12.com`. +// if (experiment.referrer) { +// props.referrer = experiment.referrer; +// context.page = { referrer: experiment.referrer }; +// } + +// // For Google's nonInteraction flag +// if (this.options.nonInteraction) props.nonInteraction = 1; + +// // Send to Segment +// this.analytics.track('Experiment Viewed', props, context); +// } + +// // Send data via `.identify()` (not recommended!) +// // TODO: deprecate this feature +// if (this.options.variations) { +// // Legacy: We never sent any experiment Id or variation Id +// // Note: The only "breaking" behavior is that now there will be an `.identify()` per active experiment +// // Legacy behavior was that we would look up all active experiments on the page after init and send one `.identify()` call +// // with all experiment/variation data as traits. +// // New behavior will call `.identify()` per active experiment with isolated experiment/variation data for that single experiment +// var traits = {}; +// traits['Experiment: ' + experiment.name] = variation.name; + +// // Send to Segment +// this.analytics.identify(traits); +// } +// }; + +// Optimizely.prototype.sendEdgeExperimentData = function(experimentState) { +// var variation = experimentState.variation; +// var context = { integration: optimizelyContext }; // backward compatibility + +// // Send data via `.track()` +// if (this.options.listen) { +// var props = { +// experimentId: experimentState.id, +// experimentName: experimentState.name, +// variationName: variation.name, +// variationId: variation.id +// }; + +// // For Google's nonInteraction flag +// if (this.options.nonInteraction) props.nonInteraction = 1; + +// // Send to Segment +// this.analytics.track('Experiment Viewed', props, context); +// } +// }; + +// /** +// * setEffectiveReferrer +// * +// * This function is called when a redirect experiment changed the effective referrer value where it is different from the `document.referrer`. +// * This is a documented caveat for any mutual customers that are using redirect experiments. +// * We will set this global variable that Segment customers can lookup and pass down in their initial `.page()` call inside +// * their Segment snippet. +// * +// * @apr private +// * @param {string} referrer +// */ + +// Optimizely.prototype.setEffectiveReferrer = function(referrer) { +// if (referrer) { +// window.optimizelyEffectiveReferrer = referrer; +// return referrer; +// } +// }; + +// /** +// * initOptimizelyIntegration(handlers) +// * +// * This function was provided by Optimizely's Engineering team. The function below once initialized can detect which version of +// * Optimizely a customer is using and call the appropriate callback functions when an experiment runs on the page. +// * Instead of Segment looking up the experiment data, we can now just bind Segment APIs to their experiment listener/handlers! +// * +// * @api private +// * @param {Object} handlers +// * @param {Function} referrerOverride: called if the effective refferer value differs from the current `document.referrer` due to a +// * invocation of a redirect experiment on the page +// * @param {Function} sendExperimentData: called for every running experiment on the page (Classic) +// * @param {Function} sendCampaignData: called for every running campaign on the page (New) +// */ + +// Optimizely.initOptimizelyIntegration = function(handlers) { +// /** +// * `initClassicOptimizelyIntegration` fetches all the experiment data from the classic Optimizely client +// * and calls the functions provided in the arguments with the data that needs to +// * be used for sending information. It is recommended to leave this function as is +// * and to create your own implementation of the functions referrerOverride and +// * sendExperimentData. +// * +// * @param {Function} referrerOverride - This function is called if the effective referrer value differs from +// * the current document.referrer value. The only argument provided is the effective referrer value. +// * @param {Function} sendExperimentData - This function is called for every running experiment on the page. +// * The function is called with all the relevant ids and names. +// */ +// var initClassicOptimizelyIntegration = function( +// referrerOverride, +// sendExperimentData +// ) { +// var data = window.optimizely && window.optimizely.data; +// var state = data && data.state; +// if (state) { +// var activeExperiments = state.activeExperiments; +// if (state.redirectExperiment) { +// var redirectExperimentId = state.redirectExperiment.experimentId; +// var index = -1; +// for (var i = 0; i < state.activeExperiments.length; i++) { +// if (state.activeExperiments[i] === redirectExperimentId) { +// index = i; +// break; +// } +// } +// if (index === -1) { +// activeExperiments.push(redirectExperimentId); +// } +// referrerOverride(state.redirectExperiment.referrer); +// } + +// for (var k = 0; k < activeExperiments.length; k++) { +// var currentExperimentId = activeExperiments[k]; +// var activeExperimentState = { +// experiment: { +// id: currentExperimentId, +// name: data.experiments[currentExperimentId].name +// }, +// variations: [], +// /** Segment added code */ +// // we need to send sectionName for multivariate experiments +// sections: data.sections +// /**/ +// }; + +// /** Segment added code */ +// // for backward compatability since we send referrer with the experiment properties +// if ( +// state.redirectExperiment && +// currentExperimentId === state.redirectExperiment.experimentId && +// state.redirectExperiment.referrer +// ) { +// activeExperimentState.experiment.referrer = +// state.redirectExperiment.referrer; +// } +// /**/ + +// var variationIds = +// state.variationIdsMap[activeExperimentState.experiment.id]; +// for (var j = 0; j < variationIds.length; j++) { +// var id = variationIds[j]; +// var name = data.variations[id].name; +// activeExperimentState.variations.push({ +// id: id, +// name: name +// }); +// } +// sendExperimentData(activeExperimentState); +// } +// } +// }; + +// /** +// * This function fetches all the campaign data from the new Optimizely client +// * and calls the functions provided in the arguments with the data that needs to +// * be used for sending information. It is recommended to leave this function as is +// * and to create your own implementation of the functions referrerOverride and +// * sendCampaignData. +// * +// * @param {Function} referrerOverride - This function is called if the effective referrer value differs from +// * the current document.referrer value. The only argument provided is the effective referrer value. +// * @param {Function} sendCampaignData - This function is called for every running campaign on the page. +// * The function is called with the campaignState for the activated campaign +// */ +// var initNewOptimizelyIntegration = function( +// referrerOverride, +// sendCampaignData +// ) { +// var newActiveCampaign = function(id, referrer) { +// var state = window.optimizely.get && window.optimizely.get('state'); +// if (state) { +// var activeCampaigns = state.getCampaignStates({ +// isActive: true +// }); +// var campaignState = activeCampaigns[id]; +// // Segment added code: in case this is a redirect experiment +// if (referrer) campaignState.experiment.referrer = referrer; +// sendCampaignData(campaignState); +// } +// }; + +// var checkReferrer = function() { +// var state = window.optimizely.get && window.optimizely.get('state'); +// if (state) { +// var referrer = +// state.getRedirectInfo() && state.getRedirectInfo().referrer; + +// if (referrer) { +// referrerOverride(referrer); +// return referrer; // Segment added code: so I can pass this referrer value in cb +// } +// } +// }; + +// /** +// * At any moment, a new campaign can be activated (manual or conditional activation). +// * This function registers a listener that listens to newly activated campaigns and +// * handles them. +// */ +// var registerFutureActiveCampaigns = function() { +// window.optimizely = window.optimizely || []; +// window.optimizely.push({ +// type: 'addListener', +// filter: { +// type: 'lifecycle', +// name: 'campaignDecided' +// }, +// handler: function(event) { +// var id = event.data.campaign.id; +// newActiveCampaign(id); +// } +// }); +// }; + +// /** +// * If this code is running after Optimizely on the page, there might already be +// * some campaigns active. This function makes sure all those campaigns are +// * handled. +// */ +// var registerCurrentlyActiveCampaigns = function() { +// window.optimizely = window.optimizely || []; +// var state = window.optimizely.get && window.optimizely.get('state'); + +// window.optimizelyEdge = window.optimizelyEdge || []; +// var edgeState = window.optimizelyEdge.state; + +// if (edgeState) { +// // TODO: checkReferrer() +// var activeCampaigns = edgeState.getActiveExperiments(); +// /* Example output: +// { '3': { +// id: '3', +// name: 'experimentName', +// variation: { +// id: '4', +// name: 'variationName +// } +// }} + +// * */ +// for (var id in activeCampaigns) { +// if ({}.hasOwnProperty.call(activeCampaigns, id)) { +// edgeActiveExperiment(id); +// } +// } +// } else if (state) { +// var referrer = checkReferrer(); +// var activeCampaigns = state.getCampaignStates({ +// isActive: true +// }); +// for (var id in activeCampaigns) { +// if ({}.hasOwnProperty.call(activeCampaigns, id)) { +// newActiveCampaign(id, referrer); +// } +// } +// } else { +// window.optimizely.push({ +// type: 'addListener', +// filter: { +// type: 'lifecycle', +// name: 'initialized' +// }, +// handler: function() { +// checkReferrer(); +// } +// }); +// } +// }; +// registerCurrentlyActiveCampaigns(); +// registerFutureActiveCampaigns(); +// }; + +// var initOptimizelyEdgeIntegration = function(sendEdgeExperimentData) { +// var edgeActiveExperiment = function(id) { +// var state = +// window.optimizelyEdge && +// window.optimizelyEdge.get && +// window.optimizelyEdge.get('state'); +// if (state) { +// var allActiveExperiments = state.getActiveExperiments(); +// var experimentState = allActiveExperiments[id]; + +// // TODO: referrer +// sendEdgeExperimentData(experimentState); +// } +// }; + +// /** +// * At any moment, a new Edge experiment can be activated (manual or conditional activation). +// * This function registers a listener that listens to newly activated Edge experiment and +// * handles them. +// */ +// var registerFutureActiveEdgeExperiment = function() { +// window.optimizely = window.optimizely || []; +// window.optimizely.push({ +// type: 'addListener', +// filter: { +// type: 'lifecycle', +// name: 'campaignDecided' +// }, +// handler: function(event) { +// var experimentId = event.data.decision.experimentId; +// if (experimentId && event.data.decision.variationId) { +// edgeActiveExperiment(experimentId); +// } +// } +// }); +// }; + +// /** +// * If this code is running after Optimizely on the page, there might already be +// * some experiments active. This function makes sure all those experiments are +// * handled. +// */ +// var registerCurrentlyActiveEdgeExperiment = function() { +// window.optimizelyEdge = window.optimizelyEdge || []; +// var edgeState = +// window.optimizelyEdge.get && window.optimizelyEdge.get('state'); +// if (edgeState) { +// // TODO: checkReferrer() +// var activeExperiments = edgeState.getActiveExperiments(); +// for (var id in activeExperiments) { +// if ({}.hasOwnProperty.call(activeExperiments, id)) { +// edgeActiveExperiment(id); +// } +// } +// } else { +// window.optimizely.push({ +// type: 'addListener', +// filter: { +// type: 'lifecycle', +// name: 'initialized' +// }, +// handler: function() { +// checkReferrer(); +// } +// }); +// } +// }; + +// registerFutureActiveEdgeExperiment(); +// registerCurrentlyActiveEdgeExperiment(); +// }; + +// initClassicOptimizelyIntegration( +// handlers.referrerOverride, +// handlers.sendExperimentData +// ); +// if (window.optimizelyEdge) { +// initOptimizelyEdgeIntegration(handler.sendEdgeExperimentData); +// } else { +// initNewOptimizelyIntegration( +// handlers.referrerOverride, +// handlers.sendCampaignData +// ); +// } +// }; diff --git a/integrations/optimizely/package.json b/integrations/optimizely/package.json index 834ab155b..b440a1e18 100644 --- a/integrations/optimizely/package.json +++ b/integrations/optimizely/package.json @@ -46,7 +46,6 @@ "karma-sauce-launcher": "^2.0.2", "karma-spec-reporter": "^0.0.32", "karma-summary-reporter": "^1.6.0", - "lerna": "^3.15.0", "mocha": "^6.1.4", "watchify": "^3.11.1" } diff --git a/integrations/optimizely/test/index.test.js b/integrations/optimizely/test/index.test.js index 59a327e04..43a1562c6 100644 --- a/integrations/optimizely/test/index.test.js +++ b/integrations/optimizely/test/index.test.js @@ -1,1298 +1,1382 @@ -'use strict'; - -var Analytics = require('@segment/analytics.js-core').constructor; -var sandbox = require('@segment/clear-env'); -var tester = require('@segment/analytics.js-integration-tester'); -var Optimizely = require('../lib/'); -var tick = require('next-tick'); - -/** - * Test account: han@segment.com - * - * Docs for Optimizely data object: https://developers.optimizely.com/javascript/personalization/index.html#reading-data-and-state - */ - -var mockOptimizelyClassicDataObject = function() { - // Classic - window.optimizely.data = { - experiments: { - 0: { name: 'Test' }, - 1: { name: 'MultiVariate Test' }, - 2: { name: 'Inactive Test' }, - 11: { name: 'Redirect Test' } - }, - variations: { - 22: { name: 'Redirect Variation', code: '' }, - 123: { name: 'Variation #123', code: '' }, - 789: { name: 'Var 789', code: '' }, - 44: { name: 'Var 44', code: '' } - }, - sections: undefined, // we'll set this during multivariate test since that's when this is set by Optimizely's API - state: { - activeExperiments: ['0', '11'], - variationNamesMap: { - 0: 'Variation #123', - 1: 'Variation #123, Redirect Variation, Var 789', // this is the data format - 2: 'Inactive Variation', - 11: 'Redirect Variation' - }, - variationIdsMap: { - 0: ['123'], - 1: ['123', '22', '789'], - 11: ['22'], - 2: ['44'] - }, - redirectExperiment: { - variationId: '22', - experimentId: '11', - referrer: 'google.com' - } - } - }; -}; - -// Optimizely X -var mockOptimizelyXDataObject = function() { - // remove Classic data object - delete window.optimizely.data; - - window.optimizely.newMockData = { - 2347102720: { - audiences: [ - { - name: 'Middle Class', - id: '7100568438' - } - ], - campaignName: 'Get Rich or Die Tryin', - id: '2347102720', - experiment: { - id: '7522212694', - name: 'Wells Fargo Scam' - }, - variation: { - id: '7551111120', - name: 'Variation Corruption #1884' - }, - isInCampaignHoldback: false, - // these are returned by real Optimizely API but will not be send to integrations - isActive: false, - reason: undefined, - visitorRedirected: true - }, - 7547101713: { - audiences: [ - { - name: 'Trust Tree', - id: '7527565438' - } - ], - campaignName: 'URF', - id: '7547101713', - experiment: { - id: '7547682694', - name: 'Worlds Group Stage' - }, - variation: { - id: '7557950020', - name: 'Variation #1' - }, - isInCampaignHoldback: true, - // these are returned by real Optimizely API but will not be send to integrations - isActive: true, - reason: undefined, - visitorRedirected: false - }, - 2542102702: { - audiences: [ - { - name: 'Penthouse 6', - id: '8888222438' - }, - { - name: 'Fam Yolo', - id: '1234567890' - } - ], - campaignName: 'Coding Bootcamp', // Experiments created in Optimizely X will set this the same as experiment name - id: '7222777766', // but this will be different than experiment id - experiment: { - id: '1111182111', - name: 'Coding Bootcamp' - }, - variation: { - id: '7333333333', - name: 'Variation DBC' - }, - isInCampaignHoldback: false, - // these are returned by real Optimizely API but will not be send to integrations - isActive: true, - reason: undefined, - visitorRedirected: false - } - }; - // Optimizely init snippet uses new API methods below to access data rather than the global optimizely.data object - window.optimizely.get = function() { - return { - getCampaignStates: function(options) { - if (!('isActive' in options)) return window.optimizely.newMockData; - // returns all campaigns with option to return just active ones (which is what we do in the snippet) - var ret = {}; - for (var campaign in window.optimizely.newMockData) { - if ( - window.optimizely.newMockData[campaign].isActive === - options.isActive - ) { - ret[campaign] = window.optimizely.newMockData[campaign]; - } - } - return ret; - }, - getRedirectInfo: function() { - var campaigns = this.getCampaignStates({ isActive: true }); - for (var id in campaigns) { - if (campaigns[id].visitorRedirected) - return { referrer: 'barstools.com' }; - } - } - }; - }; -}; - -var mockBothOptimizelyDataObjects = function() { - mockOptimizelyXDataObject(); - mockOptimizelyClassicDataObject(); -}; - -// passed into context.integration (not context.integrations!) for all track calls for some reason -var optimizelyContext = { - name: 'optimizely', - version: '2.0.0' -}; - -describe('Optimizely', function() { - var analytics; - var optimizely; - var options = { - listen: false, - variations: false, - nonInteraction: false, - customExperimentProperties: {}, - customCampaignProperties: {} - }; - - beforeEach(function() { - analytics = new Analytics(); - optimizely = new Optimizely(options); - analytics.use(Optimizely); - analytics.use(tester); - analytics.add(optimizely); - window.optimizely = []; - }); - - afterEach(function() { - analytics.restore(); - analytics.reset(); - optimizely.reset(); - sandbox(); - }); - - describe('before loading', function() { - beforeEach(function() { - analytics.stub( - Optimizely, - 'initOptimizelyIntegration', - Optimizely.initOptimizelyIntegration - ); // Reference to constructor intentionally - analytics.stub(optimizely, 'load'); - analytics.stub(optimizely, 'sendClassicDataToSegment'); - analytics.stub(optimizely, 'sendNewDataToSegment'); - analytics.stub(optimizely, 'setEffectiveReferrer'); - }); - - describe('#initialize', function() { - beforeEach(function(done) { - analytics.stub(window.optimizely, 'push'); - analytics.once('ready', done); - analytics.initialize(); - analytics.page(); - }); - - it('should call initOptimizelyIntegration', function(done) { - executeAsyncTest(done, function() { - analytics.called(Optimizely.initOptimizelyIntegration); - }); - }); - - it('should flag source of integration', function() { - analytics.called(window.optimizely.push, { - type: 'integration', - OAuthClientId: '5360906403' - }); - }); - }); - - describe('#initOptimizelyIntegration', function() { - // Testing the behavior of the Optimizely provided private init function - // to ensure that proper callback functions were executed with expected params - // given each of the possible Optimizely snippet you could have on the page (Classic, X, Both) - describe('Classic', function() { - beforeEach(function(done) { - mockOptimizelyClassicDataObject(); - analytics.initialize(); - tick(done); - }); - - it('should call setEffectiveReferrer for redirect experiments', function() { - analytics.called(optimizely.setEffectiveReferrer, 'google.com'); - }); - - it('should call sendClassicDataToSegment for active Classic experiments', function() { - // we have two active experiments running in the mock data object - analytics.calledTwice(optimizely.sendClassicDataToSegment); - analytics.deepEqual(optimizely.sendClassicDataToSegment.args[0], [ - { - experiment: { - id: '0', - name: 'Test' - }, - variations: [ - { - id: '123', - name: 'Variation #123' - } - ], - sections: undefined - } - ]); - analytics.deepEqual(optimizely.sendClassicDataToSegment.args[1], [ - { - experiment: { - id: '11', - name: 'Redirect Test', - referrer: 'google.com' - }, - variations: [ - { - id: '22', - name: 'Redirect Variation' - } - ], - sections: undefined - } - ]); - }); - }); - - describe('New', function() { - beforeEach(function() { - mockOptimizelyXDataObject(); - }); - - it('should not call setEffectiveReferrer for non redirect experiments', function(done) { - // by default mock data has no redirect experiments active - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.didNotCall(optimizely.setEffectiveReferrer); - }); - }); - - it('should call setEffectiveReferrer for redirect experiments', function(done) { - // enable redirect experiment - window.optimizely.newMockData[2347102720].isActive = true; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.called(optimizely.setEffectiveReferrer, 'barstools.com'); - }); - }); - - it('should call sendNewDataToSegment for active Optimizely X campaigns', function(done) { - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.calledTwice(optimizely.sendNewDataToSegment); - analytics.deepEqual(optimizely.sendNewDataToSegment.args[0], [ - { - audiences: [ - { - name: 'Penthouse 6', - id: '8888222438' - }, - { - name: 'Fam Yolo', - id: '1234567890' - } - ], - campaignName: 'Coding Bootcamp', - id: '7222777766', - experiment: { - id: '1111182111', - name: 'Coding Bootcamp' - }, - variation: { - id: '7333333333', - name: 'Variation DBC' - }, - isActive: true, - isInCampaignHoldback: false, - reason: undefined, - visitorRedirected: false - } - ]); - analytics.deepEqual(optimizely.sendNewDataToSegment.args[1], [ - { - audiences: [ - { - name: 'Trust Tree', - id: '7527565438' - } - ], - campaignName: 'URF', - id: '7547101713', - experiment: { - id: '7547682694', - name: 'Worlds Group Stage' - }, - variation: { - id: '7557950020', - name: 'Variation #1' - }, - isActive: true, - isInCampaignHoldback: true, - reason: undefined, - visitorRedirected: false - } - ]); - }); - }); - }); - - describe('Both', function() { - beforeEach(function() { - mockBothOptimizelyDataObjects(); - analytics.initialize(); - }); - - // Note: we're not testing setEffectiveReferrer here since you can only have one version - // or the other, not both. And each one has been tested in the above unit tests - - it('should call both sendClassicDataToSegment and sendNewDataToSegment', function(done) { - // we have two active experiments running in the mock data object for both versions - executeAsyncTest(done, function() { - analytics.calledTwice(optimizely.sendClassicDataToSegment); - analytics.calledTwice(optimizely.sendNewDataToSegment); - analytics.deepEqual(optimizely.sendClassicDataToSegment.args[0], [ - { - experiment: { - id: '0', - name: 'Test' - }, - variations: [ - { - id: '123', - name: 'Variation #123' - } - ], - sections: undefined - } - ]); - analytics.deepEqual(optimizely.sendClassicDataToSegment.args[1], [ - { - experiment: { - id: '11', - name: 'Redirect Test', - referrer: 'google.com' - }, - variations: [ - { - id: '22', - name: 'Redirect Variation' - } - ], - sections: undefined - } - ]); - analytics.deepEqual(optimizely.sendNewDataToSegment.args[0], [ - { - audiences: [ - { - name: 'Penthouse 6', - id: '8888222438' - }, - { - name: 'Fam Yolo', - id: '1234567890' - } - ], - campaignName: 'Coding Bootcamp', - id: '7222777766', - experiment: { - id: '1111182111', - name: 'Coding Bootcamp' - }, - variation: { - id: '7333333333', - name: 'Variation DBC' - }, - isActive: true, - isInCampaignHoldback: false, - reason: undefined, - visitorRedirected: false - } - ]); - analytics.deepEqual(optimizely.sendNewDataToSegment.args[1], [ - { - audiences: [ - { - name: 'Trust Tree', - id: '7527565438' - } - ], - campaignName: 'URF', - id: '7547101713', - experiment: { - id: '7547682694', - name: 'Worlds Group Stage' - }, - variation: { - id: '7557950020', - name: 'Variation #1' - }, - isActive: true, - isInCampaignHoldback: true, - reason: undefined, - visitorRedirected: false - } - ]); - }); - }); - }); - }); - }); - - describe('#setEffectiveReferrer', function() { - describe('Classic', function() { - beforeEach(function(done) { - mockOptimizelyClassicDataObject(); - analytics.initialize(); - tick(done); - }); - - it('should set a global variable `window.optimizelyEffectiveReferrer`', function() { - analytics.equal(window.optimizelyEffectiveReferrer, 'google.com'); - }); - }); - - describe('New', function() { - beforeEach(function() { - mockOptimizelyXDataObject(); - // enable redirect experiment - window.optimizely.newMockData[2347102720].isActive = true; - analytics.initialize(); - }); - - it('should set a global variable `window.optimizelyEffectiveReferrer`', function(done) { - executeAsyncTest(done, function() { - analytics.equal(window.optimizelyEffectiveReferrer, 'barstools.com'); - }); - }); - }); - - // Again -- we're not testing for both since there is no point. - // You can't have this function execute twice each with different referrer value - // It will always either just call one or the other - }); - - describe('#sendClassicDataToSegment', function() { - beforeEach(function() { - mockOptimizelyClassicDataObject(); - }); - - describe('#options.variations', function() { - beforeEach(function(done) { - optimizely.options.variations = true; - analytics.stub(analytics, 'identify'); - analytics.initialize(); - tick(done); - }); - - it('should send each experiment via `.identify()`', function() { - // Since we have two experiments in `window.optimizely.data.state.activeExperiments` - // This test proves the breaking changes for the option (it used to send both experiment data in one - // `.identify()` call) - analytics.calledTwice(analytics.identify); - analytics.deepEqual(analytics.identify.args[0], [ - { - 'Experiment: Test': 'Variation #123' - } - ]); - analytics.deepEqual(analytics.identify.args[1], [ - { - 'Experiment: Redirect Test': 'Redirect Variation' - } - ]); - }); - }); - - describe('#options.sendRevenueOnlyForOrderCompleted', function() { - beforeEach(function() { - analytics.stub(window.optimizely, 'push'); - }); - - it('should not include revenue on a non Order Completed event if `onlySendRevenueOnOrderCompleted` is enabled', function() { - analytics.initialize(); - analytics.track('Order Updated', { - revenue: 25 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Updated', - tags: {} - }); - }); - - it('should send revenue only on Order Completed if `onlySendRevenueOnOrderCompleted` is enabled', function() { - analytics.initialize(); - analytics.track('Order Completed', { - revenue: 9.99 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Completed', - tags: { - revenue: 999 - } - }); - }); - - it('should send revenue on all events with properties.revenue if `onlySendRevenueOnOrderCompleted` is disabled', function() { - optimizely.options.sendRevenueOnlyForOrderCompleted = false; - analytics.initialize(); - analytics.track('Checkout Started', { - revenue: 9.99 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Checkout Started', - tags: { - revenue: 999 - } - }); - }); - }); - - describe('#options.listen', function() { - beforeEach(function() { - optimizely.options.listen = true; - analytics.stub(analytics, 'track'); - }); - - it('should send each standard active experiment data via `.track()`', function(done) { - // activate standard experiment - window.optimizely.data.state.activeExperiments = ['0']; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '0', - experimentName: 'Test', - variationId: '123', - variationName: 'Variation #123' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should map custom properties and send each standard active experiment data via `.track()`', function(done) { - optimizely.options.customExperimentProperties = { - experimentId: 'experiment_id', - experimentName: 'experiment_name', - variationId: 'variation_id', - variationName: 'variation_name' - }; - - window.optimizely.data.experiment_id = '124'; - window.optimizely.data.experiment_name = 'custom experiment name'; - window.optimizely.data.variation_id = '421'; - window.optimizely.data.variation_name = 'custom variation name'; - - window.optimizely.data.state.activeExperiments = ['0']; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '124', - experimentName: 'custom experiment name', - variationId: '421', - variationName: 'custom variation name' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should not map existing properties if custom properties not specified`', function(done) { - optimizely.options.customExperimentProperties = { - variationId: 'variation_id', - variationName: 'variation_name' - }; - - window.optimizely.data.experiment_id = '124'; - window.optimizely.data.experiment_name = 'custom experiment name'; - window.optimizely.data.variation_id = '421'; - window.optimizely.data.variation_name = 'custom variation name'; - - window.optimizely.data.state.activeExperiments = ['0']; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '0', - experimentName: 'Test', - variationId: '421', - variationName: 'custom variation name' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should send multivariate active experiment data via `.track()`', function(done) { - // activate multivariate experiment and set section info - window.optimizely.data.state.activeExperiments = ['0']; - window.optimizely.data.sections = { - 123409: { name: 'Section 1', variation_ids: ['123'] } - }; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '0', - experimentName: 'Test', - variationId: '123', - variationName: 'Variation #123', - sectionName: 'Section 1', - sectionId: '123409' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should dedupe sectionNames for multi section multivariate active experiment data via `.track()`', function(done) { - // activate multivariate experiment and set section info - window.optimizely.data.state.activeExperiments = ['1']; - window.optimizely.data.sections = { - 123409: { name: 'Section 1', variation_ids: ['123', '22', '789'] } - }; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '1', - experimentName: 'MultiVariate Test', - variationId: '123,22,789', - variationName: 'Redirect Variation, Var 789, Variation #123', - sectionName: 'Section 1', - sectionId: '123409' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should send multivariate active experiment with multiple section data via `.track()`', function(done) { - // activate multivariate experiment and set section info - window.optimizely.data.state.activeExperiments = ['1']; - window.optimizely.data.sections = { - 112309: { name: 'Section 1', variation_ids: ['123'] }, - 111111: { name: 'Section 2', variation_ids: ['22', '789'] } - }; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '1', - experimentName: 'MultiVariate Test', - variationId: '123,22,789', - variationName: 'Redirect Variation, Var 789, Variation #123', - sectionName: 'Section 1, Section 2', - sectionId: '111111,112309' - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should send redirect active experiment data via `.track()`', function(done) { - // activate redirect experiment - window.optimizely.data.state.activeExperiments = []; - var context = { - integration: optimizelyContext, - page: { referrer: 'google.com' } - }; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '11', - experimentName: 'Redirect Test', - referrer: 'google.com', - variationId: '22', - variationName: 'Redirect Variation' - }, - context - ]); - }); - }); - - it("should send Google's nonInteraction flag via `.track()`", function(done) { - // flip the nonInteraction option on and activate standard experiment - optimizely.options.nonInteraction = true; - window.optimizely.data.state.activeExperiments = ['0']; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - experimentId: '0', - experimentName: 'Test', - variationId: '123', - variationName: 'Variation #123', - nonInteraction: 1 - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should not send inactive experiments', function(done) { - // clear out the redirect experiment - window.optimizely.data.state.redirectExperiment = undefined; - // disable all active experiments - window.optimizely.data.state.activeExperiments = []; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.didNotCall(analytics.track); - }); - }); - }); - }); - - describe('#sendNewDataToSegment', function() { - beforeEach(function() { - mockOptimizelyXDataObject(); - }); - - describe('#options.variations', function() { - beforeEach(function(done) { - optimizely.options.variations = true; - analytics.stub(analytics, 'identify'); - analytics.initialize(); - tick(done); - }); - - it('should send active campaign via `.identify()`', function() { - // Since we have two experiments in `window.optimizely.data.state.activeExperiments` - // This test proves the breaking changes for the option (it used to send both experiment data in one - // `.identify()` call) - analytics.calledTwice(analytics.identify); - analytics.deepEqual(analytics.identify.args[0], [ - { - 'Experiment: Coding Bootcamp': 'Variation DBC' - } - ]); - analytics.deepEqual(analytics.identify.args[1], [ - { - 'Experiment: Worlds Group Stage': 'Variation #1' - } - ]); - }); - }); - - describe('#options.sendRevenueOnlyForOrderCompleted', function() { - beforeEach(function() { - analytics.stub(window.optimizely, 'push'); - }); - - it('should not include revenue on a non Order Completed event if `onlySendRevenueOnOrderCompleted` is enabled', function() { - analytics.initialize(); - analytics.track('Order Updated', { - revenue: 25 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Updated', - tags: {} - }); - }); - - it('should send revenue only on Order Completed if `onlySendRevenueOnOrderCompleted` is enabled', function() { - optimizely.options.sendRevenueOnlyForOrderCompleted = true; - analytics.initialize(); - analytics.track('Order Completed', { - revenue: 9.99 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Completed', - tags: { - revenue: 999 - } - }); - }); - - it('should send revenue on all events with properties.revenue if `onlySendRevenueOnOrderCompleted` is disabled', function() { - optimizely.options.sendRevenueOnlyForOrderCompleted = false; - analytics.initialize(); - analytics.track('Checkout Started', { - revenue: 9.99 - }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Checkout Started', - tags: { - revenue: 999 - } - }); - }); - }); - - describe('#options.listen', function() { - beforeEach(function() { - optimizely.options.listen = true; - analytics.stub(analytics, 'track'); - }); - - it('should send standard active campaign data via `.track()`', function(done) { - // Mock data by default has two active campaign/experiments. - // Going to leave just the one that was created as a standard - // experiment inside Optimizely X (not campaign) - window.optimizely.newMockData[7547101713].isActive = false; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'Coding Bootcamp', - campaignId: '7222777766', - experimentId: '1111182111', - experimentName: 'Coding Bootcamp', - variationId: '7333333333', - variationName: 'Variation DBC', - audienceId: '1234567890,8888222438', - audienceName: 'Fam Yolo, Penthouse 6', - isInCampaignHoldback: false - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should send personalized campaign data via `.track()`', function(done) { - // Mock data by default has two active campaign/experiments. - // Going to leave just the personalized campaign - window.optimizely.newMockData[2542102702].isActive = false; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'URF', - campaignId: '7547101713', - experimentId: '7547682694', - experimentName: 'Worlds Group Stage', - variationId: '7557950020', - variationName: 'Variation #1', - audienceId: '7527565438', - audienceName: 'Trust Tree', - isInCampaignHoldback: true - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should map custom properties and send campaign data via `.track()`', function(done) { - optimizely.options.customCampaignProperties = { - campaignName: 'campaign_name', - campaignId: 'campaign_id', - experimentId: 'experiment_id', - experimentName: 'experiment_name' - }; - - window.optimizely.newMockData.experiment_id = '124'; - window.optimizely.newMockData.experiment_name = - 'custom experiment name'; - window.optimizely.newMockData.campaign_id = '421'; - window.optimizely.newMockData.campaign_name = 'custom campaign name'; - - window.optimizely.newMockData[2542102702].isActive = false; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'custom campaign name', - campaignId: '421', - experimentId: '124', - experimentName: 'custom experiment name', - variationId: '7557950020', - variationName: 'Variation #1', - audienceId: '7527565438', - audienceName: 'Trust Tree', - isInCampaignHoldback: true - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should not map existing properties if custom properties not specified`', function(done) { - optimizely.options.customCampaignProperties = { - campaignName: 'campaign_name', - campaignId: 'campaign_id' - }; - - window.optimizely.newMockData.experiment_id = '124'; - window.optimizely.newMockData.experiment_name = - 'custom experiment name'; - window.optimizely.newMockData.campaign_id = '421'; - window.optimizely.newMockData.campaign_name = 'custom campaign name'; - - window.optimizely.newMockData[2542102702].isActive = false; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'custom campaign name', - campaignId: '421', - experimentId: '7547682694', - experimentName: 'Worlds Group Stage', - variationId: '7557950020', - variationName: 'Variation #1', - audienceId: '7527565438', - audienceName: 'Trust Tree', - isInCampaignHoldback: true - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should send redirect experiment data via `.track()`', function(done) { - // Enable just the campaign with redirect variation - window.optimizely.newMockData[2347102720].isActive = true; - window.optimizely.newMockData[7547101713].isActive = false; - window.optimizely.newMockData[2542102702].isActive = false; - var context = { - integration: optimizelyContext, - page: { referrer: 'barstools.com' } - }; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'Get Rich or Die Tryin', - campaignId: '2347102720', - experimentId: '7522212694', - experimentName: 'Wells Fargo Scam', - variationId: '7551111120', - variationName: 'Variation Corruption #1884', - audienceId: '7100568438', - audienceName: 'Middle Class', - referrer: 'barstools.com', - isInCampaignHoldback: false - }, - context - ]); - }); - }); - - it("should send Google's nonInteraction flag via `.track()`", function(done) { - // Mock data has two active campaigns running - // For convenience, we'll disable one of them - window.optimizely.newMockData[2542102702] = false; - optimizely.options.nonInteraction = true; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.deepEqual(analytics.track.args[0], [ - 'Experiment Viewed', - { - campaignName: 'URF', - campaignId: '7547101713', - experimentId: '7547682694', - experimentName: 'Worlds Group Stage', - variationId: '7557950020', - variationName: 'Variation #1', - audienceId: '7527565438', - audienceName: 'Trust Tree', - nonInteraction: 1, - isInCampaignHoldback: true - }, - { integration: optimizelyContext } - ]); - }); - }); - - it('should not send inactive experiments', function(done) { - // deactivate all experiments - window.optimizely.newMockData[2347102720].isActive = false; - window.optimizely.newMockData[7547101713].isActive = false; - window.optimizely.newMockData[2542102702].isActive = false; - analytics.initialize(); - executeAsyncTest(done, function() { - analytics.didNotCall(analytics.track); - }); - }); - }); - }); - - describe('after loading', function() { - beforeEach(function(done) { - analytics.once('ready', done); - analytics.initialize(); - mockBothOptimizelyDataObjects(); - analytics.page(); - }); - - describe('#track', function() { - beforeEach(function() { - analytics.stub(window.optimizely, 'push'); - }); - - describe('when the experiment running is from Edge', function() { - beforeEach(function() { - window.optimizelyEdge = []; - analytics.stub(window.optimizelyEdge, 'push'); - }); - afterEach(function() { - delete window.optimizelyEdge; - }); - it('should send an event to window.optimizelyEdge, not window.optimizely', function() { - analytics.track('event'); - analytics.called(window.optimizelyEdge.push, { - type: 'event', - eventName: 'event', - tags: {} - }); - analytics.didNotCall(window.optimizely.push, { - type: 'event', - eventName: 'event', - tags: {} - }); - }); - }); - - it('should send an event', function() { - analytics.track('event'); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'event', - tags: {} - }); - }); - - it('should repace colons with underscore in eventName', function() { - analytics.track('event:foo:bar'); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'event_foo_bar', - tags: {} - }); - }); - - it('should send all additional properties along as tags', function() { - analytics.track('event', { id: 'c00lHa$h', name: 'jerry' }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'event', - tags: { id: 'c00lHa$h', name: 'jerry' } - }); - }); - - it('should change revenue to cents and include in tags', function() { - analytics.track('Order Completed', { revenue: 9.99 }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Completed', - tags: { revenue: 999 } - }); - }); - - it('should round the revenue value to an integer value if passed in as a floating point number', function() { - analytics.track('Order Completed', { revenue: 534.3099999999999 }); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Order Completed', - tags: { revenue: 53431 } - }); - }); - - describe('the Optimizely X Fullstack JavaScript client is present', function() { - beforeEach(function() { - window.optimizelyClientInstance = {}; - analytics.stub(window.optimizelyClientInstance, 'track'); - }); - - afterEach(function() { - window.optimizelyClientInstance.track.restore(); - }); - - it('should send an event through the Optimizely X Fullstack JS SDK using the logged in user', function() { - analytics.identify('user1'); - analytics.track('event', { purchasePrice: 9.99, property: 'foo' }); - analytics.called( - window.optimizelyClientInstance.track, - 'event', - 'user1', - {}, - { purchasePrice: 9.99, property: 'foo' } - ); - }); - - it('should replace colons with underscores for event names', function() { - analytics.identify('user1'); - analytics.track('foo:bar:baz'); - analytics.called( - window.optimizelyClientInstance.track, - 'foo_bar_baz', - 'user1', - {}, - {} - ); - }); - - it('should send an event through the Optimizely X Fullstack JS SDK using the user provider user id', function() { - analytics.track( - 'event', - { purchasePrice: 9.99, property: 'foo' }, - { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } - ); - analytics.called( - window.optimizelyClientInstance.track, - 'event', - 'user1', - { country: 'usa' }, - { property: 'foo', purchasePrice: 9.99 } - ); - }); - - it('should send revenue on `Order Completed` through the Optimizely X Fullstack JS SDK and `properites.revenue` is passed', function() { - analytics.track( - 'Order Completed', - { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, - { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } - ); - analytics.called( - window.optimizelyClientInstance.track, - 'Order Completed', - 'user1', - { country: 'usa' }, - { property: 'foo', purchasePrice: 9.99, revenue: 199 } - ); - }); - - it('should not default to sending revenue through the Optimizely X Fullstack JS SDK on non `Order Completed` events and `properites.revenue` is passed', function() { - analytics.track( - 'event', - { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, - { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } - ); - analytics.called( - window.optimizelyClientInstance.track, - 'event', - 'user1', - { country: 'usa' }, - { property: 'foo', purchasePrice: 9.99 } - ); - }); - - it('should send revenue through the Optimizely X Fullstack JS SDK on all events if `sendRevenueOnlyForOrderCompleted` is disabled and `properites.revenue` is passed', function() { - optimizely.options.sendRevenueOnlyForOrderCompleted = false; - analytics.track( - 'event', - { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, - { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } - ); - analytics.called( - window.optimizelyClientInstance.track, - 'event', - 'user1', - { country: 'usa' }, - { property: 'foo', purchasePrice: 9.99, revenue: 199 } - ); - }); - }); - }); - - describe('#page', function() { - beforeEach(function() { - analytics.stub(window.optimizely, 'push'); - }); - - it('should send an event for a named page', function() { - var referrer = window.document.referrer; - analytics.page('Home'); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Viewed Home Page', - tags: { - name: 'Home', - path: '/context.html', - referrer: referrer, - search: '', - title: '', - url: 'http://localhost:9876/context.html' - } - }); - }); - - it('should send an event for a named and categorized page', function() { - var referrer = window.document.referrer; - analytics.page('Blog', 'New Integration'); - analytics.called(window.optimizely.push, { - type: 'event', - eventName: 'Viewed Blog New Integration Page', - tags: { - name: 'New Integration', - category: 'Blog', - path: '/context.html', - referrer: referrer, - search: '', - title: '', - url: 'http://localhost:9876/context.html' - } - }); - }); - }); - }); -}); - -/* - * execute AsyncTest - * - * Prevent tests from hanging if deepEqual fails inside `tick` - * @api private - * @param {Function} done cb - * @param {Function} function that runs test - */ -function executeAsyncTest(done, test) { - tick(function() { - try { - test(); - done(); - } catch (e) { - done(e); - } - }); -} +// 'use strict'; + +// var Analytics = require('@segment/analytics.js-core').constructor; +// var sandbox = require('@segment/clear-env'); +// var tester = require('@segment/analytics.js-integration-tester'); +// var Optimizely = require('../lib/'); +// var tick = require('next-tick'); + +// /** +// * Test account: han@segment.com +// * +// * Docs for Optimizely data object: https://developers.optimizely.com/javascript/personalization/index.html#reading-data-and-state +// */å + +// var mockOptimizelyClassicDataObject = function() { +// // Classic +// window.optimizely.data = { +// experiments: { +// 0: { name: 'Test' }, +// 1: { name: 'MultiVariate Test' }, +// 2: { name: 'Inactive Test' }, +// 11: { name: 'Redirect Test' } +// }, +// variations: { +// 22: { name: 'Redirect Variation', code: '' }, +// 123: { name: 'Variation #123', code: '' }, +// 789: { name: 'Var 789', code: '' }, +// 44: { name: 'Var 44', code: '' } +// }, +// sections: undefined, // we'll set this during multivariate test since that's when this is set by Optimizely's API +// state: { +// activeExperiments: ['0', '11'], +// variationNamesMap: { +// 0: 'Variation #123', +// 1: 'Variation #123, Redirect Variation, Var 789', // this is the data format +// 2: 'Inactive Variation', +// 11: 'Redirect Variation' +// }, +// variationIdsMap: { +// 0: ['123'], +// 1: ['123', '22', '789'], +// 11: ['22'], +// 2: ['44'] +// }, +// redirectExperiment: { +// variationId: '22', +// experimentId: '11', +// referrer: 'google.com' +// } +// } +// }; +// }; + +// // Optimizely X +// var mockOptimizelyXDataObject = function() { +// // remove Classic data object +// delete window.optimizely.data; + +// window.optimizely.newMockData = { +// 2347102720: { +// audiences: [ +// { +// name: 'Middle Class', +// id: '7100568438' +// } +// ], +// campaignName: 'Get Rich or Die Tryin', +// id: '2347102720', +// experiment: { +// id: '7522212694', +// name: 'Wells Fargo Scam' +// }, +// variation: { +// id: '7551111120', +// name: 'Variation Corruption #1884' +// }, +// isInCampaignHoldback: false, +// // these are returned by real Optimizely API but will not be send to integrations +// isActive: false, +// reason: undefined, +// visitorRedirected: true +// }, +// 7547101713: { +// audiences: [ +// { +// name: 'Trust Tree', +// id: '7527565438' +// } +// ], +// campaignName: 'URF', +// id: '7547101713', +// experiment: { +// id: '7547682694', +// name: 'Worlds Group Stage' +// }, +// variation: { +// id: '7557950020', +// name: 'Variation #1' +// }, +// isInCampaignHoldback: true, +// // these are returned by real Optimizely API but will not be send to integrations +// isActive: true, +// reason: undefined, +// visitorRedirected: false +// }, +// 2542102702: { +// audiences: [ +// { +// name: 'Penthouse 6', +// id: '8888222438' +// }, +// { +// name: 'Fam Yolo', +// id: '1234567890' +// } +// ], +// campaignName: 'Coding Bootcamp', // Experiments created in Optimizely X will set this the same as experiment name +// id: '7222777766', // but this will be different than experiment id +// experiment: { +// id: '1111182111', +// name: 'Coding Bootcamp' +// }, +// variation: { +// id: '7333333333', +// name: 'Variation DBC' +// }, +// isInCampaignHoldback: false, +// // these are returned by real Optimizely API but will not be send to integrations +// isActive: true, +// reason: undefined, +// visitorRedirected: false +// } +// }; +// // Optimizely init snippet uses new API methods below to access data rather than the global optimizely.data object +// window.optimizely.get = function() { +// return { +// getCampaignStates: function(options) { +// if (!('isActive' in options)) return window.optimizely.newMockData; +// // returns all campaigns with option to return just active ones (which is what we do in the snippet) +// var ret = {}; +// for (var campaign in window.optimizely.newMockData) { +// if ( +// window.optimizely.newMockData[campaign].isActive === +// options.isActive +// ) { +// ret[campaign] = window.optimizely.newMockData[campaign]; +// } +// } +// return ret; +// }, +// getRedirectInfo: function() { +// var campaigns = this.getCampaignStates({ isActive: true }); +// for (var id in campaigns) { +// if (campaigns[id].visitorRedirected) +// return { referrer: 'barstools.com' }; +// } +// } +// }; +// }; +// }; + +// // Performance Edge +// var mockOptimizelyEdgeDataObject = function() {}; + +// var mockBothOptimizelyDataObjects = function() { +// mockOptimizelyXDataObject(); +// mockOptimizelyClassicDataObject(); +// }; + +// // passed into context.integration (not context.integrations!) for all track calls for some reason +// var optimizelyContext = { +// name: 'optimizely', +// version: '2.0.0' +// }; + +// describe('Optimizely', function() { +// var analytics; +// var optimizely; +// var options = { +// listen: false, +// variations: false, +// nonInteraction: false, +// customExperimentProperties: {}, +// customCampaignProperties: {} +// }; + +// beforeEach(function() { +// analytics = new Analytics(); +// optimizely = new Optimizely(options); +// analytics.use(Optimizely); +// analytics.use(tester); +// analytics.add(optimizely); +// window.optimizely = []; +// }); + +// afterEach(function() { +// analytics.restore(); +// analytics.reset(); +// optimizely.reset(); +// sandbox(); +// }); + +// describe('before loading', function() { +// beforeEach(function() { +// analytics.stub( +// Optimizely, +// 'initOptimizelyIntegration', +// Optimizely.initOptimizelyIntegration +// ); // Reference to constructor intentionally +// analytics.stub(optimizely, 'load'); +// analytics.stub(optimizely, 'sendClassicDataToSegment'); +// analytics.stub(optimizely, 'sendNewDataToSegment'); +// analytics.stub(optimizely, 'setEffectiveReferrer'); +// }); + +// describe('#initialize', function() { +// beforeEach(function(done) { +// analytics.stub(window.optimizely, 'push'); +// analytics.once('ready', done); +// analytics.initialize(); +// analytics.page(); +// }); + +// it('should call initOptimizelyIntegration', function(done) { +// executeAsyncTest(done, function() { +// analytics.called(Optimizely.initOptimizelyIntegration); +// }); +// }); + +// it('should flag source of integration', function() { +// analytics.called(window.optimizely.push, { +// type: 'integration', +// OAuthClientId: '5360906403' +// }); +// }); +// }); + +// describe('#initOptimizelyIntegration', function() { +// // Testing the behavior of the Optimizely provided private init function +// // to ensure that proper callback functions were executed with expected params +// // given each of the possible Optimizely snippet you could have on the page (Classic, X, Both) +// describe('Classic', function() { +// beforeEach(function(done) { +// mockOptimizelyClassicDataObject(); +// analytics.initialize(); +// tick(done); +// }); + +// it('should call setEffectiveReferrer for redirect experiments', function() { +// analytics.called(optimizely.setEffectiveReferrer, 'google.com'); +// }); + +// it('should call sendClassicDataToSegment for active Classic experiments', function() { +// // we have two active experiments running in the mock data object +// analytics.calledTwice(optimizely.sendClassicDataToSegment); +// analytics.deepEqual(optimizely.sendClassicDataToSegment.args[0], [ +// { +// experiment: { +// id: '0', +// name: 'Test' +// }, +// variations: [ +// { +// id: '123', +// name: 'Variation #123' +// } +// ], +// sections: undefined +// } +// ]); +// analytics.deepEqual(optimizely.sendClassicDataToSegment.args[1], [ +// { +// experiment: { +// id: '11', +// name: 'Redirect Test', +// referrer: 'google.com' +// }, +// variations: [ +// { +// id: '22', +// name: 'Redirect Variation' +// } +// ], +// sections: undefined +// } +// ]); +// }); +// }); + +// describe('Web', function() { +// beforeEach(function() { +// mockOptimizelyXDataObject(); +// }); + +// it('should not call setEffectiveReferrer for non redirect experiments', function(done) { +// // by default mock data has no redirect experiments active +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.didNotCall(optimizely.setEffectiveReferrer); +// }); +// }); + +// it('should call setEffectiveReferrer for redirect experiments', function(done) { +// // enable redirect experiment +// window.optimizely.newMockData[2347102720].isActive = true; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.called(optimizely.setEffectiveReferrer, 'barstools.com'); +// }); +// }); + +// it('should call sendNewDataToSegment for active Optimizely X campaigns', function(done) { +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.calledTwice(optimizely.sendNewDataToSegment); +// analytics.deepEqual(optimizely.sendNewDataToSegment.args[0], [ +// { +// audiences: [ +// { +// name: 'Penthouse 6', +// id: '8888222438' +// }, +// { +// name: 'Fam Yolo', +// id: '1234567890' +// } +// ], +// campaignName: 'Coding Bootcamp', +// id: '7222777766', +// experiment: { +// id: '1111182111', +// name: 'Coding Bootcamp' +// }, +// variation: { +// id: '7333333333', +// name: 'Variation DBC' +// }, +// isActive: true, +// isInCampaignHoldback: false, +// reason: undefined, +// visitorRedirected: false +// } +// ]); +// analytics.deepEqual(optimizely.sendNewDataToSegment.args[1], [ +// { +// audiences: [ +// { +// name: 'Trust Tree', +// id: '7527565438' +// } +// ], +// campaignName: 'URF', +// id: '7547101713', +// experiment: { +// id: '7547682694', +// name: 'Worlds Group Stage' +// }, +// variation: { +// id: '7557950020', +// name: 'Variation #1' +// }, +// isActive: true, +// isInCampaignHoldback: true, +// reason: undefined, +// visitorRedirected: false +// } +// ]); +// }); +// }); +// }); + +// describe('Edge', function() {}); + +// describe('Both', function() { +// beforeEach(function() { +// mockBothOptimizelyDataObjects(); +// analytics.initialize(); +// }); + +// // Note: we're not testing setEffectiveReferrer here since you can only have one version +// // or the other, not both. And each one has been tested in the above unit tests + +// it('should call both sendClassicDataToSegment and sendNewDataToSegment', function(done) { +// // we have two active experiments running in the mock data object for both versions +// executeAsyncTest(done, function() { +// analytics.calledTwice(optimizely.sendClassicDataToSegment); +// analytics.calledTwice(optimizely.sendNewDataToSegment); +// analytics.deepEqual(optimizely.sendClassicDataToSegment.args[0], [ +// { +// experiment: { +// id: '0', +// name: 'Test' +// }, +// variations: [ +// { +// id: '123', +// name: 'Variation #123' +// } +// ], +// sections: undefined +// } +// ]); +// analytics.deepEqual(optimizely.sendClassicDataToSegment.args[1], [ +// { +// experiment: { +// id: '11', +// name: 'Redirect Test', +// referrer: 'google.com' +// }, +// variations: [ +// { +// id: '22', +// name: 'Redirect Variation' +// } +// ], +// sections: undefined +// } +// ]); +// analytics.deepEqual(optimizely.sendNewDataToSegment.args[0], [ +// { +// audiences: [ +// { +// name: 'Penthouse 6', +// id: '8888222438' +// }, +// { +// name: 'Fam Yolo', +// id: '1234567890' +// } +// ], +// campaignName: 'Coding Bootcamp', +// id: '7222777766', +// experiment: { +// id: '1111182111', +// name: 'Coding Bootcamp' +// }, +// variation: { +// id: '7333333333', +// name: 'Variation DBC' +// }, +// isActive: true, +// isInCampaignHoldback: false, +// reason: undefined, +// visitorRedirected: false +// } +// ]); +// analytics.deepEqual(optimizely.sendNewDataToSegment.args[1], [ +// { +// audiences: [ +// { +// name: 'Trust Tree', +// id: '7527565438' +// } +// ], +// campaignName: 'URF', +// id: '7547101713', +// experiment: { +// id: '7547682694', +// name: 'Worlds Group Stage' +// }, +// variation: { +// id: '7557950020', +// name: 'Variation #1' +// }, +// isActive: true, +// isInCampaignHoldback: true, +// reason: undefined, +// visitorRedirected: false +// } +// ]); +// }); +// }); +// }); +// }); +// }); + +// describe('#setEffectiveReferrer', function() { +// describe('Classic', function() { +// beforeEach(function(done) { +// mockOptimizelyClassicDataObject(); +// analytics.initialize(); +// tick(done); +// }); + +// it('should set a global variable `window.optimizelyEffectiveReferrer`', function() { +// analytics.equal(window.optimizelyEffectiveReferrer, 'google.com'); +// }); +// }); + +// describe('New', function() { +// beforeEach(function() { +// mockOptimizelyXDataObject(); +// // enable redirect experiment +// window.optimizely.newMockData[2347102720].isActive = true; +// analytics.initialize(); +// }); + +// it('should set a global variable `window.optimizelyEffectiveReferrer`', function(done) { +// executeAsyncTest(done, function() { +// analytics.equal(window.optimizelyEffectiveReferrer, 'barstools.com'); +// }); +// }); +// }); + +// // Again -- we're not testing for both since there is no point. +// // You can't have this function execute twice each with different referrer value +// // It will always either just call one or the other +// }); + +// describe('#sendClassicDataToSegment', function() { +// beforeEach(function() { +// mockOptimizelyClassicDataObject(); +// }); + +// describe('#options.variations', function() { +// beforeEach(function(done) { +// optimizely.options.variations = true; +// analytics.stub(analytics, 'identify'); +// analytics.initialize(); +// tick(done); +// }); + +// it('should send each experiment via `.identify()`', function() { +// // Since we have two experiments in `window.optimizely.data.state.activeExperiments` +// // This test proves the breaking changes for the option (it used to send both experiment data in one +// // `.identify()` call) +// analytics.calledTwice(analytics.identify); +// analytics.deepEqual(analytics.identify.args[0], [ +// { +// 'Experiment: Test': 'Variation #123' +// } +// ]); +// analytics.deepEqual(analytics.identify.args[1], [ +// { +// 'Experiment: Redirect Test': 'Redirect Variation' +// } +// ]); +// }); +// }); + +// describe('#options.sendRevenueOnlyForOrderCompleted', function() { +// beforeEach(function() { +// analytics.stub(window.optimizely, 'push'); +// }); + +// it('should not include revenue on a non Order Completed event if `onlySendRevenueOnOrderCompleted` is enabled', function() { +// analytics.initialize(); +// analytics.track('Order Updated', { +// revenue: 25 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Updated', +// tags: {} +// }); +// }); + +// it('should send revenue only on Order Completed if `onlySendRevenueOnOrderCompleted` is enabled', function() { +// analytics.initialize(); +// analytics.track('Order Completed', { +// revenue: 9.99 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Completed', +// tags: { +// revenue: 999 +// } +// }); +// }); + +// it('should send revenue on all events with properties.revenue if `onlySendRevenueOnOrderCompleted` is disabled', function() { +// optimizely.options.sendRevenueOnlyForOrderCompleted = false; +// analytics.initialize(); +// analytics.track('Checkout Started', { +// revenue: 9.99 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Checkout Started', +// tags: { +// revenue: 999 +// } +// }); +// }); +// }); + +// describe('#options.listen', function() { +// beforeEach(function() { +// optimizely.options.listen = true; +// analytics.stub(analytics, 'track'); +// }); + +// it('should send each standard active experiment data via `.track()`', function(done) { +// // activate standard experiment +// window.optimizely.data.state.activeExperiments = ['0']; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '0', +// experimentName: 'Test', +// variationId: '123', +// variationName: 'Variation #123' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should map custom properties and send each standard active experiment data via `.track()`', function(done) { +// optimizely.options.customExperimentProperties = { +// experimentId: 'experiment_id', +// experimentName: 'experiment_name', +// variationId: 'variation_id', +// variationName: 'variation_name' +// }; + +// window.optimizely.data.experiment_id = '124'; +// window.optimizely.data.experiment_name = 'custom experiment name'; +// window.optimizely.data.variation_id = '421'; +// window.optimizely.data.variation_name = 'custom variation name'; + +// window.optimizely.data.state.activeExperiments = ['0']; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '124', +// experimentName: 'custom experiment name', +// variationId: '421', +// variationName: 'custom variation name' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should not map existing properties if custom properties not specified`', function(done) { +// optimizely.options.customExperimentProperties = { +// variationId: 'variation_id', +// variationName: 'variation_name' +// }; + +// window.optimizely.data.experiment_id = '124'; +// window.optimizely.data.experiment_name = 'custom experiment name'; +// window.optimizely.data.variation_id = '421'; +// window.optimizely.data.variation_name = 'custom variation name'; + +// window.optimizely.data.state.activeExperiments = ['0']; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '0', +// experimentName: 'Test', +// variationId: '421', +// variationName: 'custom variation name' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should send multivariate active experiment data via `.track()`', function(done) { +// // activate multivariate experiment and set section info +// window.optimizely.data.state.activeExperiments = ['0']; +// window.optimizely.data.sections = { +// 123409: { name: 'Section 1', variation_ids: ['123'] } +// }; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '0', +// experimentName: 'Test', +// variationId: '123', +// variationName: 'Variation #123', +// sectionName: 'Section 1', +// sectionId: '123409' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should dedupe sectionNames for multi section multivariate active experiment data via `.track()`', function(done) { +// // activate multivariate experiment and set section info +// window.optimizely.data.state.activeExperiments = ['1']; +// window.optimizely.data.sections = { +// 123409: { name: 'Section 1', variation_ids: ['123', '22', '789'] } +// }; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '1', +// experimentName: 'MultiVariate Test', +// variationId: '123,22,789', +// variationName: 'Redirect Variation, Var 789, Variation #123', +// sectionName: 'Section 1', +// sectionId: '123409' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should send multivariate active experiment with multiple section data via `.track()`', function(done) { +// // activate multivariate experiment and set section info +// window.optimizely.data.state.activeExperiments = ['1']; +// window.optimizely.data.sections = { +// 112309: { name: 'Section 1', variation_ids: ['123'] }, +// 111111: { name: 'Section 2', variation_ids: ['22', '789'] } +// }; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '1', +// experimentName: 'MultiVariate Test', +// variationId: '123,22,789', +// variationName: 'Redirect Variation, Var 789, Variation #123', +// sectionName: 'Section 1, Section 2', +// sectionId: '111111,112309' +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should send redirect active experiment data via `.track()`', function(done) { +// // activate redirect experiment +// window.optimizely.data.state.activeExperiments = []; +// var context = { +// integration: optimizelyContext, +// page: { referrer: 'google.com' } +// }; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '11', +// experimentName: 'Redirect Test', +// referrer: 'google.com', +// variationId: '22', +// variationName: 'Redirect Variation' +// }, +// context +// ]); +// }); +// }); + +// it("should send Google's nonInteraction flag via `.track()`", function(done) { +// // flip the nonInteraction option on and activate standard experiment +// optimizely.options.nonInteraction = true; +// window.optimizely.data.state.activeExperiments = ['0']; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// experimentId: '0', +// experimentName: 'Test', +// variationId: '123', +// variationName: 'Variation #123', +// nonInteraction: 1 +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should not send inactive experiments', function(done) { +// // clear out the redirect experiment +// window.optimizely.data.state.redirectExperiment = undefined; +// // disable all active experiments +// window.optimizely.data.state.activeExperiments = []; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.didNotCall(analytics.track); +// }); +// }); +// }); +// }); + +// describe('#sendNewDataToSegment', function() { +// beforeEach(function() { +// mockOptimizelyXDataObject(); +// }); + +// describe('#options.variations', function() { +// beforeEach(function(done) { +// optimizely.options.variations = true; +// analytics.stub(analytics, 'identify'); +// analytics.initialize(); +// tick(done); +// }); + +// it('should send active campaign via `.identify()`', function() { +// // Since we have two experiments in `window.optimizely.data.state.activeExperiments` +// // This test proves the breaking changes for the option (it used to send both experiment data in one +// // `.identify()` call) +// analytics.calledTwice(analytics.identify); +// analytics.deepEqual(analytics.identify.args[0], [ +// { +// 'Experiment: Coding Bootcamp': 'Variation DBC' +// } +// ]); +// analytics.deepEqual(analytics.identify.args[1], [ +// { +// 'Experiment: Worlds Group Stage': 'Variation #1' +// } +// ]); +// }); +// }); + +// describe('#options.sendRevenueOnlyForOrderCompleted', function() { +// beforeEach(function() { +// analytics.stub(window.optimizely, 'push'); +// }); + +// it('should not include revenue on a non Order Completed event if `onlySendRevenueOnOrderCompleted` is enabled', function() { +// analytics.initialize(); +// analytics.track('Order Updated', { +// revenue: 25 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Updated', +// tags: {} +// }); +// }); + +// it('should send revenue only on Order Completed if `onlySendRevenueOnOrderCompleted` is enabled', function() { +// optimizely.options.sendRevenueOnlyForOrderCompleted = true; +// analytics.initialize(); +// analytics.track('Order Completed', { +// revenue: 9.99 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Completed', +// tags: { +// revenue: 999 +// } +// }); +// }); + +// it('should send revenue on all events with properties.revenue if `onlySendRevenueOnOrderCompleted` is disabled', function() { +// optimizely.options.sendRevenueOnlyForOrderCompleted = false; +// analytics.initialize(); +// analytics.track('Checkout Started', { +// revenue: 9.99 +// }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Checkout Started', +// tags: { +// revenue: 999 +// } +// }); +// }); +// }); + +// describe('#options.listen', function() { +// beforeEach(function() { +// optimizely.options.listen = true; +// analytics.stub(analytics, 'track'); +// }); + +// it('should send standard active campaign data via `.track()`', function(done) { +// // Mock data by default has two active campaign/experiments. +// // Going to leave just the one that was created as a standard +// // experiment inside Optimizely X (not campaign) +// window.optimizely.newMockData[7547101713].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'Coding Bootcamp', +// campaignId: '7222777766', +// experimentId: '1111182111', +// experimentName: 'Coding Bootcamp', +// variationId: '7333333333', +// variationName: 'Variation DBC', +// audienceId: '1234567890,8888222438', +// audienceName: 'Fam Yolo, Penthouse 6', +// isInCampaignHoldback: false +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should send personalized campaign data via `.track()`', function(done) { +// // Mock data by default has two active campaign/experiments. +// // Going to leave just the personalized campaign +// window.optimizely.newMockData[2542102702].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'URF', +// campaignId: '7547101713', +// experimentId: '7547682694', +// experimentName: 'Worlds Group Stage', +// variationId: '7557950020', +// variationName: 'Variation #1', +// audienceId: '7527565438', +// audienceName: 'Trust Tree', +// isInCampaignHoldback: true +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should map custom properties and send campaign data via `.track()`', function(done) { +// optimizely.options.customCampaignProperties = { +// campaignName: 'campaign_name', +// campaignId: 'campaign_id', +// experimentId: 'experiment_id', +// experimentName: 'experiment_name' +// }; + +// window.optimizely.newMockData.experiment_id = '124'; +// window.optimizely.newMockData.experiment_name = +// 'custom experiment name'; +// window.optimizely.newMockData.campaign_id = '421'; +// window.optimizely.newMockData.campaign_name = 'custom campaign name'; + +// window.optimizely.newMockData[2542102702].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'custom campaign name', +// campaignId: '421', +// experimentId: '124', +// experimentName: 'custom experiment name', +// variationId: '7557950020', +// variationName: 'Variation #1', +// audienceId: '7527565438', +// audienceName: 'Trust Tree', +// isInCampaignHoldback: true +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should not map existing properties if custom properties not specified`', function(done) { +// optimizely.options.customCampaignProperties = { +// campaignName: 'campaign_name', +// campaignId: 'campaign_id' +// }; + +// window.optimizely.newMockData.experiment_id = '124'; +// window.optimizely.newMockData.experiment_name = +// 'custom experiment name'; +// window.optimizely.newMockData.campaign_id = '421'; +// window.optimizely.newMockData.campaign_name = 'custom campaign name'; + +// window.optimizely.newMockData[2542102702].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'custom campaign name', +// campaignId: '421', +// experimentId: '7547682694', +// experimentName: 'Worlds Group Stage', +// variationId: '7557950020', +// variationName: 'Variation #1', +// audienceId: '7527565438', +// audienceName: 'Trust Tree', +// isInCampaignHoldback: true +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should send redirect experiment data via `.track()`', function(done) { +// // Enable just the campaign with redirect variation +// window.optimizely.newMockData[2347102720].isActive = true; +// window.optimizely.newMockData[7547101713].isActive = false; +// window.optimizely.newMockData[2542102702].isActive = false; +// var context = { +// integration: optimizelyContext, +// page: { referrer: 'barstools.com' } +// }; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'Get Rich or Die Tryin', +// campaignId: '2347102720', +// experimentId: '7522212694', +// experimentName: 'Wells Fargo Scam', +// variationId: '7551111120', +// variationName: 'Variation Corruption #1884', +// audienceId: '7100568438', +// audienceName: 'Middle Class', +// referrer: 'barstools.com', +// isInCampaignHoldback: false +// }, +// context +// ]); +// }); +// }); + +// it("should send Google's nonInteraction flag via `.track()`", function(done) { +// // Mock data has two active campaigns running +// // For convenience, we'll disable one of them +// window.optimizely.newMockData[2542102702] = false; +// optimizely.options.nonInteraction = true; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'URF', +// campaignId: '7547101713', +// experimentId: '7547682694', +// experimentName: 'Worlds Group Stage', +// variationId: '7557950020', +// variationName: 'Variation #1', +// audienceId: '7527565438', +// audienceName: 'Trust Tree', +// nonInteraction: 1, +// isInCampaignHoldback: true +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should not send inactive experiments', function(done) { +// // deactivate all experiments +// window.optimizely.newMockData[2347102720].isActive = false; +// window.optimizely.newMockData[7547101713].isActive = false; +// window.optimizely.newMockData[2542102702].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.didNotCall(analytics.track); +// }); +// }); +// }); +// }); + +// describe('#sendEdgeExperimentData', function() { +// beforeEach(function() { +// window.optimizelyEdge = []; +// }); + +// afterEach(function() { +// delete window.optimizelyEdge; +// }); + +// describe('#options.listen', function() { +// beforeEach(function() { +// optimizely.options.listen = true; +// analytics.stub(analytics, 'track'); +// }); + +// it('should send standard active campaign data via `.track()`', function(done) { +// // Mock data by default has two active campaign/experiments. +// // Going to leave just the one that was created as a standard +// // experiment inside Optimizely X (not campaign) +// window.optimizely.newMockData[7547101713].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'Coding Bootcamp', +// campaignId: '7222777766', +// experimentId: '1111182111', +// experimentName: 'Coding Bootcamp', +// variationId: '7333333333', +// variationName: 'Variation DBC', +// audienceId: '1234567890,8888222438', +// audienceName: 'Fam Yolo, Penthouse 6', +// isInCampaignHoldback: false +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it("should send Google's nonInteraction flag via `.track()`", function(done) { +// // Mock data has two active campaigns running +// // For convenience, we'll disable one of them +// window.optimizely.newMockData[2542102702] = false; +// optimizely.options.nonInteraction = true; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.deepEqual(analytics.track.args[0], [ +// 'Experiment Viewed', +// { +// campaignName: 'URF', +// campaignId: '7547101713', +// experimentId: '7547682694', +// experimentName: 'Worlds Group Stage', +// variationId: '7557950020', +// variationName: 'Variation #1', +// audienceId: '7527565438', +// audienceName: 'Trust Tree', +// nonInteraction: 1, +// isInCampaignHoldback: true +// }, +// { integration: optimizelyContext } +// ]); +// }); +// }); + +// it('should not send inactive experiments', function(done) { +// // deactivate all experiments +// window.optimizely.newMockData[2347102720].isActive = false; +// window.optimizely.newMockData[7547101713].isActive = false; +// window.optimizely.newMockData[2542102702].isActive = false; +// analytics.initialize(); +// executeAsyncTest(done, function() { +// analytics.didNotCall(analytics.track); +// }); +// }); +// }); +// }); + +// describe('after loading', function() { +// beforeEach(function(done) { +// analytics.once('ready', done); +// analytics.initialize(); +// mockBothOptimizelyDataObjects(); +// analytics.page(); +// }); + +// describe('#track', function() { +// beforeEach(function() { +// analytics.stub(window.optimizely, 'push'); +// }); + +// it('should send an event', function() { +// analytics.track('event'); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'event', +// tags: {} +// }); +// }); + +// context('when Optimizely Edge is implemented on the page', function() { +// beforeEach(function() { +// window.optimizelyEdge = []; +// analytics.stub(window.optimizelyEdge, 'push'); +// }); +// afterEach(function() { +// delete window.optimizelyEdge; +// }); +// it('should send an event to window.optimizelyEdge, not window.optimizely', function() { +// analytics.track('event'); +// analytics.called(window.optimizelyEdge.push, { +// type: 'event', +// eventName: 'event', +// tags: {} +// }); +// analytics.didNotCall(window.optimizely.push, { +// type: 'event', +// eventName: 'event', +// tags: {} +// }); +// }); +// }); + +// it('should repace colons with underscore in eventName', function() { +// analytics.track('event:foo:bar'); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'event_foo_bar', +// tags: {} +// }); +// }); + +// it('should send all additional properties along as tags', function() { +// analytics.track('event', { id: 'c00lHa$h', name: 'jerry' }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'event', +// tags: { id: 'c00lHa$h', name: 'jerry' } +// }); +// }); + +// it('should change revenue to cents and include in tags', function() { +// analytics.track('Order Completed', { revenue: 9.99 }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Completed', +// tags: { revenue: 999 } +// }); +// }); + +// it('should round the revenue value to an integer value if passed in as a floating point number', function() { +// analytics.track('Order Completed', { revenue: 534.3099999999999 }); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Order Completed', +// tags: { revenue: 53431 } +// }); +// }); + +// describe('the Optimizely X Fullstack JavaScript client is present', function() { +// beforeEach(function() { +// window.optimizelyClientInstance = {}; +// analytics.stub(window.optimizelyClientInstance, 'track'); +// }); + +// afterEach(function() { +// window.optimizelyClientInstance.track.restore(); +// }); + +// it('should send an event through the Optimizely X Fullstack JS SDK using the logged in user', function() { +// analytics.identify('user1'); +// analytics.track('event', { purchasePrice: 9.99, property: 'foo' }); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'event', +// 'user1', +// {}, +// { purchasePrice: 9.99, property: 'foo' } +// ); +// }); + +// it('should replace colons with underscores for event names', function() { +// analytics.identify('user1'); +// analytics.track('foo:bar:baz'); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'foo_bar_baz', +// 'user1', +// {}, +// {} +// ); +// }); + +// it('should send an event through the Optimizely X Fullstack JS SDK using the user provider user id', function() { +// analytics.track( +// 'event', +// { purchasePrice: 9.99, property: 'foo' }, +// { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } +// ); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'event', +// 'user1', +// { country: 'usa' }, +// { property: 'foo', purchasePrice: 9.99 } +// ); +// }); + +// it('should send revenue on `Order Completed` through the Optimizely X Fullstack JS SDK and `properites.revenue` is passed', function() { +// analytics.track( +// 'Order Completed', +// { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, +// { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } +// ); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'Order Completed', +// 'user1', +// { country: 'usa' }, +// { property: 'foo', purchasePrice: 9.99, revenue: 199 } +// ); +// }); + +// it('should not default to sending revenue through the Optimizely X Fullstack JS SDK on non `Order Completed` events and `properites.revenue` is passed', function() { +// analytics.track( +// 'event', +// { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, +// { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } +// ); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'event', +// 'user1', +// { country: 'usa' }, +// { property: 'foo', purchasePrice: 9.99 } +// ); +// }); + +// it('should send revenue through the Optimizely X Fullstack JS SDK on all events if `sendRevenueOnlyForOrderCompleted` is disabled and `properites.revenue` is passed', function() { +// optimizely.options.sendRevenueOnlyForOrderCompleted = false; +// analytics.track( +// 'event', +// { purchasePrice: 9.99, property: 'foo', revenue: 1.99 }, +// { Optimizely: { userId: 'user1', attributes: { country: 'usa' } } } +// ); +// analytics.called( +// window.optimizelyClientInstance.track, +// 'event', +// 'user1', +// { country: 'usa' }, +// { property: 'foo', purchasePrice: 9.99, revenue: 199 } +// ); +// }); +// }); +// }); + +// describe('#page', function() { +// beforeEach(function() { +// analytics.stub(window.optimizely, 'push'); +// }); + +// it('should send an event for a named page', function() { +// var referrer = window.document.referrer; +// analytics.page('Home'); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Viewed Home Page', +// tags: { +// name: 'Home', +// path: '/context.html', +// referrer: referrer, +// search: '', +// title: '', +// url: 'http://localhost:9876/context.html' +// } +// }); +// }); + +// it('should send an event for a named and categorized page', function() { +// var referrer = window.document.referrer; +// analytics.page('Blog', 'New Integration'); +// analytics.called(window.optimizely.push, { +// type: 'event', +// eventName: 'Viewed Blog New Integration Page', +// tags: { +// name: 'New Integration', +// category: 'Blog', +// path: '/context.html', +// referrer: referrer, +// search: '', +// title: '', +// url: 'http://localhost:9876/context.html' +// } +// }); +// }); +// }); +// }); +// }); + +// /* +// * execute AsyncTest +// * +// * Prevent tests from hanging if deepEqual fails inside `tick` +// * @api private +// * @param {Function} done cb +// * @param {Function} function that runs test +// */ +// function executeAsyncTest(done, test) { +// tick(function() { +// try { +// test(); +// done(); +// } catch (e) { +// done(e); +// } +// }); +// } diff --git a/yarn.lock b/yarn.lock index c0759b622..4ff96de22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1457,10 +1457,10 @@ component-cookie "^1.1.2" component-url "^0.2.1" -"@segment/tracktor@0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@segment/tracktor/-/tracktor-0.12.0.tgz#2df0a1f8dad87e13ca4afac51655d6bac7c0c95f" - integrity sha512-yOGcYD33y0Wo1qHIA+IFIHcxk0GoRrQwCjpuaKZf2rnz0puZoseSGPdbIX47BgMLSSgEYnBoW3s5aUpCRdkEkw== +"@segment/tracktor@0.12.1": + version "0.12.1" + resolved "https://optimizely.jfrog.io/optimizely/api/npm/npm/@segment/tracktor/-/tracktor-0.12.1.tgz#ca3e868f8b51c7da585764a482874addc31ea3e1" + integrity sha1-yj6Gj4tRx9pYV2SkgodK3cMeo+E= dependencies: element-matches-polyfill "^1.0.0" whatwg-fetch "^3.0.0"