Skip to content
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
113 changes: 113 additions & 0 deletions lib/addons/prebid/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,119 @@ describe("OptablePrebidAnalytics", () => {
expect(storedAuction).toBeDefined();
});

it("should extract splitTestAssignment from bidsReceived", async () => {
const event = {
auctionId: "auction-split-test",
timeout: 3000,
bidderRequests: [
{
bidderCode: "bidder1",
bidderRequestId: "req-1",
ortb2: {
site: { domain: "example.com" },
user: {
eids: [
{
inserter: "optable.co",
matcher: "matcher1",
source: "source1",
},
],
},
},
bids: [
{
bidId: "bid-1",
adUnitCode: "ad-unit-1",
adUnitId: "ad-id-1",
transactionId: "trans-1",
src: "client",
},
],
},
],
bidsReceived: [
{
requestId: "bid-1",
cpm: 1.5,
width: 300,
height: 250,
currency: "USD",
adUnitCode: "ad-unit-1",
ortb2Imp: {
ext: {
optable: {
splitTestAssignment: "treatment",
},
},
},
},
],
noBids: [],
timeoutBids: [],
};

await analytics.trackAuctionEnd(event);

// Get the stored auction and check the bid has splitTestAssignment
const storedAuction = analytics["auctions"].get("auction-split-test");
expect(storedAuction).toBeDefined();

// The splitTestAssignment should be extracted and merged in toWitness
const payload = await analytics.toWitness(storedAuction.auctionEnd, null);
expect(payload.bidderRequests[0].bids[0].splitTestAssignment).toBe("treatment");
});

it("should handle missing splitTestAssignment gracefully", async () => {
const event = {
auctionId: "auction-no-split-test",
timeout: 3000,
bidderRequests: [
{
bidderCode: "bidder1",
bidderRequestId: "req-1",
ortb2: {
site: { domain: "example.com" },
user: {
eids: [],
},
},
bids: [
{
bidId: "bid-1",
adUnitCode: "ad-unit-1",
adUnitId: "ad-id-1",
transactionId: "trans-1",
src: "client",
},
],
},
],
bidsReceived: [
{
requestId: "bid-1",
cpm: 1.5,
width: 300,
height: 250,
currency: "USD",
adUnitCode: "ad-unit-1",
// No ortb2Imp field
},
],
noBids: [],
timeoutBids: [],
};

await analytics.trackAuctionEnd(event);

// Should not throw error and splitTestAssignment should be undefined
const storedAuction = analytics["auctions"].get("auction-no-split-test");
expect(storedAuction).toBeDefined();

const payload = await analytics.toWitness(storedAuction.auctionEnd, null);
expect(payload.bidderRequests[0].bids[0].splitTestAssignment).toBeUndefined();
});

it("should handle noBids and update status", async () => {
const event = {
auctionId: "auction-no-bids",
Expand Down
20 changes: 19 additions & 1 deletion lib/addons/prebid/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class OptablePrebidAnalytics {
transactionId: string;
src: string;
floorData?: { floorMin: number };
ortb2Imp?: { ext?: { optable?: { splitTestAssignment?: string } } };
}) => ({
bidId: b.bidId,
bidderRequestId,
Expand All @@ -252,6 +253,7 @@ class OptablePrebidAnalytics {
transactionId: b.transactionId,
src: b.src,
floorMin: b.floorData?.floorMin,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
status: STATUS.REQUESTED,
})
),
Expand Down Expand Up @@ -291,6 +293,7 @@ class OptablePrebidAnalytics {
cpm: b.cpm,
size: `${b.width}x${b.height}`,
currency: b.currency,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
});
} else {
// Create new bid object for this response
Expand All @@ -305,6 +308,7 @@ class OptablePrebidAnalytics {
size: `${b.width}x${b.height}`,
currency: b.currency,
status: STATUS.RECEIVED,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
};
br.bids.push(bidObj);
bidIndex[bidId] = bidObj;
Expand Down Expand Up @@ -349,7 +353,7 @@ class OptablePrebidAnalytics {
this.sendToWitnessAPI("optable.prebid.auction", payload);
}, this.config.bidWinTimeout);

// Store the processed auction
// Store the auction data
this.auctions.set(auctionId, { auctionEnd: event, createdAt, missed, auctionEndTimeoutId });

// Clean up old auctions
Expand Down Expand Up @@ -433,6 +437,7 @@ class OptablePrebidAnalytics {
let totalBids = 0;
let device = null;

// Process bidder requests
const requests = bidderRequests.map((br: any) => {
const { bidderCode, bidderRequestId, bids = [] } = br;
const domain = br.ortb2.site?.domain ?? "unknown";
Expand Down Expand Up @@ -461,6 +466,7 @@ class OptablePrebidAnalytics {
transactionId: string;
src: string;
floorData?: { floorMin: number };
ortb2Imp?: { ext?: { optable?: { splitTestAssignment?: string } } };
}) => ({
bidId: b.bidId,
bidderRequestId,
Expand All @@ -469,12 +475,24 @@ class OptablePrebidAnalytics {
transactionId: b.transactionId,
src: b.src,
floorMin: b.floorData?.floorMin,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
status: STATUS.REQUESTED,
})
),
};
});

// Merge splitTestAssignment from bidsReceived into the requests
const bidsReceivedMap = new Map<string, any>(bidsReceived.map((b: any) => [b.requestId, b]));
requests.forEach((request: any) => {
request.bids.forEach((bid: any) => {
const bidReceived = bidsReceivedMap.get(bid.bidId);
if (bidReceived?.ortb2Imp?.ext?.optable?.splitTestAssignment) {
bid.splitTestAssignment = bidReceived.ortb2Imp.ext.optable.splitTestAssignment;
}
});
});

const witnessData: WitnessProperties = {
bidderRequests: requests.map((br: any) => {
br.optableMatchers.forEach((m: unknown) => oMatchersSet.add(m));
Expand Down
4 changes: 4 additions & 0 deletions lib/addons/prototypes/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class OptablePrebidAnalytics {
transactionId: b.transactionId,
src: b.src,
floorMin: b.floorData?.floorMin,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
status: STATUS.REQUESTED,
})),
};
Expand Down Expand Up @@ -178,6 +179,7 @@ class OptablePrebidAnalytics {
cpm: b.cpm,
size: `${b.width}x${b.height}`,
currency: b.currency,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
});
} else {
// Create new bid object for this response
Expand All @@ -192,6 +194,7 @@ class OptablePrebidAnalytics {
size: `${b.width}x${b.height}`,
currency: b.currency,
status: STATUS.RECEIVED,
splitTestAssignment: b.ortb2Imp?.ext?.optable?.splitTestAssignment,
};
br.bids.push(bidObj);
bidIndex[bidId] = bidObj;
Expand Down Expand Up @@ -255,6 +258,7 @@ class OptablePrebidAnalytics {
cpm: b.cpm,
size: b.size,
bidId: b.bidId,
splitTestAssignment: b.splitTestAssignment,
};
}),
};
Expand Down