Skip to content

Commit 32b6ab4

Browse files
kdaswaniBrieGabriel P SamsonKiara Daswanigpsamson
authored
[STRATCONN-272, STRATCONN-265] Update trackComplete, Stringify context data, Support window-based playhead (#484)
* Add event names to top level property list * Update unit tests * Update HISTORY.md and package.json * AA: Add window based playheads * Bump AA version * [STRATCONN-272] update trackComplete logic on video events * Update tests * Gps/aa bools (#489) * Stringify context vals of type bool * Add tests * LINT * Stringify bools in createCustomVideoMetadataContext * Fix setter in createCustomVideoMetadataContext * Update HISTORY.md Co-authored-by: Brie <brienne.mcnally@segment.com> Co-authored-by: Gabriel P Samson <gabriel.samson@segment.com> Co-authored-by: Kiara Daswani <kiara.daswani@Kiaras-MBP.lan> Co-authored-by: Gabriel Samson <gpsamson@users.noreply.github.com>
1 parent d85d089 commit 32b6ab4

File tree

4 files changed

+98
-15
lines changed

4 files changed

+98
-15
lines changed

integrations/adobe-analytics/HISTORY.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
1.16.2 / 2020-07-13
2+
===================
3+
* 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.
4+
* 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.
5+
* 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.
6+
17
1.16.1 / 2020-05-15
28
===================
39
* Supports sending top level `event` as `prop`, `eVar`, `lVar`, `hVar`, or Context Data Variable.

integrations/adobe-analytics/lib/index.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ AdobeAnalytics.prototype.initialize = function() {
135135
// In case this has been defined already
136136
window.s_account = window.s_account || options.reportSuiteId;
137137

138+
// Initialize a window object that can be used to update the playhead value of a session
139+
// WITHOUT sending several 'Video Content Playing' events. (see line 1242)
140+
window._segHBPlayheads = {};
141+
138142
// Load the larger Heartbeat script only if the customer has it enabled in settings.
139143
// This file is considerably bigger, so this check is necessary.
140144
if (options.heartbeatTrackingServerUrl) {
@@ -620,6 +624,14 @@ function updateContextData(facade, options) {
620624
return;
621625
}
622626

627+
// If context data values are booleans then stringify them.
628+
// Adobe's SDK seems to reject a false boolean value. Stringifying is
629+
// acceptable since these values are appended as query strings anyway.
630+
if (typeof value === 'boolean') {
631+
addContextDatum(key, value.toString());
632+
return;
633+
}
634+
623635
addContextDatum(key, value);
624636
}, contextProperties);
625637
}
@@ -1236,7 +1248,17 @@ function initHeartbeat(track) {
12361248
mediaHeartbeatConfig.debugLogging = !!window._enableHeartbeatDebugLogging; // Optional beta flag for seeing debug output.
12371249

12381250
mediaHeartbeatDelegate.getCurrentPlaybackTime = function() {
1239-
return self.playhead || 0; // TODO: Bind to the Heartbeat events we have specced.
1251+
var playhead = self.playhead || 0;
1252+
1253+
// We allow implementions to set the playhead value of a video session on a shared
1254+
// window object. This allows us to relay the playhead to AA's heartbeat SDK several
1255+
// times a second, without relying on a 'Video Content Playing' event to update the position.
1256+
var sessions = window._segHBPlayheads || {};
1257+
if (sessions[props.session_id]) {
1258+
playhead = sessions[props.session_id];
1259+
}
1260+
1261+
return playhead;
12401262
};
12411263

12421264
mediaHeartbeatDelegate.getQoSObject = function() {
@@ -1317,9 +1339,7 @@ function heartbeatVideoStart(track) {
13171339
chapterObj,
13181340
chapterCustomMetadata
13191341
);
1320-
this.mediaHeartbeats[
1321-
props.session_id || 'default'
1322-
].chapterInProgress = true;
1342+
this.mediaHeartbeats[props.session_id || 'default'].chapterInProgress = true;
13231343
}
13241344
}
13251345

@@ -1332,8 +1352,6 @@ function heartbeatVideoComplete(track) {
13321352
videoAnalytics.MediaHeartbeat.Event.ChapterComplete
13331353
);
13341354
this.mediaHeartbeats[props.session_id || 'default'].chapterInProgress = false;
1335-
1336-
this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackComplete();
13371355
}
13381356

