Skip to content

Commit

Permalink
addressed feedback and created tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jlquaccia committed Nov 12, 2024
1 parent 8a8929c commit ac11a00
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 97 deletions.
130 changes: 130 additions & 0 deletions libraries/previousAuctionInfo/previousAuctionInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import {on as onEvent} from '../../src/events.js';
import { EVENTS } from '../../src/constants.js';

export let previousAuctionInfoEnabled = false;
let enabledBidders = [];
export let winningBidsMap = {};

export const resetPreviousAuctionInfo = () => {
previousAuctionInfoEnabled = false;
enabledBidders = [];
winningBidsMap = {};
};

export const enablePreviousAuctionInfo = (config, cb = initHandlers) => {
const { bidderCode, isBidRequestValid } = config;
const enabledBidder = enabledBidders.find(bidder => bidder.bidderCode === bidderCode);
if (!enabledBidder) enabledBidders.push({ bidderCode, isBidRequestValid, maxQueueLength: config.maxQueueLength || 10 });
if (previousAuctionInfoEnabled) return;
previousAuctionInfoEnabled = true;
cb();
}

export const initHandlers = () => {
onEvent(EVENTS.AUCTION_END, onAuctionEndHandler);
onEvent(EVENTS.BID_WON, onBidWonHandler);
onEvent(EVENTS.BID_REQUESTED, onBidRequestedHandler);
};

