Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IDG-1163:: Improve slotRenderEnded Matching #76

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions modules/33acrossAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,18 +288,26 @@ function calculateTransactionTimeout(configTimeout = DEFAULT_TRANSACTION_TIMEOUT
function subscribeToGamSlots() {
window.googletag.pubads().addEventListener('slotRenderEnded', event => {
setTimeout(() => {
const { transactionId, auctionId } = getAdUnitMetadata(event.slot.getAdUnitPath());
const { transactionId, auctionId } =
getAdUnitMetadata(event.slot.getAdUnitPath(), event.slot.getSlotElementId());
if (!transactionId || !auctionId) {
const slotName = `${event.slot.getAdUnitPath()} - ${event.slot.getSlotElementId()}`;
log.warn('Could not find configured ad unit matching GAM render of slot:', { slotName });
return;
}

locals.transactionManagers[auctionId] &&
locals.transactionManagers[auctionId].complete(transactionId);
}, POST_GAM_TIMEOUT);
});
}

function getAdUnitMetadata(adUnitCode) {
const adUnitMeta = locals.adUnitMap[adUnitCode];
function getAdUnitMetadata(adUnitPath, adSlotElementId) {
const adUnitMeta = locals.adUnitMap[adUnitPath] || locals.adUnitMap[adSlotElementId];
if (adUnitMeta && adUnitMeta.length > 0) {
return adUnitMeta[adUnitMeta.length - 1];
}
return {};
}

/** necessary for testing */
Expand Down
66 changes: 54 additions & 12 deletions test/spec/modules/33acrossAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,17 +466,31 @@ describe('33acrossAnalyticsAdapter:', function () {
});

context('and the `slotRenderEnded` event fired for all bids, but not all bids have won', function () {
it('sends a report after the all `slotRenderEnded` events have fired and timed out', function () {
const timeout = POST_GAM_TIMEOUT + 2000;
this.enableAnalytics({ timeout });
context('and the GAM slot IDs are configured as the ad unit codes', function () {
it('sends a report after the all `slotRenderEnded` events have fired and timed out', function () {
const timeout = POST_GAM_TIMEOUT + 2000;
this.enableAnalytics({ timeout });

performStandardAuction({exclude: ['bidWon', 'auctionEnd']});
sandbox.clock.tick(POST_GAM_TIMEOUT + 1);
performStandardAuction({exclude: ['bidWon', 'auctionEnd']});
sandbox.clock.tick(POST_GAM_TIMEOUT + 1);

assert.strictEqual(navigator.sendBeacon.callCount, 1);
assert.strictEqual(navigator.sendBeacon.callCount, 1);
});
});

it('does NOT sent a report if not all `slotRenderEnded` events have timed out', function () {
context('and the slot element IDs are configured as the ad unit codes', function () {
it('sends a report after the all `slotRenderEnded` events have fired and timed out', function () {
const timeout = POST_GAM_TIMEOUT + 2000;
this.enableAnalytics({ timeout });

performStandardAuction({exclude: ['bidWon', 'auctionEnd'], useSlotElementIds: true});
sandbox.clock.tick(POST_GAM_TIMEOUT + 1);

assert.strictEqual(navigator.sendBeacon.callCount, 1);
});
});

it('does NOT send a report if not all `slotRenderEnded` events have timed out', function () {
const timeout = POST_GAM_TIMEOUT + 2000;
this.enableAnalytics({ timeout });

Expand All @@ -487,6 +501,26 @@ describe('33acrossAnalyticsAdapter:', function () {
});
});

context('and the `slotRenderEnded` event has fired for an unknown slot code', function () {
it('logs a warning message', function () {
this.enableAnalytics();

const { prebid: [auction], gam } = getMockEvents();
auction.AUCTION_INIT.adUnits[0].code = 'INVALID_AD_UNIT_CODE';

const slotRenderEnded = gam.slotRenderEnded[0];
events.emit(EVENTS.AUCTION_INIT, auction.AUCTION_INIT);
events.emit(EVENTS.BID_REQUESTED, auction.BID_REQUESTED[0]);
mockGpt.emitEvent('slotRenderEnded', slotRenderEnded);

sandbox.clock.tick(POST_GAM_TIMEOUT + 1);

assert.calledWithExactly(log.warn,
'Could not find configured ad unit matching GAM render of slot:',
{ slotName: `${adUnitCodes[0]} - ${adSlotElementIds[0]}` });
});
});

context('and the incomplete report has been sent successfully', function () {
it('sends a report string with any bids with rendered status set to hasWon: 1', function () {
navigator.sendBeacon.returns(true);
Expand Down Expand Up @@ -607,12 +641,21 @@ describe('33acrossAnalyticsAdapter:', function () {
});
});

function performStandardAuction({ exclude = [] } = {}) {
const adUnitCodes = ['/19968336/header-bid-tag-0', '/19968336/header-bid-tag-1', '/17118521/header-bid-tag-2'];
const adSlotElementIds = ['ad-slot-div-0', 'ad-slot-div-1', 'ad-slot-div-2'];

function performStandardAuction({ exclude = [], useSlotElementIds = false } = {}) {
const mockEvents = getMockEvents();
const { prebid, gam } = mockEvents;
const [auction] = prebid;

if (!exclude.includes(EVENTS.AUCTION_INIT)) {
if (useSlotElementIds) {
// With this option, identify the ad units by slot element IDs instead of GAM paths
auction.AUCTION_INIT.adUnits.forEach((adUnit, i) => {
adUnit.code = adSlotElementIds[i];
});
}
events.emit(EVENTS.AUCTION_INIT, auction.AUCTION_INIT);
}

Expand Down Expand Up @@ -756,7 +799,6 @@ function getLocalAssert() {
}
};

const adUnitCodes = ['/19968336/header-bid-tag-0', '/19968336/header-bid-tag-1', '/17118521/header-bid-tag-2'];
function createReportWithThreeBidWonEvents() {
return {
pid: 'test-pid',
Expand Down Expand Up @@ -847,7 +889,7 @@ function getMockEvents() {
slotRenderEnded: [
{
serviceName: 'publisher_ads',
slot: mockGpt.makeSlot({ code: adUnitCodes[0] }),
slot: mockGpt.makeSlot({ code: adUnitCodes[0], divId: adSlotElementIds[0] }),
isEmpty: true,
slotContentChanged: true,
size: null,
Expand All @@ -861,7 +903,7 @@ function getMockEvents() {
},
{
serviceName: 'publisher_ads',
slot: mockGpt.makeSlot({ code: adUnitCodes[1] }),
slot: mockGpt.makeSlot({ code: adUnitCodes[1], divId: adSlotElementIds[1] }),
isEmpty: false,
slotContentChanged: true,
size: [1, 1],
Expand All @@ -877,7 +919,7 @@ function getMockEvents() {
},
{
serviceName: 'publisher_ads',
slot: mockGpt.makeSlot({ code: adUnitCodes[2] }),
slot: mockGpt.makeSlot({ code: adUnitCodes[2], divId: adSlotElementIds[2] }),
isEmpty: false,
slotContentChanged: true,
size: [728, 90],
Expand Down