From ef5d4f29df176abb51c13d2104d20149a8ba5834 Mon Sep 17 00:00:00 2001 From: Olivier Date: Fri, 5 Jul 2024 21:41:04 +0200 Subject: [PATCH] AdagioRtdProvider: add support for AB Testing (#11935) --- modules/adagioRtdProvider.js | 22 +++++-- test/spec/modules/adagioRtdProvider_spec.js | 72 +++++++++++++++++++++ 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/modules/adagioRtdProvider.js b/modules/adagioRtdProvider.js index 2c6628eb8460..91f446e68fd6 100644 --- a/modules/adagioRtdProvider.js +++ b/modules/adagioRtdProvider.js @@ -73,20 +73,34 @@ const _SESSION = (function() { storage.getDataFromLocalStorage('adagio', (storageValue) => { // session can be an empty object - const { rnd, new: isNew, vwSmplg, vwSmplgNxt, lastActivityTime } = _internal.getSessionFromLocalStorage(storageValue); + const { rnd, new: isNew = false, vwSmplg, vwSmplgNxt, lastActivityTime, id, testName, testVersion, initiator } = _internal.getSessionFromLocalStorage(storageValue); + + // isNew can be `true` if the session has been initialized by the A/B test snippet (external) + const isNewSess = (initiator === 'snippet') ? isNew : isNewSession(lastActivityTime); data.session = { rnd, - new: isNew || false, // legacy: `new` was used but the choosen name is not good. + new: isNewSess, // legacy: `new` was used but the choosen name is not good. // Don't use values if they are not defined. ...(vwSmplg !== undefined && { vwSmplg }), ...(vwSmplgNxt !== undefined && { vwSmplgNxt }), - ...(lastActivityTime !== undefined && { lastActivityTime }) + ...(lastActivityTime !== undefined && { lastActivityTime }), + ...(id !== undefined && { id }), + ...(testName !== undefined && { testName }), + ...(testVersion !== undefined && { testVersion }), + ...(initiator !== undefined && { initiator }), }; - if (isNewSession(lastActivityTime)) { + // `initiator` is a pseudo flag used to know if the session has been initialized by the A/B test snippet (external). + // If the AB Test snippet has not been used, then `initiator` value is `adgjs` or `undefined`. + // The check on `testName` is used to ensure that the A/B test values are removed. + if (initiator !== 'snippet' && (isNewSess || testName)) { data.session.new = true; + data.session.id = generateUUID(); data.session.rnd = Math.random(); + // Ensure that the A/B test values are removed. + delete data.session.testName; + delete data.session.testVersion; } _internal.getAdagioNs().queue.push({ diff --git a/test/spec/modules/adagioRtdProvider_spec.js b/test/spec/modules/adagioRtdProvider_spec.js index 3fbd1ca20e85..6dbe4b349853 100644 --- a/test/spec/modules/adagioRtdProvider_spec.js +++ b/test/spec/modules/adagioRtdProvider_spec.js @@ -118,6 +118,7 @@ describe('Adagio Rtd Provider', function () { describe('store session data in localStorage', function () { const session = { lastActivityTime: 1714116520700, + id: 'uid-1234', rnd: 0.5697, vwSmplg: 0.1, vwSmplgNxt: 0.1 @@ -128,6 +129,7 @@ describe('Adagio Rtd Provider', function () { sandbox.stub(storage, 'getDataFromLocalStorage').callsArgWith(1, storageValue); sandbox.stub(Date, 'now').returns(1714116520710); sandbox.stub(Math, 'random').returns(0.8); + sandbox.stub(utils, 'generateUUID').returns('uid-1234'); const spy = sandbox.spy(_internal.getAdagioNs().queue, 'push') @@ -136,6 +138,7 @@ describe('Adagio Rtd Provider', function () { const expected = { session: { new: true, + id: utils.generateUUID(), rnd: Math.random() } } @@ -176,6 +179,7 @@ describe('Adagio Rtd Provider', function () { sandbox.stub(Date, 'now').returns(1715679344351); sandbox.stub(storage, 'getDataFromLocalStorage').callsArgWith(1, storageValue); sandbox.stub(Math, 'random').returns(0.8); + sandbox.stub(utils, 'generateUUID').returns('uid-5678'); const spy = sandbox.spy(_internal.getAdagioNs().queue, 'push') @@ -185,6 +189,7 @@ describe('Adagio Rtd Provider', function () { session: { ...session, new: true, + id: utils.generateUUID(), rnd: Math.random(), } } @@ -196,6 +201,73 @@ describe('Adagio Rtd Provider', function () { }).calledOnce).to.be.true; }); }); + + describe('store session data in localStorage when used with external AB Test snippet', function () { + const sessionWithABTest = { + lastActivityTime: 1714116520700, + id: 'uid-1234', + rnd: 0.5697, + vwSmplg: 0.1, + vwSmplgNxt: 0.1, + testName: 'adg-test', + testVersion: 'srv', + initiator: 'snippet' + }; + + it('store new session data instancied by the AB Test snippet for further usage', function () { + const sessionWithNewFlag = { ...sessionWithABTest, new: true }; + const storageValue = JSON.stringify({session: sessionWithNewFlag}); + sandbox.stub(storage, 'getDataFromLocalStorage').callsArgWith(1, storageValue); + sandbox.stub(Date, 'now').returns(1714116520710); + sandbox.stub(Math, 'random').returns(0.8); + + const spy = sandbox.spy(_internal.getAdagioNs().queue, 'push') + + adagioRtdSubmodule.init(config); + + const expected = { + session: { + ...sessionWithNewFlag + } + } + + expect(spy.withArgs({ + action: 'session', + ts: Date.now(), + data: expected, + }).calledOnce).to.be.true; + }); + + it('store new session data after removing AB Test props when initiator is not the snippet', function () { + const sessionWithNewFlag = { ...sessionWithABTest, new: false, initiator: 'adgjs' }; + const storageValue = JSON.stringify({session: sessionWithNewFlag}); + sandbox.stub(storage, 'getDataFromLocalStorage').callsArgWith(1, storageValue); + sandbox.stub(Date, 'now').returns(1714116520710); + sandbox.stub(Math, 'random').returns(0.8); + sandbox.stub(utils, 'generateUUID').returns('uid-5678'); + + const spy = sandbox.spy(_internal.getAdagioNs().queue, 'push') + + adagioRtdSubmodule.init(config); + + const expected = { + session: { + ...sessionWithNewFlag, + new: true, + id: utils.generateUUID(), + rnd: Math.random(), + } + } + delete expected.session.testName; + delete expected.session.testVersion; + + expect(spy.withArgs({ + action: 'session', + ts: Date.now(), + data: expected, + }).calledOnce).to.be.true; + }); + }); }); describe('submodule `getBidRequestData`', function () {