diff --git a/src/adapters/adkernel.js b/src/adapters/adkernel.js index 2b6c4eca83e..32415bcba41 100644 --- a/src/adapters/adkernel.js +++ b/src/adapters/adkernel.js @@ -42,7 +42,11 @@ const AdKernelAdapter = function AdKernelAdapter() { if (!(zone in _dispatch[host])) { _dispatch[host][zone] = []; } - let imp = {'id': bidId, 'tagid': bid.placementCode, 'banner': {'w': size[0], 'h': size[1]}}; + let imp = { + 'id': bidId, + 'tagid': bid.placementCode, + 'banner': {'w': size[0], 'h': size[1]} + }; if (utils.getTopWindowLocation().protocol === 'https:') { imp.secure = 1; } @@ -55,21 +59,9 @@ const AdKernelAdapter = function AdKernelAdapter() { } if (syncedHostZones[host].indexOf(zone) === -1) { syncedHostZones[host].push(zone); - insertUserSync(host, zone); } }; - function insertUserSync(host, zone) { - var iframe = utils.createInvisibleIframe(); - iframe.src = `//${host}/user-sync?zone=${zone}`; - try { - document.body.appendChild(iframe); - } catch (error) { - /* istanbul ignore next */ - utils.logError(error); - } - } - /** * Main function to get bid requests */ @@ -82,6 +74,16 @@ const AdKernelAdapter = function AdKernelAdapter() { }); }); }; + /** + * Build flat user-sync queue from host->zones mapping + */ + this.buildUserSyncQueue = function() { + return Object.keys(syncedHostZones) + .reduce((m, k) => { + syncedHostZones[k].forEach((v) => m.push([k, v])); + return m; + }, []); + }; function dispatchRtbRequest(host, zone, impressions, callback) { let url = buildEndpointUrl(host); @@ -160,7 +162,10 @@ const AdKernelAdapter = function AdKernelAdapter() { dispatcher.addImp(bid); } }); - // process bids grouped into bidrequests + // start async usersync + processUserSyncQueue(dispatcher.buildUserSyncQueue()); + + // process bids grouped into bid requests dispatcher.dispatch((bid, imp, bidResp) => { let adUnitId = bid.placementCode; if (bidResp) { @@ -221,6 +226,32 @@ const AdKernelAdapter = function AdKernelAdapter() { }; } + /** + * Recursively process user-sync queue + */ + function processUserSyncQueue(queue) { + if (queue.length === 0) { + return; + } + let entry = queue.pop(); + insertUserSync(entry[0], entry[1], () => processUserSyncQueue(queue)); + } + + /** + * Insert single iframe user-sync + */ + function insertUserSync(host, zone, callback) { + var iframe = utils.createInvisibleIframe(); + iframe.src = `//sync.adkernel.com/user-sync?zone=${zone}&r=%2F%2F${host}%2Fuser-synced%3Fuid%3D%7BUID%7D`; + utils.addEventHandler(iframe, 'load', callback); + try { + document.body.appendChild(iframe); + } catch (error) { + /* istanbul ignore next */ + utils.logError(error); + } + } + return { callBids: baseAdapter.callBids, setBidderCode: baseAdapter.setBidderCode, diff --git a/test/spec/adapters/adkernel_spec.js b/test/spec/adapters/adkernel_spec.js index 095a51249fb..dd7eb82060a 100644 --- a/test/spec/adapters/adkernel_spec.js +++ b/test/spec/adapters/adkernel_spec.js @@ -238,21 +238,27 @@ describe('Adkernel adapter', () => { sandbox.spy(utils, 'createTrackPixelHtml'); ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(bidResponse1)); doRequest([bid1_zone1]); - expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); expect(utils.createTrackPixelHtml.calledOnce); - let result = pbjs.getBidResponsesForAdUnitCode(bid1_zone1.placementCode); + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); let expectedNurl = bidResponse1.seatbid[0].bid[0].nurl + '&px=1'; - expect(result.bids[0].ad).to.include(expectedNurl); + expect(bidmanager.addBidResponse.firstCall.args[1].ad).to.include(expectedNurl); }); it('should perform usersync for each unique host/zone combination', () => { ajaxStub.callsArgWith(1, ''); - const expectedSyncUrls = ['http://rtb.adkernel.com/user-sync?zone=1', 'http://rtb.adkernel.com/user-sync?zone=2', - 'http://rtb-private.adkernel.com/user-sync?zone=1']; - sandbox.spy(utils, 'createInvisibleIframe'); + const expectedSyncUrls = ['//sync.adkernel.com/user-sync?zone=1&r=%2F%2Frtb-private.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D', + '//sync.adkernel.com/user-sync?zone=2&r=%2F%2Frtb.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D', + '//sync.adkernel.com/user-sync?zone=1&r=%2F%2Frtb.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D']; + let userSyncUrls = []; + sandbox.stub(utils, 'createInvisibleIframe', () => { + return {}; + }); + sandbox.stub(utils, 'addEventHandler', (el, ev, cb) => { + userSyncUrls.push(el.src); + cb(); // instant callback + }); doRequest([bid1_zone1, bid2_zone2, bid2_zone2, bid3_host2]); expect(utils.createInvisibleIframe.calledThrice); - let userSyncUrls = utils.createInvisibleIframe.returnValues.map(val => val.src); expect(userSyncUrls).to.be.eql(expectedSyncUrls); }); });