From 10ef60fdbc5c81cb4b45091b017508937341e2df Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 14 Dec 2021 09:01:34 -0800 Subject: [PATCH] RTD module: allow submodules to setBidRequestData without `waitForIt` This change allows all RTD submodules at least one shot to see the `setBidRequestData` hook even if they are not flagged `waitForIt` (previously they would not be run at all in some cases). Addresses https://github.com/prebid/Prebid.js/issues/7117 --- modules/rtdModule/index.js | 15 +++--- test/spec/modules/realTimeDataModule_spec.js | 54 +++++++++++++++++++- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index 1efa89e329f..5517bb350cf 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -289,18 +289,12 @@ export function setBidRequestsData(fn, reqBidsConfigObj) { return exitHook(); } - if (shouldDelayAuction) { - waitTimeout = setTimeout(exitHook, _moduleConfig.auctionDelay); - } + waitTimeout = setTimeout(exitHook, shouldDelayAuction ? _moduleConfig.auctionDelay : 0); relevantSubModules.forEach(sm => { sm.getBidRequestData(reqBidsConfigObj, onGetBidRequestDataCallback.bind(sm), sm.config, _userConsent) }); - if (!shouldDelayAuction) { - return exitHook(); - } - function onGetBidRequestDataCallback() { if (isDone) { return; @@ -308,12 +302,15 @@ export function setBidRequestsData(fn, reqBidsConfigObj) { if (this.config && this.config.waitForIt) { callbacksExpected--; } - if (callbacksExpected <= 0) { - return exitHook(); + if (callbacksExpected === 0) { + setTimeout(exitHook, 0); } } function exitHook() { + if (isDone) { + return; + } isDone = true; clearTimeout(waitTimeout); fn.call(this, reqBidsConfigObj); diff --git a/test/spec/modules/realTimeDataModule_spec.js b/test/spec/modules/realTimeDataModule_spec.js index 45559c5bc48..b735b05b363 100644 --- a/test/spec/modules/realTimeDataModule_spec.js +++ b/test/spec/modules/realTimeDataModule_spec.js @@ -3,6 +3,7 @@ import {config} from 'src/config.js'; import * as sinon from 'sinon'; import {default as CONSTANTS} from '../../../src/constants.json'; import {default as events} from '../../../src/events.js'; +import 'src/prebid.js'; const getBidRequestDataSpy = sinon.spy(); @@ -140,7 +141,56 @@ describe('Real time module', function () { const adUnits = rtdModule.getAdUnitTargeting(auction); assert.deepEqual(expectedAdUnits, adUnits) done(); - }) + }); + + describe('setBidRequestData', () => { + let withWait, withoutWait; + + function runSetBidRequestData() { + return new Promise((resolve) => { + rtdModule.setBidRequestsData(resolve, {bidRequest: {}}); + }); + } + + beforeEach(() => { + withWait = { + submod: validSMWait, + cbTime: 0, + cbRan: false + }; + withoutWait = { + submod: validSM, + cbTime: 0, + cbRan: false + }; + + [withWait, withoutWait].forEach((c) => { + c.submod.getBidRequestData = sinon.stub().callsFake((_, cb) => { + setTimeout(() => { + c.cbRan = true; + cb(); + }, c.cbTime); + }); + }); + }); + + it('should allow non-priority submodules to run synchronously', () => { + withWait.cbTime = withoutWait.cbTime = 0; + return runSetBidRequestData().then(() => { + expect(withWait.cbRan).to.be.true; + expect(withoutWait.cbRan).to.be.true; + }) + }); + + it('should not wait for non-priority submodules if priority ones complete first', () => { + withWait.cbTime = 10; + withoutWait.cbTime = 100; + return runSetBidRequestData().then(() => { + expect(withWait.cbRan).to.be.true; + expect(withoutWait.cbRan).to.be.false; + }); + }); + }); }); it('deep merge object', function () { @@ -242,5 +292,5 @@ describe('Real time module', function () { expect(providers[1][hook].called).to.be.true; }); }); - }) + }); });