From 1e86b703d73c2268b151e89079f1d97276705c9f Mon Sep 17 00:00:00 2001 From: Ibrahima Niass <48965172+Niass@users.noreply.github.com> Date: Wed, 30 Aug 2023 18:17:41 +0000 Subject: [PATCH] Bliink Bid Adapter : enhance request data with userIds, ect, refresh (#10290) * fix(bliink): bid ttl * fix(bliink): ttl unit tests * Bliink Bid Adapter: enhance request data with userIds, ect, refresh * Bliink Bid Adapter: fix tests --------- Co-authored-by: Samous --- modules/bliinkBidAdapter.js | 45 +- test/spec/modules/bliinkBidAdapter_spec.js | 820 ++++++++++++++------- 2 files changed, 606 insertions(+), 259 deletions(-) diff --git a/modules/bliinkBidAdapter.js b/modules/bliinkBidAdapter.js index 9a9d74d14c1..6f3f5e21cb8 100644 --- a/modules/bliinkBidAdapter.js +++ b/modules/bliinkBidAdapter.js @@ -12,7 +12,7 @@ export const META_DESCRIPTION = 'description' const VIDEO = 'video' const BANNER = 'banner' - +window.bliinkBid = window.bliinkBid || {}; const supportedMediaTypes = [BANNER, VIDEO] const aliasBidderCode = ['bk'] @@ -23,6 +23,37 @@ function getCoppa() { return config.getConfig('coppa') === true ? 1 : 0; } +/** + * Retrieves the effective connection type from the browser's Navigator API. + * @returns {string} The effective connection type or 'unsupported' if unavailable. + */ +export function getEffectiveConnectionType() { + /** + * The effective connection type obtained from the browser's Navigator API. + * @type {string|undefined} + */ + const navigatorEffectiveType = navigator?.connection?.effectiveType; + + if (navigatorEffectiveType) { + return navigatorEffectiveType; + } + + return 'unsupported'; +} + +/** + * Retrieves the user IDs as EIDs from the first valid bid request. + * + * @param {Array} validBidRequests - Array of valid bid requests + * @returns {Array|undefined} - Array of user IDs as EIDs, or undefined if not found + */ +export function getUserIds(validBidRequests) { + /** @type {Object} */ + const firstBidRequest = validBidRequests?.[0] + if (firstBidRequest?.userIds) { + return firstBidRequest.userIds + } +} export function getMetaList(name) { if (!name || name.length === 0) return [] @@ -151,13 +182,16 @@ export const buildRequests = (validBidRequests, bidderRequest) => { if (!validBidRequests || !bidderRequest || !bidderRequest.bids) return null const tags = bidderRequest.bids.map((bid) => { + const id = bid.params.tagId return { sizes: bid.sizes.map((size) => ({ w: size[0], h: size[1] })), - id: bid.params.tagId, + id, // TODO: bidId is globally unique, is it a good choice for transaction ID (vs ortb2Imp.ext.tid)? transactionId: bid.bidId, mediaTypes: Object.keys(bid.mediaTypes), imageUrl: deepAccess(bid, 'params.imageUrl', ''), + videoUrl: deepAccess(bid, 'params.videoUrl', ''), + refresh: (window.bliinkBid[id] = (window.bliinkBid[id] ?? -1) + 1) || undefined, }; }); @@ -167,11 +201,17 @@ export const buildRequests = (validBidRequests, bidderRequest) => { pageUrl: deepAccess(bidderRequest, 'refererInfo.page'), pageDescription: getMetaValue(META_DESCRIPTION), keywords: getKeywords().join(','), + ect: getEffectiveConnectionType(), }; + const schain = deepAccess(validBidRequests[0], 'schain') + const userIds = getUserIds(validBidRequests) if (schain) { request.schain = schain } + if (userIds) { + request.userIds = userIds + } const gdprConsent = deepAccess(bidderRequest, 'gdprConsent'); if (!!gdprConsent && gdprConsent.gdprApplies) { request.gdpr = true @@ -183,7 +223,6 @@ export const buildRequests = (validBidRequests, bidderRequest) => { if (bidderRequest.uspConsent) { deepSetValue(request, 'uspConsent', bidderRequest.uspConsent); } - return { method: 'POST', url: BLIINK_ENDPOINT_ENGINE, diff --git a/test/spec/modules/bliinkBidAdapter_spec.js b/test/spec/modules/bliinkBidAdapter_spec.js index 8e96bd76940..d0320ab6ec1 100644 --- a/test/spec/modules/bliinkBidAdapter_spec.js +++ b/test/spec/modules/bliinkBidAdapter_spec.js @@ -1,5 +1,14 @@ -import { expect } from 'chai' -import { spec, buildBid, BLIINK_ENDPOINT_ENGINE, getMetaList, BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME } from 'modules/bliinkBidAdapter.js' +import { expect } from 'chai'; +import { + spec, + buildBid, + BLIINK_ENDPOINT_ENGINE, + getMetaList, + BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME, + getEffectiveConnectionType, + getUserIds, +} from 'modules/bliinkBidAdapter.js'; +import { config } from 'src/config.js'; /** * @description Mockup bidRequest @@ -20,6 +29,8 @@ import { spec, buildBid, BLIINK_ENDPOINT_ENGINE, getMetaList, BLIINK_ENDPOINT_CO * crumbs: {pubcid: string}, * ortb2Imp: {ext: {data: {pbadslot: string}}}}} */ + +const connectionType = getEffectiveConnectionType(); const getConfigBid = (placement) => { return { adUnitCode: '/19968336/test', @@ -31,31 +42,32 @@ const getConfigBid = (placement) => { bidderRequestsCount: 1, bidderWinsCount: 0, crumbs: { - pubcid: '55ffadc5-051f-428d-8ecc-dc585e0bde0d' + pubcid: '55ffadc5-051f-428d-8ecc-dc585e0bde0d', }, sizes: [[300, 250]], mediaTypes: { banner: { - sizes: [ - [300, 250] - ] - } + sizes: [[300, 250]], + }, }, ortb2Imp: { ext: { data: { - pbadslot: '/19968336/test' - } - } + pbadslot: '/19968336/test', + }, + }, }, + ect: connectionType, params: { placement: placement, - tagId: '14f30eca-85d2-11e8-9eed-0242ac120007' + tagId: '14f30eca-85d2-11e8-9eed-0242ac120007', + videoUrl: 'https://www.example.com/advideo.mp4', + imageUrl: 'https://www.example.com/adimage.jpg', }, src: 'client', - transactionId: 'cc6678c4-9746-4082-b9e2-d8065d078ebf' - } -} + transactionId: 'cc6678c4-9746-4082-b9e2-d8065d078ebf', + }; +}; const getConfigBannerBid = () => { return { creative: { @@ -76,14 +88,13 @@ const getConfigBannerBid = () => { transaction_id: '2def0c5b2a7f6e', }, currency: 'EUR', - } -} + }; +}; const getConfigVideoBid = () => { return { creative: { video: { - content: - '', + content: '', height: 250, width: 300, }, @@ -99,8 +110,8 @@ const getConfigVideoBid = () => { transaction_id: '2def0c5b2a7f6e', }, currency: 'EUR', - } -} + }; +}; /** * @description Mockup response from engine.bliink.io/xxxx @@ -119,7 +130,7 @@ const getConfigVideoBid = () => { * } * } * } -* } + * } */ const getConfigCreative = () => { return { @@ -132,8 +143,8 @@ const getConfigCreative = () => { height: 250, ttl: 300, netRevenue: true, - } -} + }; +}; const getConfigCreativeVideo = (isNoVast) => { return { @@ -147,8 +158,8 @@ const getConfigCreativeVideo = (isNoVast) => { height: 250, ttl: 300, netRevenue: true, - } -} + }; +}; /** * @description Mockup BuildRequest function @@ -166,19 +177,19 @@ const getConfigBuildRequest = (placement) => { reachedTop: true, page: 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', }, - } + }; if (!placement) { - return buildRequest + return buildRequest; } return Object.assign(buildRequest, { params: { bids: [getConfigBid(placement)], - placement: placement + placement: placement, }, - }) -} + }); +}; /** * @description Mockup response from API @@ -189,8 +200,8 @@ const getConfigInterpretResponse = (noAd = false) => { if (noAd) { return { message: 'invalid tag', - mode: 'no-ad' - } + mode: 'no-ad', + }; } return { @@ -198,11 +209,12 @@ const getConfigInterpretResponse = (noAd = false) => { ...getConfigCreative(), mode: 'ad', transactionId: '2def0c5b2a7f6e', - token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjgxNzA4MzEsImlhdCI6MTYyNzU2NjAzMSwiaXNzIjoiYmxpaW5rIiwiZGF0YSI6eyJ0eXBlIjoiYWQtc2VydmVyIiwidHJhbnNhY3Rpb25JZCI6IjM1YmU1NDNjLTNkZTQtNGQ1Yy04N2NjLWIzYzEyOGZiYzU0MCIsIm5ldHdvcmtJZCI6MjEsInNpdGVJZCI6NTksInRhZ0lkIjo1OSwiY29va2llSWQiOiJjNGU4MWVhOS1jMjhmLTQwZDItODY1ZC1hNjQzZjE1OTcyZjUiLCJldmVudElkIjozLCJ0YXJnZXRpbmciOnsicGxhdGZvcm0iOiJXZWJzaXRlIiwiaXAiOiI3OC4xMjIuNzUuNzIiLCJ0aW1lIjoxNjI3NTY2MDMxLCJsb2NhdGlvbiI6eyJsYXRpdHVkZSI6NDguOTczOSwibG9uZ2l0dWRlIjozLjMxMTMsInJlZ2lvbiI6IkhERiIsImNvdW50cnkiOiJGUiIsImNpdHkiOiJTYXVsY2hlcnkiLCJ6aXBDb2RlIjoiMDIzMTAiLCJkZXBhcnRtZW50IjoiMDIifSwiY2l0eSI6IlNhdWxjaGVyeSIsImNvdW50cnkiOiJGUiIsImRldmljZU9zIjoibWFjT1MiLCJkZXZpY2VQbGF0Zm9ybSI6IldlYnNpdGUiLCJyYXdVc2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvOTEuMC40NDcyLjEyNCBTYWZhcmkvNTM3LjM2In0sImdkcHIiOnsiaGFzQ29uc2VudCI6dHJ1ZX0sIndpbiI6ZmFsc2UsImFkSWQiOjU2NDgsImFkdmVydGlzZXJJZCI6MSwiY2FtcGFpZ25JZCI6MSwiY3JlYXRpdmVJZCI6MjgyNSwiZXJyb3IiOmZhbHNlfX0.-UefQH4G0k-RJGemBYffs-KL7EEwma2Wuwgk2xnpij8' + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjgxNzA4MzEsImlhdCI6MTYyNzU2NjAzMSwiaXNzIjoiYmxpaW5rIiwiZGF0YSI6eyJ0eXBlIjoiYWQtc2VydmVyIiwidHJhbnNhY3Rpb25JZCI6IjM1YmU1NDNjLTNkZTQtNGQ1Yy04N2NjLWIzYzEyOGZiYzU0MCIsIm5ldHdvcmtJZCI6MjEsInNpdGVJZCI6NTksInRhZ0lkIjo1OSwiY29va2llSWQiOiJjNGU4MWVhOS1jMjhmLTQwZDItODY1ZC1hNjQzZjE1OTcyZjUiLCJldmVudElkIjozLCJ0YXJnZXRpbmciOnsicGxhdGZvcm0iOiJXZWJzaXRlIiwiaXAiOiI3OC4xMjIuNzUuNzIiLCJ0aW1lIjoxNjI3NTY2MDMxLCJsb2NhdGlvbiI6eyJsYXRpdHVkZSI6NDguOTczOSwibG9uZ2l0dWRlIjozLjMxMTMsInJlZ2lvbiI6IkhERiIsImNvdW50cnkiOiJGUiIsImNpdHkiOiJTYXVsY2hlcnkiLCJ6aXBDb2RlIjoiMDIzMTAiLCJkZXBhcnRtZW50IjoiMDIifSwiY2l0eSI6IlNhdWxjaGVyeSIsImNvdW50cnkiOiJGUiIsImRldmljZU9zIjoibWFjT1MiLCJkZXZpY2VQbGF0Zm9ybSI6IldlYnNpdGUiLCJyYXdVc2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvOTEuMC40NDcyLjEyNCBTYWZhcmkvNTM3LjM2In0sImdkcHIiOnsiaGFzQ29uc2VudCI6dHJ1ZX0sIndpbiI6ZmFsc2UsImFkSWQiOjU2NDgsImFkdmVydGlzZXJJZCI6MSwiY2FtcGFpZ25JZCI6MSwiY3JlYXRpdmVJZCI6MjgyNSwiZXJyb3IiOmZhbHNlfX0.-UefQH4G0k-RJGemBYffs-KL7EEwma2Wuwgk2xnpij8', }, headers: {}, - } -} + }; +}; /** * @description Mockup response from API for RTB creative @@ -213,8 +225,8 @@ const getConfigInterpretResponseRTB = (noAd = false, isInvalidVast = false) => { if (noAd) { return { message: 'invalid tag', - mode: 'no-ad' - } + mode: 'no-ad', + }; } const validVast = ` @@ -229,41 +241,43 @@ const getConfigInterpretResponseRTB = (noAd = false, isInvalidVast = false) => { - ` + `; const invalidVast = ` - ` + `; return { - body: { bids: [ - { - 'creative': { - 'video': { - 'content': isInvalidVast ? invalidVast : validVast, - 'height': 250, - 'width': 300 + body: { + bids: [ + { + creative: { + video: { + content: isInvalidVast ? invalidVast : validVast, + height: 250, + width: 300, + }, + media_type: 'video', + creativeId: 0, }, - 'media_type': 'video', - 'creativeId': 0, - }, - 'price': 0, - 'id': '8121', - 'token': 'token', - 'mode': 'rtb', - 'extras': { - 'deal_id': '34567ertyaza', - 'transaction_id': '2def0c5b2a7f6e' + price: 0, + id: '8121', + token: 'token', + mode: 'rtb', + extras: { + deal_id: '34567ertyaza', + transaction_id: '2def0c5b2a7f6e', + }, + currency: 'EUR', }, - 'currency': 'EUR' - } - ], - userSyncs: []} - } -} + ], + userSyncs: [], + }, + }; +}; /** * @@ -279,9 +293,9 @@ const testsGetMetaList = [ { title: 'Should return empty array if there are no parameters', args: { - fn: getMetaList() + fn: getMetaList(), }, - want: [] + want: [], }, { title: 'Should return list of metas with name associated', @@ -313,18 +327,43 @@ const testsGetMetaList = [ key: 'property', value: `'article:${'test'}'`, }, - ] - } -] + ], + }, +]; -describe('BLIINK Adapter getMetaList', function() { +describe('BLIINK Adapter getMetaList', function () { for (const test of testsGetMetaList) { it(test.title, () => { - const res = test.args.fn - expect(res).to.eql(test.want) - }) + const res = test.args.fn; + expect(res).to.eql(test.want); + }); + } +}); +const GetUserIds = [ + { + title: 'Should return undefined if there are no parameters', + args: { + fn: getUserIds(), + }, + want: undefined, + }, + { + title: 'Should return userIds if exists', + args: { + fn: getUserIds([{ userIds: { criteoId: 'testId' } }]), + }, + want: { criteoId: 'testId' }, + }, +]; + +describe('BLIINK Adapter getUserIds', function () { + for (const test of GetUserIds) { + it(test.title, () => { + const res = test.args.fn; + expect(res).to.eql(test.want); + }); } -}) +}); /** * @description Array of tests used in describe function below @@ -349,127 +388,142 @@ const testsIsBidRequestValid = [ { title: 'isBidRequestValid format not valid', args: { - fn: spec.isBidRequestValid({}) + fn: spec.isBidRequestValid({}), }, want: false, }, { title: 'isBidRequestValid does not receive any bid', args: { - fn: spec.isBidRequestValid() + fn: spec.isBidRequestValid(), }, want: false, }, { title: 'isBidRequestValid Receive a valid bid', args: { - fn: spec.isBidRequestValid(getConfigBid('banner')) + fn: spec.isBidRequestValid(getConfigBid('banner')), }, want: true, - } -] + }, +]; -describe('BLIINK Adapter isBidRequestValid', function() { +describe('BLIINK Adapter isBidRequestValid', function () { for (const test of testsIsBidRequestValid) { it(test.title, () => { - const res = test.args.fn - expect(res).to.eql(test.want) - }) + const res = test.args.fn; + expect(res).to.eql(test.want); + }); } -}) +}); -const vastXml = getConfigInterpretResponseRTB().body.bids[0].creative.video.content +const vastXml = + getConfigInterpretResponseRTB().body.bids[0].creative.video.content; const testsInterpretResponse = [ { title: 'Should construct bid for video instream', args: { - fn: spec.interpretResponse(getConfigInterpretResponseRTB(false)) + fn: spec.interpretResponse(getConfigInterpretResponseRTB(false)), }, - want: [{ - cpm: 0, - currency: 'EUR', - height: 250, - width: 300, - creativeId: '34567ertyaza', - mediaType: 'video', - netRevenue: true, - requestId: '2def0c5b2a7f6e', - ttl: 300, - vastXml, - vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(vastXml.replace(/\\"/g, '"')) - }] + want: [ + { + cpm: 0, + currency: 'EUR', + height: 250, + width: 300, + creativeId: '34567ertyaza', + mediaType: 'video', + netRevenue: true, + requestId: '2def0c5b2a7f6e', + ttl: 300, + vastXml, + vastUrl: + 'data:text/xml;charset=utf-8;base64,' + + btoa(vastXml.replace(/\\"/g, '"')), + }, + ], }, { title: 'ServerResponse with message: invalid tag, return empty array', args: { - fn: spec.interpretResponse(getConfigInterpretResponse(true)) + fn: spec.interpretResponse(getConfigInterpretResponse(true)), }, - want: [] + want: [], }, { title: 'ServerResponse with mediaType banner', args: { - fn: spec.interpretResponse({body: {bids: [getConfigBannerBid()]}}), + fn: spec.interpretResponse({ body: { bids: [getConfigBannerBid()] } }), }, - want: [{ - ad: '', - cpm: 1, - creativeId: '34567erty', - currency: 'EUR', - height: 250, - mediaType: 'banner', - netRevenue: true, - requestId: '2def0c5b2a7f6e', - ttl: 300, - width: 300 - }] + want: [ + { + ad: '', + cpm: 1, + creativeId: '34567erty', + currency: 'EUR', + height: 250, + mediaType: 'banner', + netRevenue: true, + requestId: '2def0c5b2a7f6e', + ttl: 300, + width: 300, + }, + ], }, { title: 'ServerResponse with unhandled mediaType, return empty array', args: { - fn: spec.interpretResponse({body: {bids: [{...getConfigBannerBid(), - creative: { - unknown: { - adm: '', - height: 250, - width: 300, - }, - media_type: 'unknown', - creativeId: 125, - requestId: '2def0c5b2a7f6e', - }}]}}), + fn: spec.interpretResponse({ + body: { + bids: [ + { + ...getConfigBannerBid(), + creative: { + unknown: { + adm: '', + height: 250, + width: 300, + }, + media_type: 'unknown', + creativeId: 125, + requestId: '2def0c5b2a7f6e', + }, + }, + ], + }, + }), }, - want: [] + want: [], }, -] +]; -describe('BLIINK Adapter interpretResponse', function() { +describe('BLIINK Adapter interpretResponse', function () { for (const test of testsInterpretResponse) { it(test.title, () => { - const res = test.args.fn + const res = test.args.fn; if (res) { - expect(res).to.eql(test.want) + expect(res).to.eql(test.want); } - }) + }); } -}) +}); /** * @description Array of tests used in describe function below * @type {[ * {args: * {fn: { - * cpm: number, - * netRevenue: boolean, - * ad, requestId, - * meta: {mediaType}, - * width: number, - * currency: string, - * ttl: number, - * creativeId: number, - * height: number + * cpm: number, + * netRevenue: boolean, + * ad, requestId, + * meta: {mediaType}, + * width: number, + * currency: string, + * ttl: number, + * creativeId: number, + * height: number * } * }, want, title: string}]} */ @@ -478,21 +532,26 @@ const testsBuildBid = [ { title: 'Should return null if no bid passed in parameters', args: { - fn: buildBid() + fn: buildBid(), }, - want: null + want: null, }, { title: 'Input data must respect the output model', args: { - fn: buildBid({ id: 1, test: '123' }, { id: 2, test: '345' }, false, false) + fn: buildBid( + { id: 1, test: '123' }, + { id: 2, test: '345' }, + false, + false + ), }, - want: null + want: null, }, { title: 'input data respect the output model for video', args: { - fn: buildBid(getConfigVideoBid('video'), getConfigCreativeVideo()) + fn: buildBid(getConfigVideoBid('video'), getConfigCreativeVideo()), }, want: { requestId: getConfigBid('video').bidId, @@ -504,25 +563,31 @@ const testsBuildBid = [ creativeId: getConfigVideoBid().extras.deal_id, netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, - vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), + vastUrl: + 'data:text/xml;charset=utf-8;base64,' + + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), ttl: 300, - } + }, }, { title: 'use default height width output model for video', args: { - fn: buildBid({...getConfigVideoBid('video'), - creative: { - video: { - content: - '', - height: null, - width: null, + fn: buildBid( + { + ...getConfigVideoBid('video'), + creative: { + video: { + content: '', + height: null, + width: null, + }, + media_type: 'video', + creativeId: getConfigVideoBid().extras.deal_id, + requestId: '2def0c5b2a7f6e', }, - media_type: 'video', - creativeId: getConfigVideoBid().extras.deal_id, - requestId: '2def0c5b2a7f6e', - }}, getConfigCreativeVideo()) + }, + getConfigCreativeVideo() + ), }, want: { requestId: getConfigBid('video').bidId, @@ -534,14 +599,16 @@ const testsBuildBid = [ creativeId: getConfigVideoBid().extras.deal_id, netRevenue: true, vastXml: getConfigCreativeVideo().vastXml, - vastUrl: 'data:text/xml;charset=utf-8;base64,' + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), + vastUrl: + 'data:text/xml;charset=utf-8;base64,' + + btoa(getConfigCreativeVideo().vastXml.replace(/\\"/g, '"')), ttl: 300, - } + }, }, { title: 'input data respect the output model for banner', args: { - fn: buildBid(getConfigBannerBid()) + fn: buildBid(getConfigBannerBid()), }, want: { requestId: getConfigBid('banner').bidId, @@ -554,18 +621,18 @@ const testsBuildBid = [ ad: getConfigBannerBid().creative.banner.adm, ttl: 300, netRevenue: true, - } - } -] + }, + }, +]; -describe('BLIINK Adapter buildBid', function() { +describe('BLIINK Adapter buildBid', function () { for (const test of testsBuildBid) { it(test.title, () => { - const res = test.args.fn - expect(res).to.eql(test.want) - }) + const res = test.args.fn; + expect(res).to.eql(test.want); + }); } -}) +}); /** * @description Array of tests used in describe function below @@ -575,28 +642,32 @@ const testsBuildRequests = [ { title: 'Should not build request, no bidder request exist', args: { - fn: spec.buildRequests() + fn: spec.buildRequests(), }, - want: null + want: null, }, { title: 'Should build request if bidderRequest exist', args: { - fn: spec.buildRequests([], getConfigBuildRequest('banner')) + fn: spec.buildRequests([], getConfigBuildRequest('banner')), }, want: { method: 'POST', url: BLIINK_ENDPOINT_ENGINE, data: { + ect: connectionType, keywords: '', pageDescription: '', pageTitle: '', - pageUrl: 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', tags: [ { transactionId: '2def0c5b2a7f6e', + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, id: '14f30eca-85d2-11e8-9eed-0242ac120007', - imageUrl: '', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', mediaTypes: ['banner'], sizes: [ { @@ -605,35 +676,42 @@ const testsBuildRequests = [ }, ], }, - ] - } - } + ], + }, + }, }, { title: 'Should build request width GDPR configuration', args: { - fn: spec.buildRequests([], Object.assign(getConfigBuildRequest('banner'), { - gdprConsent: { - gdprApplies: true, - consentString: 'XXXX' - }, - })) + fn: spec.buildRequests( + [], + Object.assign(getConfigBuildRequest('banner'), { + gdprConsent: { + gdprApplies: true, + consentString: 'XXXX', + }, + }) + ), }, want: { method: 'POST', url: BLIINK_ENDPOINT_ENGINE, data: { + ect: connectionType, gdpr: true, gdprConsent: 'XXXX', pageDescription: '', pageTitle: '', keywords: '', - pageUrl: 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', tags: [ { transactionId: '2def0c5b2a7f6e', + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, id: '14f30eca-85d2-11e8-9eed-0242ac120007', - imageUrl: '', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', mediaTypes: ['banner'], sizes: [ { @@ -642,52 +720,113 @@ const testsBuildRequests = [ }, ], }, - ] - } - } + ], + }, + }, + }, + { + title: 'Should build request width uspConsent if exists', + args: { + fn: spec.buildRequests( + [], + Object.assign(getConfigBuildRequest('banner'), { + gdprConsent: { + gdprApplies: true, + consentString: 'XXXX', + }, + uspConsent: 'uspConsent', + }) + ), + }, + want: { + method: 'POST', + url: BLIINK_ENDPOINT_ENGINE, + data: { + ect: connectionType, + gdpr: true, + uspConsent: 'uspConsent', + gdprConsent: 'XXXX', + pageDescription: '', + pageTitle: '', + keywords: '', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + tags: [ + { + transactionId: '2def0c5b2a7f6e', + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, + id: '14f30eca-85d2-11e8-9eed-0242ac120007', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', + mediaTypes: ['banner'], + sizes: [ + { + h: 250, + w: 300, + }, + ], + }, + ], + }, + }, }, { title: 'Should build request width schain if exists', args: { - fn: spec.buildRequests([{schain: { - ver: '1.0', - complete: 1, - nodes: [{ - asi: 'ssp.test', - sid: '00001', - hp: 1 - }] - }}], Object.assign(getConfigBuildRequest('banner'), { - gdprConsent: { - gdprApplies: true, - consentString: 'XXXX' - }, - })) + fn: spec.buildRequests( + [ + { + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'ssp.test', + sid: '00001', + hp: 1, + }, + ], + }, + }, + ], + Object.assign(getConfigBuildRequest('banner'), { + gdprConsent: { + gdprApplies: true, + consentString: 'XXXX', + }, + }) + ), }, want: { method: 'POST', url: BLIINK_ENDPOINT_ENGINE, data: { + ect: connectionType, gdpr: true, gdprConsent: 'XXXX', pageDescription: '', pageTitle: '', keywords: '', - pageUrl: 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', schain: { ver: '1.0', complete: 1, - nodes: [{ - asi: 'ssp.test', - sid: '00001', - hp: 1 - }] + nodes: [ + { + asi: 'ssp.test', + sid: '00001', + hp: 1, + }, + ], }, tags: [ { transactionId: '2def0c5b2a7f6e', + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, id: '14f30eca-85d2-11e8-9eed-0242ac120007', - imageUrl: '', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', mediaTypes: ['banner'], sizes: [ { @@ -696,107 +835,276 @@ const testsBuildRequests = [ }, ], }, - ] - } - } - } -] + ], + }, + }, + }, + { + title: 'Should build request with userIds if exists', + args: { + fn: spec.buildRequests( + [ + { + userIds: { + criteoId: + 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG', + netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', + }, + }, + ], + Object.assign(getConfigBuildRequest('banner'), { + gdprConsent: { + gdprApplies: true, + consentString: 'XXXX', + }, + }) + ), + }, + want: { + method: 'POST', + url: BLIINK_ENDPOINT_ENGINE, + data: { + ect: connectionType, + gdpr: true, + gdprConsent: 'XXXX', + pageDescription: '', + pageTitle: '', + keywords: '', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + userIds: { + criteoId: 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG', + netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', + }, + tags: [ + { + transactionId: '2def0c5b2a7f6e', + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, + id: '14f30eca-85d2-11e8-9eed-0242ac120007', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', + mediaTypes: ['banner'], + sizes: [ + { + h: 250, + w: 300, + }, + ], + }, + ], + }, + }, + }, +]; -describe('BLIINK Adapter buildRequests', function() { +describe('BLIINK Adapter buildRequests', function () { for (const test of testsBuildRequests) { it(test.title, () => { - const res = test.args.fn - expect(res).to.eql(test.want) - }) + const res = test.args.fn; + expect(res).to.eql(test.want); + test.args.after; + }); } -}) +}); const getSyncOptions = (pixelEnabled = true, iframeEnabled = false) => { return { pixelEnabled, - iframeEnabled - } -} + iframeEnabled, + }; +}; const getServerResponses = () => { return [ { - body: {bids: [], - userSyncs: [ { - type: 'script', - url: 'https://prg.smartadserver.com/ac?out=js&nwid=3392&siteid=305791&pgname=rg&fmtid=81127&tgt=[sas_target]&visit=m&tmstp=[timestamp]&clcturl=[countgo]' - }, - { - type: 'image', - url: 'https://sync.smartadserver.com/getuid?nwid=3392&consentString=XXX&url=https%3A%2F%2Fcookiesync.api.bliink.io%2Fcookiesync%3Fpartner%3Dsmart%26uid%3D%5Bsas_uid%5D' - }]}, - } - ] -} + body: { + bids: [], + userSyncs: [ + { + type: 'script', + url: 'https://prg.smartadserver.com/ac?out=js&nwid=3392&siteid=305791&pgname=rg&fmtid=81127&tgt=[sas_target]&visit=m&tmstp=[timestamp]&clcturl=[countgo]', + }, + { + type: 'image', + url: 'https://sync.smartadserver.com/getuid?nwid=3392&consentString=XXX&url=https%3A%2F%2Fcookiesync.api.bliink.io%2Fcookiesync%3Fpartner%3Dsmart%26uid%3D%5Bsas_uid%5D', + }, + ], + }, + }, + ]; +}; const getGdprConsent = () => { return { gdprApplies: 1, consentString: 'XXX', - apiVersion: 2 - } -} + apiVersion: 2, + }; +}; const testsGetUserSyncs = [ { title: 'Should not have gdprConsent exist', args: { - fn: spec.getUserSyncs(getSyncOptions(), getServerResponses(), getGdprConsent()) + fn: spec.getUserSyncs( + getSyncOptions(), + getServerResponses(), + getGdprConsent() + ), }, want: [ { type: 'script', - url: 'https://prg.smartadserver.com/ac?out=js&nwid=3392&siteid=305791&pgname=rg&fmtid=81127&tgt=[sas_target]&visit=m&tmstp=[timestamp]&clcturl=[countgo]' + url: 'https://prg.smartadserver.com/ac?out=js&nwid=3392&siteid=305791&pgname=rg&fmtid=81127&tgt=[sas_target]&visit=m&tmstp=[timestamp]&clcturl=[countgo]', }, { type: 'image', - url: 'https://sync.smartadserver.com/getuid?nwid=3392&consentString=XXX&url=https%3A%2F%2Fcookiesync.api.bliink.io%2Fcookiesync%3Fpartner%3Dsmart%26uid%3D%5Bsas_uid%5D' - } - ] + url: 'https://sync.smartadserver.com/getuid?nwid=3392&consentString=XXX&url=https%3A%2F%2Fcookiesync.api.bliink.io%2Fcookiesync%3Fpartner%3Dsmart%26uid%3D%5Bsas_uid%5D', + }, + ], }, { title: 'Should return iframe cookie sync if iframeEnabled', args: { - fn: spec.getUserSyncs(getSyncOptions(true, true), getServerResponses(), getGdprConsent()) + fn: spec.getUserSyncs( + getSyncOptions(true, true), + getServerResponses(), + getGdprConsent() + ), }, want: [ { type: 'iframe', - url: `${BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME}?gdpr=${getGdprConsent().gdprApplies}&coppa=0&gdprConsent=${getGdprConsent().consentString}&apiVersion=${getGdprConsent().apiVersion}` + url: `${BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME}?gdpr=${ + getGdprConsent().gdprApplies + }&coppa=0&gdprConsent=${getGdprConsent().consentString}&apiVersion=${ + getGdprConsent().apiVersion + }`, }, - ] + ], }, { title: 'ccpa', args: { - fn: spec.getUserSyncs(getSyncOptions(true, true), getServerResponses(), getGdprConsent(), 'ccpa-consent') + fn: spec.getUserSyncs( + getSyncOptions(true, true), + getServerResponses(), + getGdprConsent(), + 'ccpa-consent' + ), }, want: [ { type: 'iframe', - url: `${BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME}?gdpr=${getGdprConsent().gdprApplies}&coppa=0&uspConsent=ccpa-consent&gdprConsent=${getGdprConsent().consentString}&apiVersion=${getGdprConsent().apiVersion}` + url: `${BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME}?gdpr=${ + getGdprConsent().gdprApplies + }&coppa=0&uspConsent=ccpa-consent&gdprConsent=${ + getGdprConsent().consentString + }&apiVersion=${getGdprConsent().apiVersion}`, }, - ] + ], }, { title: 'Should output sync if no gdprConsent', args: { - fn: spec.getUserSyncs(getSyncOptions(), getServerResponses()) + fn: spec.getUserSyncs(getSyncOptions(), getServerResponses()), }, - want: getServerResponses()[0].body.userSyncs - } -] + want: getServerResponses()[0].body.userSyncs, + }, + { + title: 'Should output empty array if no pixelEnabled', + args: { + fn: spec.getUserSyncs({}, getServerResponses()), + }, + want: [], + }, +]; -describe('BLIINK Adapter getUserSyncs', function() { +describe('BLIINK Adapter getUserSyncs', function () { for (const test of testsGetUserSyncs) { it(test.title, () => { - const res = test.args.fn - expect(res).to.eql(test.want) - }) + const res = test.args.fn; + expect(res).to.eql(test.want); + }); + } +}); + +describe('BLIINK Adapter keywords & coppa true', function () { + it('Should build request with keyword and coppa true if exist', () => { + const metaElement = document.createElement('meta'); + metaElement.name = 'keywords'; + metaElement.content = 'Bliink, Saber, Prebid'; + sinon.stub(config, 'getConfig').withArgs('coppa').returns(true); + + const querySelectorStub = sinon + .stub(document, 'querySelector') + .returns(metaElement); + expect( + spec.buildRequests( + [], + Object.assign(getConfigBuildRequest('banner'), { + gdprConsent: { + gdprApplies: true, + consentString: 'XXXX', + }, + }) + ) + ).to.eql({ + method: 'POST', + url: BLIINK_ENDPOINT_ENGINE, + data: { + ect: connectionType, + gdpr: true, + coppa: 1, + gdprConsent: 'XXXX', + pageDescription: 'Bliink, Saber, Prebid', + pageTitle: '', + keywords: 'Bliink,Saber,Prebid', + pageUrl: + 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true', + tags: [ + { + transactionId: '2def0c5b2a7f6e', + id: '14f30eca-85d2-11e8-9eed-0242ac120007', + imageUrl: 'https://www.example.com/adimage.jpg', + videoUrl: 'https://www.example.com/advideo.mp4', + mediaTypes: ['banner'], + refresh: window.bliinkBid['14f30eca-85d2-11e8-9eed-0242ac120007'] || undefined, + sizes: [ + { + h: 250, + w: 300, + }, + ], + }, + ], + }, + }); + querySelectorStub.restore(); + config.getConfig.restore(); + }); +}); + +describe('getEffectiveConnectionType', () => { + let navigatorStub; + + beforeEach(() => { + if ('connection' in navigator) { + navigatorStub = sinon.stub(navigator, 'connection').value({ + effectiveType: undefined, + }); + } + }); + + afterEach(() => { + if (navigatorStub) { + navigatorStub.restore(); + } + }); + if (navigatorStub) { + it('should return "unsupported" when effective connection type is undefined', () => { + const result = getEffectiveConnectionType(); + expect(result).to.equal('unsupported'); + }); } -}) +});