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

describe("trackAuctionEnd - split test assignment", () => {
function makeEvent(bids: any[]) {
return {
auctionId: "auction-split-test",
timeout: 3000,
bidderRequests: [
{
bidderCode: "bidder1",
bidderRequestId: "req-1",
ortb2: { site: { domain: "example.com" }, user: { eids: [] } },
bids,
},
],
bidsReceived: [],
noBids: [],
timeoutBids: [],
};
}

it("does nothing when getSplitTestAssignment is not configured", async () => {
analytics = new OptablePrebidAnalytics(mockOptableInstance);
const bid = { bidId: "bid-1" };
await analytics.trackAuctionEnd(makeEvent([bid]));

expect(bid).not.toHaveProperty("ortb2Imp");
});

it("does nothing when getSplitTestAssignment returns undefined", async () => {
analytics = new OptablePrebidAnalytics(mockOptableInstance, {
getSplitTestAssignment: () => undefined,
});
const bid = { bidId: "bid-1" };
await analytics.trackAuctionEnd(makeEvent([bid]));

expect(bid).not.toHaveProperty("ortb2Imp");
});

it("tags every bid's ortb2Imp.ext.optable.splitTestAssignment", async () => {
analytics = new OptablePrebidAnalytics(mockOptableInstance, {
getSplitTestAssignment: () => "all",
});
const bidA: any = { bidId: "bid-1" };
const bidB: any = { bidId: "bid-2" };
await analytics.trackAuctionEnd(makeEvent([bidA, bidB]));

expect(bidA.ortb2Imp.ext.optable.splitTestAssignment).toBe("all");
expect(bidB.ortb2Imp.ext.optable.splitTestAssignment).toBe("all");
});

it("does not override an already-set splitTestAssignment", async () => {
analytics = new OptablePrebidAnalytics(mockOptableInstance, {
getSplitTestAssignment: () => "all",
});
const bid: any = { bidId: "bid-1", ortb2Imp: { ext: { optable: { splitTestAssignment: "control" } } } };
await analytics.trackAuctionEnd(makeEvent([bid]));

expect(bid.ortb2Imp.ext.optable.splitTestAssignment).toBe("control");
});

it("preserves other fields already present on ortb2Imp.ext.optable", async () => {
analytics = new OptablePrebidAnalytics(mockOptableInstance, {
getSplitTestAssignment: () => "all",
});
const bid: any = { bidId: "bid-1", ortb2Imp: { ext: { optable: { foo: "bar" } } } };
await analytics.trackAuctionEnd(makeEvent([bid]));

expect(bid.ortb2Imp.ext.optable).toEqual({ foo: "bar", splitTestAssignment: "all" });
});
});

describe("trackBidWon", () => {
beforeEach(() => {
jest.useFakeTimers();
Expand Down
14 changes: 14 additions & 0 deletions lib/addons/prebid/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface OptablePrebidAnalyticsConfig {
samplingSeed?: string;
samplingRate?: number;
samplingRateFn?: () => boolean;
getSplitTestAssignment?: () => string | undefined;
}

interface AuctionItem {
Expand Down Expand Up @@ -227,6 +228,19 @@ class OptablePrebidAnalytics {

this.log(`Processing auction ${auctionId} with ${bidderRequests.length} bidder requests`);

const splitTestAssignment = this.config.getSplitTestAssignment?.();
if (splitTestAssignment) {
bidderRequests.forEach((br: any) => {
(br.bids || []).forEach((b: any) => {
if (b.ortb2Imp?.ext?.optable?.splitTestAssignment) return;
b.ortb2Imp = b.ortb2Imp || {};
b.ortb2Imp.ext = b.ortb2Imp.ext || {};
b.ortb2Imp.ext.optable = b.ortb2Imp.ext.optable || {};
b.ortb2Imp.ext.optable.splitTestAssignment = splitTestAssignment;
});
});
}

(window as any).optable = (window as any).optable || {};
(window as any).optable.pageAuctionsCount = (Number((window as any).optable.pageAuctionsCount) || 0) + 1;

Expand Down
13 changes: 13 additions & 0 deletions lib/addons/prototypes/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,19 @@ class OptablePrebidAnalytics {

this.log(`Processing auction ${auctionId} with ${bidderRequests.length} bidder requests`);

const splitTestAssignment = this.config.getSplitTestAssignment?.();
if (splitTestAssignment) {
bidderRequests.forEach((br) => {
(br.bids || []).forEach((b) => {
if (b.ortb2Imp?.ext?.optable?.splitTestAssignment) return;
b.ortb2Imp = b.ortb2Imp || {};
b.ortb2Imp.ext = b.ortb2Imp.ext || {};
b.ortb2Imp.ext.optable = b.ortb2Imp.ext.optable || {};
b.ortb2Imp.ext.optable.splitTestAssignment = splitTestAssignment;
});
});
}

// Build auction object with bidder requests and EID flags
const auction = {
auctionId,
Expand Down
Loading