diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index ac9a7d30429..57ab4ff4ed9 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -5,9 +5,12 @@ import { VIDEO, BANNER } from '../src/mediaTypes'; const BIDDER_CODE = 'grid'; const ENDPOINT_URL = '//grid.bidswitch.net/hb'; +const SYNC_URL = '//x.bidswitch.net/sync?ssp=iow_labs'; const TIME_TO_LIVE = 360; const RENDERER_URL = '//acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; +let hasSynced = false; + const LOG_ERROR_MESS = { noAuid: 'Bid from response has no auid parameter - ', noAdm: 'Bid from response has no adm parameter - ', @@ -136,6 +139,25 @@ export const spec = { } if (errorMessage) utils.logError(errorMessage); return bidResponses; + }, + getUserSyncs: function (syncOptions, responses, gdprConsent) { + if (!hasSynced && syncOptions.pixelEnabled) { + let params = ''; + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + if (typeof gdprConsent.gdprApplies === 'boolean') { + params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + params += `&gdpr_consent=${gdprConsent.consentString}`; + } + } + + hasSynced = true; + return { + type: 'image', + url: SYNC_URL + params + }; + } } }; @@ -244,4 +266,12 @@ function createRenderer (bid, rendererParams) { return renderer; } +export function resetUserSync() { + hasSynced = false; +} + +export function getSyncUrl() { + return SYNC_URL; +} + registerBidder(spec); diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index 36aaddb8b42..d972ec25c8a 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/gridBidAdapter'; +import { spec, resetUserSync, getSyncUrl } from 'modules/gridBidAdapter'; import { newBidder } from 'src/adapters/bidderFactory'; describe('TheMediaGrid Adapter', function () { @@ -577,4 +577,91 @@ describe('TheMediaGrid Adapter', function () { expect(result).to.deep.equal(expectedResponse); }); }); + + describe('user sync', function () { + const syncUrl = getSyncUrl(); + + beforeEach(function () { + resetUserSync(); + }); + + it('should register the Emily iframe', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + }); + + it('should not register the Emily iframe more than once', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + + // when called again, should still have only been called once + syncs = spec.getUserSyncs(); + expect(syncs).to.equal(undefined); + }); + + it('should pass gdpr params if consent is true', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: true, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=1&gdpr_consent=foo` + }); + }); + + it('should pass gdpr params if consent is false', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: false, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=0&gdpr_consent=foo` + }); + }); + + it('should pass gdpr param gdpr_consent only when gdprApplies is undefined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr_consent=foo` + }); + }); + + it('should pass no params if gdpr consentString is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {})).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a number', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 0 + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is null', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: null + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a object', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: {} + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined)).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + }); });