From 72ba13923f20fbc73eefa7fc08bd4729244ffe77 Mon Sep 17 00:00:00 2001 From: Brie Date: Fri, 15 May 2020 15:18:35 -0700 Subject: [PATCH 01/11] Add event names to top level property list --- integrations/adobe-analytics/lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 8c1274fa8..84073d524 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -821,7 +821,7 @@ function extractProperties(facade, options, propType) { options.contextValues ]; - var topLevelProperties = ['messageId', 'anonymousId']; + var topLevelProperties = ['messageId', 'anonymousId', 'event']; var props = facade.properties(); if (propType === 'mergedPropContext') { From f643606edc651f4b878dcb058e98f1adf5c4d372 Mon Sep 17 00:00:00 2001 From: Brie Date: Fri, 15 May 2020 15:19:06 -0700 Subject: [PATCH 02/11] Update unit tests --- .../adobe-analytics/test/index.test.js | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/integrations/adobe-analytics/test/index.test.js b/integrations/adobe-analytics/test/index.test.js index 6782f03a6..d1c3fdb23 100644 --- a/integrations/adobe-analytics/test/index.test.js +++ b/integrations/adobe-analytics/test/index.test.js @@ -229,22 +229,25 @@ describe('Adobe Analytics', function() { analytics.called(window.s.tl, true, 'o', 'Overlord exploded'); }); - it('should track set top level fields (msgId and anonId) set as eVars properly', function() { + it('should track set top level fields (msgId, anonId, event) set as eVars properly', function() { adobeAnalytics.options.eVars = { messageId: 'eVar2', - anonymousId: 'eVar3' + anonymousId: 'eVar3', + event: 'eVar4' }; analytics.track('Overlord exploded'); analytics.equal(window.s.events, 'event7'); analytics.assert(window.s.eVar2); analytics.assert(window.s.eVar3); + analytics.assert(window.s.eVar4); analytics.assert( contains( window.s.linkTrackVars, 'events', 'timestamp', 'eVar2', - 'eVar3' + 'eVar3', + 'eVar4' ) ); analytics.called(window.s.tl, true, 'o', 'Overlord exploded'); @@ -275,22 +278,25 @@ describe('Adobe Analytics', function() { analytics.called(window.s.tl, true, 'o', 'Drank Some Milk'); }); - it('should track set top level fields (msgId and anonId) set as props properly', function() { + it('should track set top level fields (msgId, anonId, event) set as props properly', function() { adobeAnalytics.options.eVars = { messageId: 'prop1', - anonymousId: 'prop2' + anonymousId: 'prop2', + event: 'prop3' }; analytics.track('Overlord exploded'); analytics.equal(window.s.events, 'event7'); analytics.assert(window.s.prop1); analytics.assert(window.s.prop2); + analytics.assert(window.s.prop3); analytics.assert( contains( window.s.linkTrackVars, 'events', 'timestamp', 'prop1', - 'prop2' + 'prop2', + 'prop3' ) ); analytics.called(window.s.tl, true, 'o', 'Overlord exploded'); @@ -314,14 +320,16 @@ describe('Adobe Analytics', function() { analytics.called(window.s.tl); }); - it('should send top level fields (msgId & anonId) as context properties', function() { + it('should send top level fields (msgId, anonId, event) as context properties', function() { adobeAnalytics.options.contextValues = { messageId: 'messageIdAdobe', - anonymousId: 'anonymousIdAdobe' + anonymousId: 'anonymousIdAdobe', + event: 'adobeEvent' }; analytics.track('Drank Some Milk', { foo: 'bar' }); analytics.assert(window.s.contextData.messageIdAdobe); analytics.assert(window.s.contextData.anonymousIdAdobe); + analytics.assert(window.s.contextData.adobeEvent); analytics.called(window.s.tl); }); @@ -1203,10 +1211,11 @@ describe('Adobe Analytics', function() { analytics.called(window.s.t); }); - it('tracks top level fields (msgId & anonId) as mapped properties', function() { + it('tracks top level fields (msgId, anonId, event) as mapped properties', function() { adobeAnalytics.options.props = { anonymousId: 'prop1', - messageId: 'prop2' + messageId: 'prop2', + event: 'prop3' }; analytics.page('Drank Some Milk', { type: '2%', @@ -1216,6 +1225,7 @@ describe('Adobe Analytics', function() { analytics.equal(window.s.pageName, 'Drank Some Milk'); analytics.assert(window.s.prop1); analytics.assert(window.s.prop2); + analytics.assert(window.s.prop3); analytics.called(window.s.t); }); @@ -1241,14 +1251,16 @@ describe('Adobe Analytics', function() { analytics.called(window.s.t); }); - it('should send top level fields (msgId & anonId) as context properties', function() { + it('should send top level fields (msgId, anonId, event) as context properties', function() { adobeAnalytics.options.contextValues = { anonymousId: 'anonymousId', - messageId: 'messageId' + messageId: 'messageId', + event: 'eventContextData' }; analytics.page('Page1', {}); analytics.assert(window.s.contextData.anonymousId); analytics.assert(window.s.contextData.messageId); + analytics.assert(window.s.contextData.eventContextData); analytics.called(window.s.t); }); From 86ab8d09f3d5e1b227b97574eca8763cdc16972e Mon Sep 17 00:00:00 2001 From: Brie Date: Fri, 15 May 2020 15:20:15 -0700 Subject: [PATCH 03/11] Update HISTORY.md and package.json --- integrations/adobe-analytics/HISTORY.md | 4 ++++ integrations/adobe-analytics/package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/HISTORY.md b/integrations/adobe-analytics/HISTORY.md index d7656716e..e16b2a8d4 100644 --- a/integrations/adobe-analytics/HISTORY.md +++ b/integrations/adobe-analytics/HISTORY.md @@ -1,3 +1,7 @@ +1.16.1 / 2020-05-15 +=================== +* Supports sending top level `event` as `prop`, `eVar`, `lVar`, `hVar`, or Context Data Variable. + 1.16.0 / 2020-05-05 =================== * Supports sending top level `messageId` and `anonymousId` as `prop`, `eVar`, `lVar`, `hVar`, or Context Data Variable. diff --git a/integrations/adobe-analytics/package.json b/integrations/adobe-analytics/package.json index edb80264e..9321ac1c7 100644 --- a/integrations/adobe-analytics/package.json +++ b/integrations/adobe-analytics/package.json @@ -1,7 +1,7 @@ { "name": "@segment/analytics.js-integration-adobe-analytics", "description": "The Adobe Analytics analytics.js integration.", - "version": "1.16.0", + "version": "1.16.1", "keywords": [ "analytics.js", "analytics.js-integration", From d76aa96fbbcb2abe9b47f7f37167ff63fa78f4fe Mon Sep 17 00:00:00 2001 From: Gabriel P Samson Date: Sun, 17 May 2020 21:32:05 -0700 Subject: [PATCH 04/11] AA: Add window based playheads --- integrations/adobe-analytics/lib/index.js | 16 ++++++++++++++- .../adobe-analytics/test/index.test.js | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 84073d524..d181b2972 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -135,6 +135,10 @@ AdobeAnalytics.prototype.initialize = function() { // In case this has been defined already window.s_account = window.s_account || options.reportSuiteId; + // Initialize a window object that can be used to update the playhead value of a session + // WITHOUT sending several 'Video Content Playing' events. (see line 1242) + window._segHBPlayheads = {}; + // Load the larger Heartbeat script only if the customer has it enabled in settings. // This file is considerably bigger, so this check is necessary. if (options.heartbeatTrackingServerUrl) { @@ -1236,7 +1240,17 @@ function initHeartbeat(track) { mediaHeartbeatConfig.debugLogging = !!window._enableHeartbeatDebugLogging; // Optional beta flag for seeing debug output. mediaHeartbeatDelegate.getCurrentPlaybackTime = function() { - return self.playhead || 0; // TODO: Bind to the Heartbeat events we have specced. + var playhead = self.playhead || 0; + + // We allow implementions to set the playhead value of a video session on a shared + // window object. This allows us to relay the playhead to AA's heartbeat SDK several + // times a second, without relying on a 'Video Content Playing' event to update the position. + var sessions = window._segHBPlayheads || {}; + if (sessions[props.session_id]) { + playhead = sessions[props.session_id]; + } + + return playhead; }; mediaHeartbeatDelegate.getQoSObject = function() { diff --git a/integrations/adobe-analytics/test/index.test.js b/integrations/adobe-analytics/test/index.test.js index d1c3fdb23..5880c4da8 100644 --- a/integrations/adobe-analytics/test/index.test.js +++ b/integrations/adobe-analytics/test/index.test.js @@ -1833,6 +1833,26 @@ describe('Adobe Analytics', function() { 'trackPause' ); }); + + it('should return the playhead value from the window object', function() { + analytics.track('Video Playback Started', { + session_id: sessionId, + channel: 'Black Mesa', + video_player: 'Transit Announcement System', + playhead: 5, + asset_id: 'Gordon Freeman', + title: 'Half-Life', + total_length: 1260, + livestream: false + }); + + window._segHBPlayheads[sessionId] = 5.111; + + var actual = adobeAnalytics.mediaHeartbeats[ + sessionId + ].delegate.getCurrentPlaybackTime(); + analytics.assert(actual, 5.111); + }); }); }); }); From 99453967fbc65f357f12d919d8c9a94d51162f8b Mon Sep 17 00:00:00 2001 From: Gabriel P Samson Date: Sun, 17 May 2020 21:36:31 -0700 Subject: [PATCH 05/11] Bump AA version --- integrations/adobe-analytics/HISTORY.md | 4 ++++ integrations/adobe-analytics/package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/HISTORY.md b/integrations/adobe-analytics/HISTORY.md index e16b2a8d4..72f1eb3bf 100644 --- a/integrations/adobe-analytics/HISTORY.md +++ b/integrations/adobe-analytics/HISTORY.md @@ -1,3 +1,7 @@ +1.16.2 / 2020-05-17 +=================== +* Reads session playhead values from `window._segHBPlayheads` if it exists. This solves an issue where the playhead is only updated when 'Video Content Playing' (+ various others) events are tracked. To get around this, we allow video implementations to set the playhead value as often as possible without the need to trigger an event. + 1.16.1 / 2020-05-15 =================== * Supports sending top level `event` as `prop`, `eVar`, `lVar`, `hVar`, or Context Data Variable. diff --git a/integrations/adobe-analytics/package.json b/integrations/adobe-analytics/package.json index 9321ac1c7..3b24c3dc4 100644 --- a/integrations/adobe-analytics/package.json +++ b/integrations/adobe-analytics/package.json @@ -1,7 +1,7 @@ { "name": "@segment/analytics.js-integration-adobe-analytics", "description": "The Adobe Analytics analytics.js integration.", - "version": "1.16.1", + "version": "1.16.2", "keywords": [ "analytics.js", "analytics.js-integration", From bb8467ca2a8d03255298181b202322c9292adc26 Mon Sep 17 00:00:00 2001 From: Kiara Daswani Date: Wed, 24 Jun 2020 17:08:24 -0700 Subject: [PATCH 06/11] [STRATCONN-272] update trackComplete logic on video events --- integrations/adobe-analytics/lib/index.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 84073d524..0f86cb92c 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -1317,9 +1317,7 @@ function heartbeatVideoStart(track) { chapterObj, chapterCustomMetadata ); - this.mediaHeartbeats[ - props.session_id || 'default' - ].chapterInProgress = true; + this.mediaHeartbeats[props.session_id || 'default'].chapterInProgress = true; } } @@ -1332,8 +1330,6 @@ function heartbeatVideoComplete(track) { videoAnalytics.MediaHeartbeat.Event.ChapterComplete ); this.mediaHeartbeats[props.session_id || 'default'].chapterInProgress = false; - - this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackComplete(); } function heartbeatVideoPaused(track) { @@ -1347,9 +1343,8 @@ function heartbeatSessionEnd(track) { populateHeartbeat.call(this, track); var props = track.properties(); - this.mediaHeartbeats[ - props.session_id || 'default' - ].heartbeat.trackSessionEnd(); + this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackComplete(); + this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackSessionEnd(); // Remove the session from memory when it's all over. delete this.mediaHeartbeats[props.session_id || 'default']; From 6d64aa007cd6f7c2cf97017797c2fda146884784 Mon Sep 17 00:00:00 2001 From: Gabriel P Samson Date: Fri, 26 Jun 2020 13:37:29 -0700 Subject: [PATCH 07/11] Update tests --- integrations/adobe-analytics/test/index.test.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/integrations/adobe-analytics/test/index.test.js b/integrations/adobe-analytics/test/index.test.js index d1c3fdb23..5b4a500ee 100644 --- a/integrations/adobe-analytics/test/index.test.js +++ b/integrations/adobe-analytics/test/index.test.js @@ -1592,7 +1592,7 @@ describe('Adobe Analytics', function() { ); }); - it('should call trackComplete when a video completes', function() { + it('should set chapterInProgress when a video completes', function() { analytics.track('Video Playback Started', { session_id: sessionId, channel: 'Black Mesa', @@ -1606,7 +1606,7 @@ describe('Adobe Analytics', function() { analytics.stub( adobeAnalytics.mediaHeartbeats[sessionId].heartbeat, - 'trackComplete' + 'trackEvent' ); analytics.track('Video Content Completed', { @@ -1621,7 +1621,12 @@ describe('Adobe Analytics', function() { }); analytics.called( - adobeAnalytics.mediaHeartbeats[sessionId].heartbeat.trackComplete + adobeAnalytics.mediaHeartbeats[sessionId].heartbeat.trackEvent, + window.ADB.va.MediaHeartbeat.Event.ChapterComplete + ); + analytics.equal( + false, + adobeAnalytics.mediaHeartbeats[sessionId].chapterInProgress ); }); @@ -1658,7 +1663,7 @@ describe('Adobe Analytics', function() { ); }); - it('should delete the instance when the session is over', function() { + it('should call final hb methods and delete the instance when the session is over', function() { analytics.track('Video Playback Started', { session_id: sessionId, channel: 'Black Mesa', @@ -1674,6 +1679,7 @@ describe('Adobe Analytics', function() { // We need to save this reference for the upcoming check, since we delete the higher property after the next call. var heartbeatRef = adobeAnalytics.mediaHeartbeats[sessionId].heartbeat; + analytics.stub(heartbeatRef, 'trackComplete'); analytics.stub(heartbeatRef, 'trackSessionEnd'); analytics.track('Video Playback Completed', { @@ -1687,8 +1693,9 @@ describe('Adobe Analytics', function() { livestream: false }); - analytics.assert(!adobeAnalytics.mediaHeartbeats[sessionId]); + analytics.called(heartbeatRef.trackComplete); analytics.called(heartbeatRef.trackSessionEnd); + analytics.assert(!adobeAnalytics.mediaHeartbeats[sessionId]); }); it('should start an Ad Break and Ad Tracking when an ad starts', function() { From cda242bb70200c214a05c396cc188b02f973b19b Mon Sep 17 00:00:00 2001 From: Gabriel Samson Date: Fri, 26 Jun 2020 14:39:13 -0700 Subject: [PATCH 08/11] Gps/aa bools (#489) * Stringify context vals of type bool * Add tests * LINT --- integrations/adobe-analytics/lib/index.js | 8 +++++++ .../adobe-analytics/test/index.test.js | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 0f86cb92c..a1b110cf6 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -620,6 +620,14 @@ function updateContextData(facade, options) { return; } + // If context data values are booleans then stringify them. + // Adobe's SDK seems to reject a false boolean value. Stringifying is + // acceptable since these values are appended as query strings anyway. + if (typeof value === 'boolean') { + addContextDatum(key, value.toString()); + return; + } + addContextDatum(key, value); }, contextProperties); } diff --git a/integrations/adobe-analytics/test/index.test.js b/integrations/adobe-analytics/test/index.test.js index 5b4a500ee..a3c85bace 100644 --- a/integrations/adobe-analytics/test/index.test.js +++ b/integrations/adobe-analytics/test/index.test.js @@ -1175,6 +1175,30 @@ describe('Adobe Analytics', function() { }); analytics.equal(window.s.events, 'prodView,event1,event38'); }); + + it('should stringify bool context data', function() { + adobeAnalytics.options.contextValues = { + 'page.referrer': 'page.referrer', + 'page.url': 'page.title', + 'page.bickenBack': 'page.bickenBack' + }; + analytics.track( + 'Drank Some Milk', + { foo: 'bar' }, + { page: { bickenBack: false } } + ); + analytics.equal( + window.s.contextData['page.referrer'], + window.document.referrer + ); + analytics.equal( + window.s.contextData['page.title'], + window.location.href + ); + analytics.equal(window.s.contextData['page.bickenBack'], 'false'); + analytics.equal(window.s.contextData.foo, 'bar'); + analytics.called(window.s.tl); + }); }); }); From cfe4fbcf48767f684fd9b8798fe321efa9c62569 Mon Sep 17 00:00:00 2001 From: Gabriel P Samson Date: Mon, 29 Jun 2020 16:47:48 -0700 Subject: [PATCH 09/11] Stringify bools in createCustomVideoMetadataContext --- integrations/adobe-analytics/lib/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 23285c429..980feb9af 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -1531,6 +1531,15 @@ function createCustomVideoMetadataContext(track, options) { if (!key || value === undefined || value === null || value === '') { return; } + + // If context data values are booleans then stringify them. + // Adobe's SDK seems to reject a false boolean value. Stringifying is + // acceptable since these values are appended as query strings anyway. + if (typeof value === 'boolean') { + addContextDatum(key, value.toString()); + return; + } + contextData[key] = value; }, extractedProperties); return contextData; From 3c4503125de78dbd42c80dee68184fe07cc9ce53 Mon Sep 17 00:00:00 2001 From: Gabriel P Samson Date: Mon, 29 Jun 2020 18:41:53 -0700 Subject: [PATCH 10/11] Fix setter in createCustomVideoMetadataContext --- integrations/adobe-analytics/lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/lib/index.js b/integrations/adobe-analytics/lib/index.js index 980feb9af..dbd35942d 100644 --- a/integrations/adobe-analytics/lib/index.js +++ b/integrations/adobe-analytics/lib/index.js @@ -1536,7 +1536,7 @@ function createCustomVideoMetadataContext(track, options) { // Adobe's SDK seems to reject a false boolean value. Stringifying is // acceptable since these values are appended as query strings anyway. if (typeof value === 'boolean') { - addContextDatum(key, value.toString()); + contextData[key] = value.toString(); return; } From a38e1803dc62b9ce17be6b6eb4d9d3cee0d5b948 Mon Sep 17 00:00:00 2001 From: Gabriel Samson Date: Mon, 13 Jul 2020 15:20:45 -0700 Subject: [PATCH 11/11] Update HISTORY.md --- integrations/adobe-analytics/HISTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integrations/adobe-analytics/HISTORY.md b/integrations/adobe-analytics/HISTORY.md index 72f1eb3bf..4d81820a2 100644 --- a/integrations/adobe-analytics/HISTORY.md +++ b/integrations/adobe-analytics/HISTORY.md @@ -1,6 +1,8 @@ -1.16.2 / 2020-05-17 +1.16.2 / 2020-07-13 =================== * Reads session playhead values from `window._segHBPlayheads` if it exists. This solves an issue where the playhead is only updated when 'Video Content Playing' (+ various others) events are tracked. To get around this, we allow video implementations to set the playhead value as often as possible without the need to trigger an event. +* Removes trackComplete from Video Content Completed events and only calls chapterComplete on these events. It also adds trackComplete to Video Playback Completed events. This is in line with Adobe's documentation and also allows for parity between iOS, a.js, and Android. +* Stringifies context data values which are booleans. The AA SDK tends to reject false boolean values when setting them on the window object. This does not break existing behavior since booleans are stringified when they're sent in the query string. 1.16.1 / 2020-05-15 ===================