diff --git a/src/build-options.js b/src/build-options.js index 0ad2676..8563130 100644 --- a/src/build-options.js +++ b/src/build-options.js @@ -12,7 +12,6 @@ import { assign } from './ponyfills/objects.js'; * @property {string} [endpoint] * @property {boolean} [autoConfirm] * @property {RequestHooks} [hooks] - * @property {boolean} [analytics] * @property {*} [store] * @property {*} [context] * @property {*} [auth] @@ -44,7 +43,6 @@ export function buildOptions(options) { opts.version = opts.version || 1; opts.endpoint = ((opts.endpoint && opts.endpoint.replace(/\/$/, '')) || 'https://participants.evolv.ai') + '/v' + opts.version; - opts.analytics = 'analytics' in opts ? opts.analytics : opts.version > 1; opts.hooks = assign({}, opts.hooks); diff --git a/src/index.js b/src/index.js index a915c11..992c018 100644 --- a/src/index.js +++ b/src/index.js @@ -53,8 +53,7 @@ function EvolvClient(opts) { clientName: options.clientName }; - const contextBeacon = options.analytics ? new Beacon(options.endpoint + '/' + options.environment + '/data', context, beaconOptions) : null; - const eventBeacon = options.beacon || new Beacon(options.endpoint + '/' + options.environment + '/events', context, beaconOptions); + const contextBeacon = new Beacon(options.endpoint + '/' + options.environment + '/data', context, beaconOptions); /** * The context against which the key predicates will be evaluated. @@ -214,29 +213,12 @@ function EvolvClient(opts) { * * @param {String} type The type associated with the event. * @param {Object} [metadata] Any metadata to attach to the event. - * @param {Boolean} [flush = false] If true, the event will be sent immediately. */ - this.emit = function(type, metadata, flush) { + this.emit = function(type, metadata) { context.pushToArray('events', {type: type, timestamp: (new Date()).getTime()}); - eventBeacon.emit(type, assign({ - uid: context.uid, - metadata: metadata - }), flush); emit(context, EvolvClient.EVENT_EMITTED, type, metadata); }; - // TODO AP-2318 prevent sending confirmations when every stat comes from analytics. Prior to that, these are still needed - /*let getSessionBasedExps = function() { - let sessionBasedExps = {}; - - ((store.configuration && store.configuration._experiments) || []).forEach(function(experiment) { - if (experiment._optimization_metric === 'SESSION') { - sessionBasedExps[experiment.id] = true; - } - }); - - return sessionBasedExps; - }*/ /** * Confirm that the consumer has successfully received and applied values, making them eligible for inclusion in @@ -295,18 +277,6 @@ function EvolvClient(opts) { const existingValues = isInternalUser ? existingInternalConfirmations : existingConfirmations; context.set(confirmationsKey, newConfirmations.concat(existingValues)); - confirmableAllocations.forEach(function(alloc) { - // Only confirm for non session based experiments -- session based use the analytics data - // TODO AP-2318 prevent sending confirmations when every stat comes from analytics. Prior to that, these are still needed - // !sessionBasedExps[alloc.eid] && eventBeacon.emit('confirmation', { - eventBeacon.emit('confirmation', { - uid: alloc.uid, - eid: alloc.eid, - cid: alloc.cid - }); - }); - - eventBeacon.flush(); emit(context, EvolvClient.CONFIRMED); resolve(); return; @@ -359,15 +329,6 @@ function EvolvClient(opts) { context.set('experiments.contaminations', contextContaminations.concat(contaminations)); - contaminatableAllocations.forEach(function(alloc) { - eventBeacon.emit('contamination', { - uid: alloc.uid, - eid: alloc.eid, - cid: alloc.cid, - contaminationReason: details - }); - }); - eventBeacon.flush(); emit(context, EvolvClient.CONTAMINATED); }; @@ -413,33 +374,31 @@ function EvolvClient(opts) { console.log('Evolv: Failed to retrieve client context'); }); - if (options.analytics) { - /*eslint no-unused-vars: ["error", { "argsIgnorePattern": "ctx" }]*/ - waitFor(context, CONTEXT_INITIALIZED, function (type, ctx) { - contextBeacon.emit(type, context.remoteContext); - }); - waitFor(context, CONTEXT_VALUE_ADDED, function (type, key, value, local) { - if (local) { - return; - } + /*eslint no-unused-vars: ["error", { "argsIgnorePattern": "ctx" }]*/ + waitFor(context, CONTEXT_INITIALIZED, function (type, ctx) { + contextBeacon.emit(type, context.remoteContext); + }); + waitFor(context, CONTEXT_VALUE_ADDED, function (type, key, value, local) { + if (local) { + return; + } - contextBeacon.emit(type, {key: key, value: value}); - }); - waitFor(context, CONTEXT_VALUE_CHANGED, function (type, key, value, before, local) { - if (local) { - return; - } + contextBeacon.emit(type, {key: key, value: value}); + }); + waitFor(context, CONTEXT_VALUE_CHANGED, function (type, key, value, before, local) { + if (local) { + return; + } - contextBeacon.emit(type, {key: key, value: value}); - }); - waitFor(context, CONTEXT_VALUE_REMOVED, function (type, key, local) { - if (local) { - return; - } + contextBeacon.emit(type, {key: key, value: value}); + }); + waitFor(context, CONTEXT_VALUE_REMOVED, function (type, key, local) { + if (local) { + return; + } - contextBeacon.emit(type, {key: key}); - }); - } + contextBeacon.emit(type, {key: key}); + }); if (options.autoConfirm) { this.confirm(); @@ -454,10 +413,7 @@ function EvolvClient(opts) { * Force all beacons to transmit. */ this.flush = function() { - eventBeacon.flush(); - if (options.analytics) { - contextBeacon.flush(); - } + contextBeacon.flush(); }; /** @@ -466,10 +422,7 @@ function EvolvClient(opts) { * then calling this will allow data to be sent back to Evolv */ this.allowEvents = function() { - eventBeacon.unblockAndFlush(); - if (options.analytics) { - contextBeacon.unblockAndFlush(); - } + contextBeacon.unblockAndFlush(); }; /** diff --git a/src/tests/beacon.test.js b/src/tests/beacon.test.js index a1398e0..599853a 100644 --- a/src/tests/beacon.test.js +++ b/src/tests/beacon.test.js @@ -484,143 +484,6 @@ describe('beacon', () => { }); }); - describe('test events v1', () => { - it('should use get is the message is short enough - Edge', async() => { - const v1EventEndpoint = 'https://participants.evolv.ai/v1/MYUID/events' - const fetch = chai.spy(() => new Promise(resolve => resolve({ok: true}))); - // noinspection JSConstantReassignment - global.window = { - addEventListener: () => null, - fetch: fetch, - navigator: { - userAgent: edgeAgent - } - }; - const beacon = new Beacon(v1EventEndpoint, {uid: ''}, ''); - - let longMessage = 'abc'; - - beacon.emit('test', { - test: longMessage - }, false); - - await new Promise(resolve => setTimeout(resolve, DELAY + 100)); - - expect(fetch).to.have.been.called(1); - expect(xhrRequests.length).to.equal(0); - expect(fetch).to.have.been.called.with(v1EventEndpoint +'?test=abc&type=test' , { - cache: 'no-cache', - keepalive: true, - method: 'GET' - }); - }); - - it('should use get is the message is short enough - Chrome', async() => { - const v1EventEndpoint = 'https://participants.evolv.ai/v1/MYUID/events' - const fetch = chai.spy(() => new Promise(resolve => resolve({ok: true}))); - // noinspection JSConstantReassignment - global.window = { - addEventListener: () => null, - fetch: fetch, - navigator: { - userAgent: chromeAgent - } - }; - const beacon = new Beacon(v1EventEndpoint, {uid: ''}, ''); - - let longMessage = ''; - for (let i = 0; i < MICROSOFT_MAX_MESSAGE_SIZE + 1; i++) { - longMessage += 'a'; - } - - beacon.emit('test', { - test: longMessage - }, false); - - await new Promise(resolve => setTimeout(resolve, DELAY + 100)); - - expect(fetch).to.have.been.called(1); - expect(xhrRequests.length).to.equal(0); - expect(fetch).to.have.been.called.with(v1EventEndpoint +'?test=' + longMessage + '&type=test' , { - cache: 'no-cache', - keepalive: true, - method: 'GET' - }); - }); - it('should send the message directly to the failover XHRPost if too big - Edge', async() => { - const v1EventEndpoint = 'https://participants.evolv.ai/v1/MYUID/events' - const fetch = chai.spy(() => new Promise(resolve => resolve({ok: true}))); - // noinspection JSConstantReassignment - global.window = { - addEventListener: () => null, - fetch: fetch, - navigator: { - userAgent: edgeAgent - } - }; - const beacon = new Beacon(v1EventEndpoint, {uid: ''}, ''); - - let longMessage = ''; - for (let i = 0; i < MICROSOFT_MAX_MESSAGE_SIZE + 1; i++) { - longMessage += 'a'; - } - - beacon.emit('test', { - test: longMessage - }, false); - - await new Promise(resolve => setTimeout(resolve, DELAY + 100)); - - expect(fetch).to.have.been.called(1); - expect(xhrRequests.length).to.equal(0); - expect(fetch).to.have.been.called.with(v1EventEndpoint , { - body: JSON.stringify({ - test: longMessage, - type: 'test' - }), - cache: 'no-cache', - keepalive: true, - method: 'POST' - }); - }); - - it('should send the message directly to the failover XHRPost if too big - Chrome', async() => { - const v1EventEndpoint = 'https://participants.evolv.ai/v1/MYUID/events' - const fetch = chai.spy(() => new Promise(resolve => resolve({ok: true}))); - // noinspection JSConstantReassignment - global.window = { - addEventListener: () => null, - fetch: fetch, - navigator: { - userAgent: chromeAgent - } - }; - const beacon = new Beacon(v1EventEndpoint, {uid: ''}, ''); - - let longMessage = ''; - for (let i = 0; i < DEFAULT_MAX_MESSAGE_SIZE + 1; i++) { - longMessage += 'a'; - } - - beacon.emit('test', { - test: longMessage - }, false); - - await new Promise(resolve => setTimeout(resolve, DELAY + 100)); - - expect(fetch).to.have.been.called(1); - expect(xhrRequests.length).to.equal(0); - expect(fetch).to.have.been.called.with(v1EventEndpoint , { - body: JSON.stringify({ - test: longMessage, - type: 'test' - }), - cache: 'no-cache', - keepalive: true, - method: 'POST' - }); - }); - }); }); }); diff --git a/src/tests/index.test.js b/src/tests/index.test.js index d1247e2..03c614a 100644 --- a/src/tests/index.test.js +++ b/src/tests/index.test.js @@ -59,7 +59,7 @@ async function validateClient(evolv, opts, uid) { expect(contextInitializedSpy).to.not.have.been.called; let analyticsPayloads = []; - let eventPayloads = []; + const beaconHandler = (req, res) => { expect(req.method()).to.equal('POST'); expect(req.header('Content-Type')).to.equal('application/json; charset=UTF-8'); @@ -69,8 +69,6 @@ async function validateClient(evolv, opts, uid) { if (req.url().path.endsWith('data')) { analyticsPayloads.push(data); - } else if (req.url().path.endsWith('events')) { - eventPayloads.push(data); } else { res.status(500); } @@ -79,7 +77,6 @@ async function validateClient(evolv, opts, uid) { xhrMock.post(`${options.endpoint}/${options.environment}/data`, beaconHandler); - xhrMock.post(`${options.endpoint}/${options.environment}/events`, beaconHandler); evolv.initialize(uid, { remote: true, @@ -199,7 +196,7 @@ async function validateClient(evolv, opts, uid) { return new Promise((resolve, reject) => { setTimeout(function() { try { - resolve({analyticsPayloads, eventPayloads}); + resolve({analyticsPayloads}); } catch (ex) { reject(ex); } @@ -589,7 +586,6 @@ describe('Evolv client integration tests', () => { const environment = '579b106c73'; const endpoint = 'https://participants-frazer.evolv.ai/'; const version = 2; - const analytics = true; xhrMock.get(`${endpoint}v${version}/${environment}/${uid}/configuration.json`, (req, res) => { return res.status(200).body(JSON.stringify({ @@ -697,18 +693,12 @@ describe('Evolv client integration tests', () => { const options = { environment, endpoint, - version, - analytics + version }; const evolv = new Evolv(options); const results = await validateClient(evolv, options, uid); - expect(results.eventPayloads.length).to.equal(2) - expect(results.eventPayloads[0].messages[0].type).to.equal("confirmation") - expect(results.eventPayloads[0].messages[0].payload.eid).to.equal("0f39849197") - expect(results.eventPayloads[1].messages[0].type).to.equal("lunch-time") - expect(results.analyticsPayloads.length).to.equal(1); expect(results.analyticsPayloads[0].uid).to.equal(uid); @@ -750,150 +740,6 @@ describe('Evolv client integration tests', () => { expect(messages[16]).to.be.a.message("context.value.changed", "keys.active", []); expect(messages[17]).to.be.a.message("context.value.changed", "variants.active", []); }); - - // TODO AP-2318 bring back when confirmations killed again - xit('should not fire confirmation if session based', async () => { - const uid = 123; - const environment = '579b106c73'; - const endpoint = 'https://participants-frazer.evolv.ai/'; - const version = 2; - const analytics = true; - - xhrMock.get(`${endpoint}v${version}/${environment}/${uid}/configuration.json`, (req, res) => { - return res.status(200).body(JSON.stringify({ - _published: 1584475383.3865728, - _client: {}, - _experiments: [ - { - _optimization_metric: "SESSION", - web: { - "ab8numq2j": { - _is_entry_point: true, - _predicate: { - combinator: "and", - rules: [ - { - field: "web.url", - operator: "regex64_match", - value: "L2h0dHBzPzpcL1wvW14vXStcL2RldjFcL2luZGV4XC5odG1sKD86JHxcP3wjKS9p" - } - ] - }, - am94yhwo2: { - _values: true - } - }, - "7w3zpgfy9": { - _is_entry_point: false, - _predicate: { - combinator: "and", - rules: [ - { - field: "web.url", - operator: "regex64_match", - value: "L2h0dHBzPzpcL1wvW14vXStcL2RldjFcL2ZlYXR1cmVzXC5odG1sKD86JHxcP3wjKS9p" - } - ] - }, - azevlvf5g: { - _values: true - } - } - }, - id: "0f39849197", - _predicate: { - combinator: "and", - rules: [ - { - field: "user_attributes", - operator: "kv_equal", - value: [ - "country", - "usa" - ] - } - ] - } - } - ] - })); - }); - - xhrMock.get(`${endpoint}v${version}/${environment}/${uid}/allocations`, (req, res) => { - return res.status(200).body(JSON.stringify([ - { - uid: uid, - eid: "0f39849197", - cid: "0cf8ffcedea2:0f39849197", - genome: { - web: { - "ab8numq2j": { - am94yhwo2: { - id: "2fxe5dy5j", - type: "compound", - _metadata: { }, - script: "console.log('62px');", - styles: "#ReactLogo { font-size: 62px; }" - } - }, - "7w3zpgfy9": { - azevlvf5g: { - type: "noop" - } - } - } - }, - audience_query: { - id: 1, - name: "USA Users", - combinator: "and", - rules: [ - { - field: "user_attributes", - operator: "kv_equal", - value: [ - "country", - "usa" - ] - } - ] - }, - excluded: false - } - ])); - }); - - const options = { - environment, - endpoint, - version, - analytics - }; - const evolv = new Evolv(options); - - const results = await validateClient(evolv, options, uid); - - expect(results.eventPayloads.length).to.equal(1) - expect(results.eventPayloads[0].messages[0].type).to.equal("lunch-time") - - expect(results.analyticsPayloads.length).to.equal(1); - expect(results.analyticsPayloads[0].uid).to.equal(uid); - - const messages = results.analyticsPayloads[0].messages; - expect(messages.length).to.equal(18) - - expect(messages[9]).to.be.a.messageWithLength("context.value.added", "confirmations", 1); - expect(messages[9].payload.value[0].cid).to.equal("0cf8ffcedea2:0f39849197") - expect(messages[10]).to.be.a.messageWithLength("context.value.added", CONFIRMATIONS_KEY, 1); - expect(messages[10].payload.value[0].cid).to.equal("0cf8ffcedea2:0f39849197") - expect(messages[11]).to.be.a.messageWithLength("context.value.added", "events", 1); - expect(messages[11].payload.value[0].type).to.equal("lunch-time") - expect(messages[12]).to.be.a.messageWithLength("context.value.added", "contaminations", 1); - expect(messages[12].payload.value[0].cid).to.equal("0cf8ffcedea2:0f39849197") - expect(messages[13]).to.be.a.messageWithLength("context.value.added", "experiments.contaminations", 1); - expect(messages[13].payload.value[0].cid).to.equal("0cf8ffcedea2:0f39849197") - expect(messages[14].type).to.equal("context.value.changed") - }); }); describe('prevent beacon', () => { @@ -902,7 +748,6 @@ describe('Evolv client integration tests', () => { const environment = '579b106c73'; const endpoint = 'https://participants-frazer.evolv.ai/'; const version = 2; - const analytics = true; xhrMock.get(`${endpoint}v${version}/${environment}/${uid}/configuration.json`, (req, res) => { return res.status(200).body(JSON.stringify({ @@ -1011,7 +856,6 @@ describe('Evolv client integration tests', () => { environment, endpoint, version, - analytics, bufferEvents: true }; const evolv = new Evolv(options); @@ -1019,7 +863,6 @@ describe('Evolv client integration tests', () => { const results = await validateClient(evolv, options, uid); expect(results.analyticsPayloads.length).to.equal(0); - expect(results.eventPayloads.length).to.equal(0); evolv.allowEvents(); @@ -1037,11 +880,6 @@ describe('Evolv client integration tests', () => { "url": "https://www.lunch.com/dev1/index.html" } }); - - expect(results.eventPayloads.length).to.equal(1); - const eventsMessages = results.eventPayloads[0].messages; - expect(eventsMessages.length).to.equal(3); - expect(eventsMessages[0].type).to.equal("confirmation"); }); }); }); @@ -1311,35 +1149,6 @@ describe('Evolv client unit tests', () => { expect(correctlyErrored).to.be.equal(true); }); - it('should should send the contamination details to the events endpoint', (done) => { - store.activeEntryPoints = () => new Promise((resolve) => { resolve(['1234']) }); - Object.defineProperty(store, 'configuration', { get: function() { return { foo: 'bar' }; }, }); - Object.defineProperty(store, 'activeEids', { get: function() { return new Set(['1234']); } }); - options.store = store; - - let contaminationDetails = { - reason: 'broken', - details: 'mistake' - }; - - context.initialize(); - context.set("experiments.allocations", [{eid: '1234', cid: '5678'}]); - options.context = context; - options.beacon = { - emit: function(type, details) { - expect(details.contaminationReason).to.equal(contaminationDetails); - done(); - } - }; - - const client = new Evolv(options); - - client.contaminate(contaminationDetails); - - expect(context.remoteContext.contaminations).to.be.lengthOf(1); - expect(context.remoteContext.contaminations[0].cid).to.be.equal('5678'); - }); - it('should not confirm into allocated experiments that have been contaminated', (done) => { store.activeEntryPoints = () => new Promise((resolve) => { resolve(['1234']) }); Object.defineProperty(store, 'configuration', { get: function() { return { foo: 'bar' }; }, }); diff --git a/src/types.d.ts b/src/types.d.ts index d6f684f..6f4217c 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -39,7 +39,6 @@ export interface EvolvClientOptions { pushstate?: boolean; version?: number; autoConfirm?: boolean; - analytics?: boolean; bufferEvents?: boolean; clientName?: string; clientType?: 'direct' | 'proxied';