From c7194d470c42611526114174bf1c8e1eb0abe529 Mon Sep 17 00:00:00 2001 From: MO Thibault <103271673+MO-Thibault@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:49:18 -0400 Subject: [PATCH] analytics: V1 auction with Optable sources is not missed Same fix as #356, applied to the V1 add-on that feeds bid_analytics. Co-Authored-By: Claude Opus 5.5 (1M context) --- lib/addons/prototypes/analytics.js | 2 +- .../prototypes/analytics.missed.test.js | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 lib/addons/prototypes/analytics.missed.test.js diff --git a/lib/addons/prototypes/analytics.js b/lib/addons/prototypes/analytics.js index fbdf4f1e..db300ae3 100644 --- a/lib/addons/prototypes/analytics.js +++ b/lib/addons/prototypes/analytics.js @@ -274,7 +274,7 @@ class OptablePrebidAnalytics { optableMatchers: Array.from(oMatchersSet), optableSources: Array.from(oSourcesSet), liveintentEIDs: Array.from(lSourcesSet), - missed, + missed: missed && oSourcesSet.size === 0, url: `${window.location.hostname}${window.location.pathname}`, tenant: this.config.tenant, optableWrapperVersion: SDK_WRAPPER_VERSION, // eslint-disable-line no-undef diff --git a/lib/addons/prototypes/analytics.missed.test.js b/lib/addons/prototypes/analytics.missed.test.js new file mode 100644 index 00000000..6dd548dd --- /dev/null +++ b/lib/addons/prototypes/analytics.missed.test.js @@ -0,0 +1,41 @@ +import OptablePrebidAnalytics from "./analytics"; + +global.SDK_WRAPPER_VERSION = "1.0.0-test"; + +function bidderRequest(bidderCode, sources) { + return { + bidderCode, + bidderRequestId: `br-${bidderCode}`, + ortb2: { + user: { ext: { eids: sources.map((source) => ({ source, inserter: "optable.co", uids: [{ id: "x" }] })) } }, + }, + bids: [{ bidId: `bid-${bidderCode}`, adUnitCode: "slot-1" }], + }; +} + +async function run(sources, missed) { + const witness = jest.fn().mockResolvedValue(undefined); + const analytics = new OptablePrebidAnalytics({ witness }, { analytics: true, tenant: "t" }); + await analytics.trackAuctionEnd({ auctionId: "a-1", bidderRequests: [bidderRequest("a", sources)] }, missed); + return JSON.parse(witness.mock.calls[0][1].auction); +} + +beforeEach(() => { + window.optable = {}; +}); + +describe("missed", () => { + test("false when the hook attached before the auction", async () => { + expect((await run([], false)).missed).toBe(false); + }); + + test("false when the hook attached late but Optable sources are present", async () => { + const p = await run(["uidapi.com"], true); + expect(p.optableSources).toEqual(["uidapi.com"]); + expect(p.missed).toBe(false); + }); + + test("true when the hook attached late and no Optable sources are present", async () => { + expect((await run([], true)).missed).toBe(true); + }); +});