export const onAuctionEndHandler = (auctionDetails) => {
// eslint-disable-next-line no-console
console.log('onAuctionEndHandler', auctionDetails);

try {
let highestCpmBid = 0;
const receivedBidsMap = {};
const rejectedBidsMap = {};

if (auctionDetails.bidsReceived && auctionDetails.bidsReceived.length) {
highestCpmBid = auctionDetails.bidsReceived.reduce((highestBid, currentBid) => {
return currentBid.cpm > highestBid.cpm ? currentBid : highestBid;
}, auctionDetails.bidsReceived[0]);

auctionDetails.bidsReceived.forEach(bidReceived => {
receivedBidsMap[bidReceived.requestId] = bidReceived;
});
}

if (auctionDetails.bidsRejected && auctionDetails.bidsRejected.length) {
auctionDetails.bidsRejected.forEach(bidRejected => {
rejectedBidsMap[bidRejected.requestId] = bidRejected;
});
}

if (auctionDetails.bidderRequests && auctionDetails.bidderRequests.length) {
auctionDetails.bidderRequests.forEach(bidderRequest => {
const enabledBidder = enabledBidders.find(bidder => bidder.bidderCode === bidderRequest.bidderCode);

if (enabledBidder) {
bidderRequest.bids.forEach(bid => {
const isValidBid = enabledBidder.isBidRequestValid(bid);

if (!isValidBid) return;

const previousAuctionInfoPayload = {
bidderRequestId: bidderRequest.bidderRequestId,
minBidToWin: highestCpmBid?.cpm || 0,
rendered: 0,
transactionId: bid.ortb2Imp.ext.tid || bid.transactionId,
source: 'pbjs',
auctionId: auctionDetails.auctionId,
impId: bid.adUnitCode,
// bidResponseId: FLOAT, // don't think this is available client side?
// targetedbidcpm: FLOAT, // don't think this is available client side?
highestcpm: highestCpmBid?.cpm || 0,
cur: bid.ortb2.cur,
bidderCpm: receivedBidsMap[bid.bidId] ? receivedBidsMap[bid.bidId].cpm : 'nobid',
biddererrorcode: rejectedBidsMap[bid.bidId] ? rejectedBidsMap[bid.bidId].rejectionReason : -1,
timestamp: auctionDetails.timestamp,
}

window.pbpai = window.pbpai || {};
if (!window.pbpai[bidderRequest.bidderCode]) {
window.pbpai[bidderRequest.bidderCode] = [];
}

if (window.pbpai[bidderRequest.bidderCode].length > enabledBidder.maxQueueLength) {
window.pbpai[bidderRequest.bidderCode].shift();
}

window.pbpai[bidderRequest.bidderCode].push(previousAuctionInfoPayload);
});
}
});
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
}
}

const onBidWonHandler = (winningBid) => {
// // eslint-disable-next-line no-console
// console.log('onBidWonHandler', winningBid);
winningBidsMap[winningBid.transactionId] = winningBid;
}

export const onBidRequestedHandler = (bidRequest) => {
try {
const enabledBidder = enabledBidders.find(bidder => bidder.bidderCode === bidRequest.bidderCode);
window.pbpai = window.pbpai || {};

if (enabledBidder && window.pbpai[bidRequest.bidderCode]) {
window.pbpai[bidRequest.bidderCode].forEach(prevAuctPayload => {
if (winningBidsMap[prevAuctPayload.transactionId]) {
prevAuctPayload.minBidToWin = winningBidsMap[prevAuctPayload.transactionId].cpm;
prevAuctPayload.rendered = 1;
}
});

bidRequest.ortb2 ??= {};
bidRequest.ortb2.ext ??= {};
bidRequest.ortb2.ext.prebid ??= {};
bidRequest.ortb2.ext.prebid.previousauctioninfo = window.pbpai[bidRequest.bidderCode];
delete window.pbpai[bidRequest.bidderCode];
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
}
}
97 changes: 0 additions & 97 deletions src/lossNotifications.js

This file was deleted.

81 changes: 81 additions & 0 deletions test/spec/libraries/previousAuctionInfo_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as previousAuctionInfo from 'libraries/previousAuctionInfo/previousAuctionInfo.js';
import sinon from 'sinon';

describe('previous auction info', () => {
let sandbox;
let initHandlersStub;

const auctionDetails = {
auctionId: 'auction123',
bidsReceived: [{ requestId: 'bid1', bidderCode: 'testBidder2', cpm: 2 }],
bidsRejected: [{ requestId: 'bid2', rejectionReason: 1 }],
bidderRequests: [
{
bidderCode: 'testBidder2',
bidderRequestId: 'req1',
bids: [{ bidId: 'bid1', ortb2: { cur: ['US'] }, ortb2Imp: { ext: { tid: 'trans123' } }, adUnitCode: 'adUnit1' }],
},
],
timestamp: Date.now(),
};

beforeEach(() => {
previousAuctionInfo.resetPreviousAuctionInfo();
if (window.pbpai) delete window.pbpai;
sandbox = sinon.createSandbox();
initHandlersStub = sandbox.stub();
});

afterEach(() => {
sandbox.restore();
if (window.pbpai) delete window.pbpai;
});

describe('config', () => {
it('should only be initialized once', () => {
const config = { bidderCode: 'testBidder', isBidRequestValid: () => true };
previousAuctionInfo.enablePreviousAuctionInfo(config, initHandlersStub);
sandbox.assert.calledOnce(initHandlersStub);
previousAuctionInfo.enablePreviousAuctionInfo(config, initHandlersStub);
sandbox.assert.calledOnce(initHandlersStub);
});
});

describe('on auction end', () => {
it('should only capture data for enabled bids who submitted a valid bid', () => {
const config = { bidderCode: 'testBidder2', isBidRequestValid: (bid) => bid.bidId === 'bid1' };
previousAuctionInfo.enablePreviousAuctionInfo(config, initHandlersStub);
previousAuctionInfo.onAuctionEndHandler(auctionDetails);

expect(window.pbpai.testBidder2).to.be.an('array').with.lengthOf(1);
expect(window.pbpai.testBidder2[0]).to.include({
auctionId: 'auction123',
minBidToWin: 2,
transactionId: 'trans123',
rendered: 0,
});
});
});

describe('on bid requested', () => {
it('should update the minBidToWin and rendered fields if a pbjs bid wins', () => {
const config = { bidderCode: 'testBidder3', isBidRequestValid: () => true };
previousAuctionInfo.enablePreviousAuctionInfo(config, initHandlersStub);
const bidRequest = {
bidderCode: 'testBidder3',
ortb2: { ext: { prebid: {} } },
};

previousAuctionInfo.winningBidsMap['trans123'] = { cpm: 5, transactionId: 'trans123' };

window.pbpai = {
testBidder3: [{ transactionId: 'trans123', minBidToWin: 0, rendered: 0 }],
};

previousAuctionInfo.onBidRequestedHandler(bidRequest);
const updatedInfo = bidRequest.ortb2.ext.prebid.previousauctioninfo;
expect(updatedInfo).to.be.an('array').with.lengthOf(1);
expect(updatedInfo[0]).to.include({ minBidToWin: 5, rendered: 1 });
});
});
});

0 comments on commit ac11a00

Please sign in to comment.