13391357
function heartbeatVideoPaused(track) {
@@ -1347,9 +1365,8 @@ function heartbeatSessionEnd(track) {
13471365
populateHeartbeat.call(this, track);
13481366

13491367
var props = track.properties();
1350-
this.mediaHeartbeats[
1351-
props.session_id || 'default'
1352-
].heartbeat.trackSessionEnd();
1368+
this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackComplete();
1369+
this.mediaHeartbeats[props.session_id || 'default'].heartbeat.trackSessionEnd();
13531370

13541371
// Remove the session from memory when it's all over.
13551372
delete this.mediaHeartbeats[props.session_id || 'default'];
@@ -1514,6 +1531,15 @@ function createCustomVideoMetadataContext(track, options) {
15141531
if (!key || value === undefined || value === null || value === '') {
15151532
return;
15161533
}
1534+
1535+
// If context data values are booleans then stringify them.
1536+
// Adobe's SDK seems to reject a false boolean value. Stringifying is
1537+
// acceptable since these values are appended as query strings anyway.
1538+
if (typeof value === 'boolean') {
1539+
contextData[key] = value.toString();
1540+
return;
1541+
}
1542+
15171543
contextData[key] = value;
15181544
}, extractedProperties);
15191545
return contextData;

integrations/adobe-analytics/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@segment/analytics.js-integration-adobe-analytics",
33
"description": "The Adobe Analytics analytics.js integration.",
4-
"version": "1.16.1",
4+
"version": "1.16.2",
55
"keywords": [
66
"analytics.js",
77
"analytics.js-integration",

integrations/adobe-analytics/test/index.test.js

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,30 @@ describe('Adobe Analytics', function() {
11751175
});
11761176
analytics.equal(window.s.events, 'prodView,event1,event38');
11771177
});
1178+
1179+
it('should stringify bool context data', function() {
1180+
adobeAnalytics.options.contextValues = {
1181+
'page.referrer': 'page.referrer',
1182+
'page.url': 'page.title',
1183+
'page.bickenBack': 'page.bickenBack'
1184+
};
1185+
analytics.track(
1186+
'Drank Some Milk',
1187+
{ foo: 'bar' },
1188+
{ page: { bickenBack: false } }
1189+
);
1190+
analytics.equal(
1191+
window.s.contextData['page.referrer'],
1192+
window.document.referrer
1193+
);
1194+
analytics.equal(
1195+
window.s.contextData['page.title'],
1196+
window.location.href
1197+
);
1198+
analytics.equal(window.s.contextData['page.bickenBack'], 'false');
1199+
analytics.equal(window.s.contextData.foo, 'bar');
1200+
analytics.called(window.s.tl);
1201+
});
11781202
});
11791203
});
11801204

@@ -1592,7 +1616,7 @@ describe('Adobe Analytics', function() {
15921616
);
15931617
});
15941618

1595-
it('should call trackComplete when a video completes', function() {
1619+
it('should set chapterInProgress when a video completes', function() {
15961620
analytics.track('Video Playback Started', {
15971621
session_id: sessionId,
15981622
channel: 'Black Mesa',
@@ -1606,7 +1630,7 @@ describe('Adobe Analytics', function() {
16061630

16071631
analytics.stub(
16081632
adobeAnalytics.mediaHeartbeats[sessionId].heartbeat,
1609-
'trackComplete'
1633+
'trackEvent'
16101634
);
16111635

16121636
analytics.track('Video Content Completed', {
@@ -1621,7 +1645,12 @@ describe('Adobe Analytics', function() {
16211645
});
16221646

16231647
analytics.called(
1624-
adobeAnalytics.mediaHeartbeats[sessionId].heartbeat.trackComplete
1648+
adobeAnalytics.mediaHeartbeats[sessionId].heartbeat.trackEvent,
1649+
window.ADB.va.MediaHeartbeat.Event.ChapterComplete
1650+
);
1651+
analytics.equal(
1652+
false,
1653+
adobeAnalytics.mediaHeartbeats[sessionId].chapterInProgress
16251654
);
16261655
});
16271656

@@ -1658,7 +1687,7 @@ describe('Adobe Analytics', function() {
16581687
);
16591688
});
16601689

1661-
it('should delete the instance when the session is over', function() {
1690+
it('should call final hb methods and delete the instance when the session is over', function() {
16621691
analytics.track('Video Playback Started', {
16631692
session_id: sessionId,
16641693
channel: 'Black Mesa',
@@ -1674,6 +1703,7 @@ describe('Adobe Analytics', function() {
16741703

16751704
// We need to save this reference for the upcoming check, since we delete the higher property after the next call.
16761705
var heartbeatRef = adobeAnalytics.mediaHeartbeats[sessionId].heartbeat;
1706+
analytics.stub(heartbeatRef, 'trackComplete');
16771707
analytics.stub(heartbeatRef, 'trackSessionEnd');
16781708

16791709
analytics.track('Video Playback Completed', {
@@ -1687,8 +1717,9 @@ describe('Adobe Analytics', function() {
16871717
livestream: false
16881718
});
16891719

1690-
analytics.assert(!adobeAnalytics.mediaHeartbeats[sessionId]);
1720+
analytics.called(heartbeatRef.trackComplete);
16911721
analytics.called(heartbeatRef.trackSessionEnd);
1722+
analytics.assert(!adobeAnalytics.mediaHeartbeats[sessionId]);
16921723
});
16931724

16941725
it('should start an Ad Break and Ad Tracking when an ad starts', function() {
@@ -1833,6 +1864,26 @@ describe('Adobe Analytics', function() {
18331864
'trackPause'
18341865
);
18351866
});
1867+
1868+
it('should return the playhead value from the window object', function() {
1869+
analytics.track('Video Playback Started', {
1870+
session_id: sessionId,
1871+
channel: 'Black Mesa',
1872+
video_player: 'Transit Announcement System',
1873+
playhead: 5,
1874+
asset_id: 'Gordon Freeman',
1875+
title: 'Half-Life',
1876+
total_length: 1260,
1877+
livestream: false
1878+
});
1879+
1880+
window._segHBPlayheads[sessionId] = 5.111;
1881+
1882+
var actual = adobeAnalytics.mediaHeartbeats[
1883+
sessionId
1884+
].delegate.getCurrentPlaybackTime();
1885+
analytics.assert(actual, 5.111);
1886+
});
18361887
});
18371888
});
18381889
});

0 commit comments

Comments
 (0)