From 68717af5d2dce425c82672275f0e0eb809448449 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 8 Aug 2019 18:35:01 +0300 Subject: [PATCH 01/25] -- first commit --- modules/videoNowBidAdapter.js | 156 ++++++++++++++++++++++++++++++++++ test/pages/outstream.html | 152 +++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 modules/videoNowBidAdapter.js create mode 100755 test/pages/outstream.html diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js new file mode 100644 index 00000000000..93232257dc6 --- /dev/null +++ b/modules/videoNowBidAdapter.js @@ -0,0 +1,156 @@ +import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory'; +// import { config } from 'src/config'; +import { BANNER } from '../src/mediaTypes' + +// const VIDEONOW_CALLBACK_NAME = 'videoNowResponse' +// const VIDEONOW_REQUESTS_MAP = 'videoNowRequests' + +// import { addBidResponse } from '../src/bidmanager' +// import { registerBidAdapter } from '../src/adaptermanager' + +// const RTB_URL = 'localhost:8085/bid' // 'rtb.videonow.com/bid' +// const RTB_URL = 'rtb.videonow.com/bid' +const RTB_URL = 'poligon.videonow.ru/tests/hbiding.php' // 'localhost:8085/bid' // 'rtb.videonow.com/bid' + +const BIDDER_CODE = 'videoNow' +const TTL_SECONDS = 60 * 5; + +function isBidRequestValid(bid) { + const params = bid.params || {}; + return !!(params.cId /* && params.pId */); +} + +function buildRequest(bid, size, bidderRequest) { + const {params, bidId} = bid; + const {bidFloor, cId} = params; + const [width, height] = size.split('x'); + + const dto = { + method: 'GET', + url: `${RTB_URL}/${cId}`, + data: { + cb: Date.now(), + bidFloor: bidFloor, + bidId: bidId, + // publisherId: pId, + consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString, + width, + height + } + } + // utils._each(ext, (value, key) => { + // dto.data['ext.' + key] = value; + // }); + // + return dto; +} + +function buildRequests(validBidRequests, bidderRequest) { + // const topWindowUrl = utils.getTopWindowUrl(); + const requests = []; + validBidRequests.forEach(validBidRequest => { + const sizes = utils.parseSizesInput(validBidRequest.sizes); + sizes.forEach(size => { + const request = buildRequest(validBidRequest, size, bidderRequest); + requests.push(request); + }); + }); + return requests; +} + +function interpretResponse(serverResponse, bidRequest) { + if (!serverResponse || !serverResponse.body) { + return []; + } + const {crid: creativeId, ad, price, exp, ext} = serverResponse.body; + + if (!ad || !price) { + return []; + } + const { adm } = ext + const {bidId, width, height, cur} = bidRequest.data; + + try { + return [{ + requestId: bidId, + cpm: price, + width: width, + height: height, + creativeId: creativeId, + currency: cur || 'RUB', + netRevenue: true, + ttl: exp || TTL_SECONDS, + ad: ad, + renderer: { + url: adm.vastUrl, + /** + * injects javascript code into page + * + * @param bid + */ + render: function(bid) { + const d = window.top.document + const elem = d.createElement('script') + const params = {} + adm.moduleUrl && (params['data-module-url'] = adm.moduleUrl) + adm.vast && (params['data-vast'] = JSON.stringify(adm.vast)) + adm.vastUrl && (params['data-vast-url'] = adm.vastUrl) + adm.options && (params['data-opts'] = JSON.stringify(adm.options)) + Object.keys(params).forEach(key => elem.setAttribute(key, params[key])) + elem.src = adm.init + d.head.appendChild(elem) + } + } + } + ]; + } catch (e) { + return []; + } +} + +export const spec = { + code: BIDDER_CODE, + aliases: ['videonow'], // short code + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs: function(syncOptions, serverResponses) { + + }, + onTimeout: function(timeoutData) {}, + onBidWon: function(bid) { + + }, + onSetTargeting: function(bid) {} +} + +registerBidder(spec); + +// const json = { +// 'id': '2955a162-699e-4811-ce88-5c3ac973e73c', +// 'seatbid': [{ +// 'bid': [{ +// 'id': '1', +// 'impid': '0005110c-8db7-44d8-d47c-cea0908dea9e', +// 'price': 0.1, +// 'adid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', +// 'nurl': 'http://rtb.videonow.ru/?profile_id=111', +// 'adomain': ['www.paulig.ru'], +// 'ext': { +// 'pixels': ['http://sync.videonow.ru/ssp?uuid=1&dsp_id=1', 'http://sync.videonow.ru/ssp?uuid=1&dsp_id=2'], +// adm: { +// vastUrl: 'vast', +// moduleUrl: 'vn_module.js' +// } +// }, +// 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', +// }], +// 'group': 0, +// }], +// 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', +// 'cur': 'USD', +// } + +// const bidResponse = JSON.stringify(json) diff --git a/test/pages/outstream.html b/test/pages/outstream.html new file mode 100755 index 00000000000..72a0c86943f --- /dev/null +++ b/test/pages/outstream.html @@ -0,0 +1,152 @@ + + + + + + Prebid.js video adUnit example + + + + + + + + + + + + + + + + + + +

Prebid Video -- video.js

+
Bid Response
+

HEADERBIDDINGЕмкость рынка, пренебрегая деталями, деятельно программирует типичный имидж предприятия. Стимулирование + коммьюнити изящно развивает культурный потребительский рынок. Исходя из структуры пирамиды Маслоу, экспертиза + выполненного проекта синхронизирует принцип восприятия, опираясь на опыт западных коллег. Примерная структура + маркетингового исследования, отбрасывая подробности, очевидна не для всех. Системный анализ вполне вероятен. + +

Нестандартный подход, следовательно, существенно поддерживает клиентский спрос. Поисковая реклама переворачивает + повторный контакт. Мониторинг активности уравновешивает нестандартный подход, осознав маркетинг как часть + производства. Привлечение аудитории недостижимо. + +

Выставка позитивно детерминирует конвергентный рейтинг. Организация службы маркетинга охватывает экспериментальный + поведенческий таргетинг. Ребрендинг ригиден. + +

Лидерство в продажах, отбрасывая подробности, редко соответствует рыночным ожиданиям. Корпоративная культура, + пренебрегая деталями, слабо ускоряет институциональный показ баннера, опираясь на опыт западных коллег. В + соответствии с законом Ципфа, департамент маркетинга и продаж директивно изменяет клиентский спрос. + +

Портрет потребителя усиливает принцип восприятия, размещаясь во всех медиа. Стратегическое планирование, суммируя + приведенные примеры, нетривиально. Общество потребления искажает межличностный SWOT-анализ. По мнению ведущих + маркетологов, спонсорство усиливает продвигаемый имидж. + +

Искусство медиапланирования раскручивает бюджет на размещение. Производство притягивает экспериментальный + рекламоноситель. Надо сказать, что основная стадия проведения рыночного исследования синхронизирует баинг и селлинг. + Как предсказывают футурологи план размещения ригиден как никогда. Дело в том, что ассортиментная политика + предприятия поддерживает эмпирический медиаплан. + +

Медийная связь индуктивно ускоряет ребрендинг. Создание приверженного покупателя, следовательно, переворачивает + рекламный клаттер. Размещение уравновешивает комплексный сегмент рынка. Потребление стремительно восстанавливает + эмпирический клиентский спрос. +

+
SUUUUXXXXXX
+
+ + + + + +

Стимулирование коммьюнити допускает рыночный комплексный анализ ситуации. Представляется логичным, что рекламная + акция специфицирует популярный побочный PR-эффект. Потребление, вопреки мнению П.Друкера, достижимо в разумные + сроки. + +

В соответствии с законом Ципфа, баинг и селлинг вполне вероятен. В общем, охват аудитории директивно синхронизирует + бренд, используя опыт предыдущих кампаний. Медиавес естественно обуславливает формат события. В рамках концепции + Акоффа и Стэка, узнавание бренда ускоряет повседневный конкурент, повышая конкуренцию. + +

Наряду с этим, пул лояльных изданий вполне вероятен. Можно предположить, что особенность рекламы интуитивно + концентрирует медиабизнес. Контент интуитивно концентрирует жизненный цикл продукции. Согласно последним + исследованиям, процесс стратегического планирования деятельно концентрирует показ баннера. Селекция бренда, суммируя + приведенные примеры, редко соответствует рыночным ожиданиям. + +

Фирменный стиль индуцирует ролевой клиентский спрос. Идеология выстраивания бренда подсознательно индуцирует ролевой + системный анализ. Стратегическое планирование, на первый взгляд, притягивает стратегический рыночный план. Пул + лояльных изданий, в рамках сегодняшних воззрений, довольно неоднозначен. + +

Ребрендинг сфокусирован. Комплексный анализ ситуации, следовательно, специфицирует конструктивный системный анализ. + Конкурентоспособность синхронизирует презентационный материал. + +

SWOT-анализ, анализируя результаты рекламной кампании, основан на анализе телесмотрения. Конкурентоспособность слабо + обуславливает потребительский рынок. Искусство медиапланирования, анализируя результаты рекламной кампании, + нейтрализует повседневный рекламный клаттер, признавая определенные рыночные тенденции. Можно предположить, что + стратегический маркетинг переворачивает целевой трафик. По сути, сегментация рынка концентрирует коллективный + медиабизнес. + +

Эволюция мерчандайзинга индуцирует рыночный стратегический рыночный план. Соц-дем характеристика аудитории + нейтрализует потребительский комплексный анализ ситуации. До недавнего времени считалось, что имидж предприятия + концентрирует поведенческий таргетинг. + +

Восприятие марки не критично. Примерная структура маркетингового исследования нейтрализует комплексный анализ + зарубежного опыта, осознав маркетинг как часть производства. Стимулирование коммьюнити, анализируя результаты + рекламной кампании, достижимо в разумные сроки. В рамках концепции Акоффа и Стэка, информационная связь с + потребителем сознательно ускоряет принцип восприятия. + HEADERBIDDING + + + + From e49d26af0f9bc3eb4dfc9da6d5fb094d6251aaaa Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 8 Aug 2019 19:29:24 +0300 Subject: [PATCH 02/25] -- cors and bidder's name fixed --- modules/videoNowBidAdapter.js | 9 ++-- test/pages/outstream.html | 95 +++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 93232257dc6..feb127c4f92 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -9,11 +9,11 @@ import { BANNER } from '../src/mediaTypes' // import { addBidResponse } from '../src/bidmanager' // import { registerBidAdapter } from '../src/adaptermanager' -// const RTB_URL = 'localhost:8085/bid' // 'rtb.videonow.com/bid' +const RTB_URL = '//localhost:8085/bid' // 'rtb.videonow.com/bid' // const RTB_URL = 'rtb.videonow.com/bid' -const RTB_URL = 'poligon.videonow.ru/tests/hbiding.php' // 'localhost:8085/bid' // 'rtb.videonow.com/bid' +// const RTB_URL = '//poligon.videonow.ru/tests/hbiding.php' // 'localhost:8085/bid' // 'rtb.videonow.com/bid' -const BIDDER_CODE = 'videoNow' +const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5; function isBidRequestValid(bid) { @@ -28,7 +28,7 @@ function buildRequest(bid, size, bidderRequest) { const dto = { method: 'GET', - url: `${RTB_URL}/${cId}`, + url: RTB_URL, // /${cId}`, data: { cb: Date.now(), bidFloor: bidFloor, @@ -47,6 +47,7 @@ function buildRequest(bid, size, bidderRequest) { } function buildRequests(validBidRequests, bidderRequest) { + console.log('buildRequests') // const topWindowUrl = utils.getTopWindowUrl(); const requests = []; validBidRequests.forEach(validBidRequest => { diff --git a/test/pages/outstream.html b/test/pages/outstream.html index 72a0c86943f..7355246027d 100755 --- a/test/pages/outstream.html +++ b/test/pages/outstream.html @@ -21,53 +21,62 @@ From 1654ea5a6a220136b8622f7f98ea19f523bac1e1 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Fri, 9 Aug 2019 17:32:31 +0300 Subject: [PATCH 03/25] -- almost ready --- modules/videoNowBidAdapter.js | 82 +++++++++++------ test/pages/outstream.html | 161 ---------------------------------- 2 files changed, 53 insertions(+), 190 deletions(-) delete mode 100755 test/pages/outstream.html diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index feb127c4f92..e16789d7638 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -18,23 +18,26 @@ const TTL_SECONDS = 60 * 5; function isBidRequestValid(bid) { const params = bid.params || {}; - return !!(params.cId /* && params.pId */); + return !!(params.cId); } function buildRequest(bid, size, bidderRequest) { - const {params, bidId} = bid; - const {bidFloor, cId} = params; + const {params, bidId, bidFloor, cId, url: rtbUrl} = bid; + const {placementId} = params || {}; const [width, height] = size.split('x'); + let url = rtbUrl || RTB_URL + url = `${url}${~url.indexOf('?') ? '&' : '?'}cId=${cId}` const dto = { method: 'GET', - url: RTB_URL, // /${cId}`, + url, data: { cb: Date.now(), - bidFloor: bidFloor, + bidFloor, + placementId, bidId: bidId, // publisherId: pId, - consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString, + // consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString, width, height } @@ -64,49 +67,70 @@ function interpretResponse(serverResponse, bidRequest) { if (!serverResponse || !serverResponse.body) { return []; } - const {crid: creativeId, ad, price, exp, ext} = serverResponse.body; + const { bidId, width, height, placementId } = (bidRequest && bidRequest.data) || {} + if (!bidId) return [] - if (!ad || !price) { - return []; - } - const { adm } = ext - const {bidId, width, height, cur} = bidRequest.data; + const {seatbid, cur} = serverResponse.body; + + if (!seatbid || !seatbid.length) return [] + const bids = [] + seatbid.forEach(sb => { + const { bid } = sb + if (bid && bid.length) { + bid.forEach(b => { + const res = createResponseBid(b, bidId, cur, width, height, placementId) + bids.push(res) + }) + } + }) + + return bids +} + +function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { + const {id, code, price, crid, adm, ttl, netRevenue} = bidInfo + + if (!id || !price) { + return null; + } + const { dataUrl, vastUrl, moduleUrl, vast, options, profileId } = adm || {} try { - return [{ + return { requestId: bidId, cpm: price, width: width, height: height, - creativeId: creativeId, + creativeId: crid, currency: cur || 'RUB', - netRevenue: true, - ttl: exp || TTL_SECONDS, - ad: ad, + netRevenue: netRevenue !== undefined ? netRevenue : true, + ttl: ttl || TTL_SECONDS, + ad: code, renderer: { - url: adm.vastUrl, + url: dataUrl || vastUrl, /** * injects javascript code into page * - * @param bid */ - render: function(bid) { - const d = window.top.document + render: function() { + const d = window.document const elem = d.createElement('script') const params = {} - adm.moduleUrl && (params['data-module-url'] = adm.moduleUrl) - adm.vast && (params['data-vast'] = JSON.stringify(adm.vast)) - adm.vastUrl && (params['data-vast-url'] = adm.vastUrl) - adm.options && (params['data-opts'] = JSON.stringify(adm.options)) + dataUrl && (params['data-url'] = dataUrl) + moduleUrl && (params['data-module-url'] = moduleUrl) + vast && (params['data-vast'] = JSON.stringify(vast)) + vastUrl && (params['data-vast-url'] = vastUrl) + options && (params['data-opts'] = JSON.stringify(options)) Object.keys(params).forEach(key => elem.setAttribute(key, params[key])) - elem.src = adm.init - d.head.appendChild(elem) + elem.src = adm.init + (profileId ? `?profileId=${profileId}` : '') + const el = placementId ? d.getElementById(placementId) : d.head; + + (el || d.head).appendChild(elem) } } } - ]; } catch (e) { - return []; + return null } } diff --git a/test/pages/outstream.html b/test/pages/outstream.html deleted file mode 100755 index 7355246027d..00000000000 --- a/test/pages/outstream.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - Prebid.js video adUnit example - - - - - - - - - - - - - - - - - - -

Prebid Video -- video.js

-
Bid Response
-

HEADERBIDDINGЕмкость рынка, пренебрегая деталями, деятельно программирует типичный имидж предприятия. Стимулирование - коммьюнити изящно развивает культурный потребительский рынок. Исходя из структуры пирамиды Маслоу, экспертиза - выполненного проекта синхронизирует принцип восприятия, опираясь на опыт западных коллег. Примерная структура - маркетингового исследования, отбрасывая подробности, очевидна не для всех. Системный анализ вполне вероятен. - -

Нестандартный подход, следовательно, существенно поддерживает клиентский спрос. Поисковая реклама переворачивает - повторный контакт. Мониторинг активности уравновешивает нестандартный подход, осознав маркетинг как часть - производства. Привлечение аудитории недостижимо. - -

Выставка позитивно детерминирует конвергентный рейтинг. Организация службы маркетинга охватывает экспериментальный - поведенческий таргетинг. Ребрендинг ригиден. - -

Лидерство в продажах, отбрасывая подробности, редко соответствует рыночным ожиданиям. Корпоративная культура, - пренебрегая деталями, слабо ускоряет институциональный показ баннера, опираясь на опыт западных коллег. В - соответствии с законом Ципфа, департамент маркетинга и продаж директивно изменяет клиентский спрос. - -

Портрет потребителя усиливает принцип восприятия, размещаясь во всех медиа. Стратегическое планирование, суммируя - приведенные примеры, нетривиально. Общество потребления искажает межличностный SWOT-анализ. По мнению ведущих - маркетологов, спонсорство усиливает продвигаемый имидж. - -

Искусство медиапланирования раскручивает бюджет на размещение. Производство притягивает экспериментальный - рекламоноситель. Надо сказать, что основная стадия проведения рыночного исследования синхронизирует баинг и селлинг. - Как предсказывают футурологи план размещения ригиден как никогда. Дело в том, что ассортиментная политика - предприятия поддерживает эмпирический медиаплан. - -

Медийная связь индуктивно ускоряет ребрендинг. Создание приверженного покупателя, следовательно, переворачивает - рекламный клаттер. Размещение уравновешивает комплексный сегмент рынка. Потребление стремительно восстанавливает - эмпирический клиентский спрос. -

-
SUUUUXXXXXX
-
- - - - - -

Стимулирование коммьюнити допускает рыночный комплексный анализ ситуации. Представляется логичным, что рекламная - акция специфицирует популярный побочный PR-эффект. Потребление, вопреки мнению П.Друкера, достижимо в разумные - сроки. - -

В соответствии с законом Ципфа, баинг и селлинг вполне вероятен. В общем, охват аудитории директивно синхронизирует - бренд, используя опыт предыдущих кампаний. Медиавес естественно обуславливает формат события. В рамках концепции - Акоффа и Стэка, узнавание бренда ускоряет повседневный конкурент, повышая конкуренцию. - -

Наряду с этим, пул лояльных изданий вполне вероятен. Можно предположить, что особенность рекламы интуитивно - концентрирует медиабизнес. Контент интуитивно концентрирует жизненный цикл продукции. Согласно последним - исследованиям, процесс стратегического планирования деятельно концентрирует показ баннера. Селекция бренда, суммируя - приведенные примеры, редко соответствует рыночным ожиданиям. - -

Фирменный стиль индуцирует ролевой клиентский спрос. Идеология выстраивания бренда подсознательно индуцирует ролевой - системный анализ. Стратегическое планирование, на первый взгляд, притягивает стратегический рыночный план. Пул - лояльных изданий, в рамках сегодняшних воззрений, довольно неоднозначен. - -

Ребрендинг сфокусирован. Комплексный анализ ситуации, следовательно, специфицирует конструктивный системный анализ. - Конкурентоспособность синхронизирует презентационный материал. - -

SWOT-анализ, анализируя результаты рекламной кампании, основан на анализе телесмотрения. Конкурентоспособность слабо - обуславливает потребительский рынок. Искусство медиапланирования, анализируя результаты рекламной кампании, - нейтрализует повседневный рекламный клаттер, признавая определенные рыночные тенденции. Можно предположить, что - стратегический маркетинг переворачивает целевой трафик. По сути, сегментация рынка концентрирует коллективный - медиабизнес. - -

Эволюция мерчандайзинга индуцирует рыночный стратегический рыночный план. Соц-дем характеристика аудитории - нейтрализует потребительский комплексный анализ ситуации. До недавнего времени считалось, что имидж предприятия - концентрирует поведенческий таргетинг. - -

Восприятие марки не критично. Примерная структура маркетингового исследования нейтрализует комплексный анализ - зарубежного опыта, осознав маркетинг как часть производства. Стимулирование коммьюнити, анализируя результаты - рекламной кампании, достижимо в разумные сроки. В рамках концепции Акоффа и Стэка, информационная связь с - потребителем сознательно ускоряет принцип восприятия. - HEADERBIDDING - - - - From 81379755353d6ca87c15ff1e97dff3ed6f176c02 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 12 Aug 2019 19:48:03 +0300 Subject: [PATCH 04/25] -- added docs --- modules/videoNowBidAdapter.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 modules/videoNowBidAdapter.md diff --git a/modules/videoNowBidAdapter.md b/modules/videoNowBidAdapter.md new file mode 100644 index 00000000000..5f7f82f12f8 --- /dev/null +++ b/modules/videoNowBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: Videonow Bidder Adapter +Module Type: Bidder Adapter +Maintainer: info@videonow.ru +``` + +# Description + +Connect to Videonow for bids. + +The Videonow bidder adapter requires setup and approval from the videoNow team. +Please reach out to your account team or info@videonow.ru for more information. + +# Test Parameters +```javascript +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[640, 480], [300, 250], [336, 280]] + } + }, + bids: [{ + bidder: 'videonow', + pId: 1, + ext: { + placementId: '36891' + } + }] + }] +``` From ed28e3cd04ce6eaaa7b61c1a2dacbc4c052ce379 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 12 Aug 2019 19:48:35 +0300 Subject: [PATCH 05/25] -- added nurl tracking --- modules/videoNowBidAdapter.js | 102 ++++++++++++++++------------------ 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index e16789d7638..7be11d3a5a1 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,13 +1,9 @@ import * as utils from '../src/utils'; +// import {config} from '../src/config'; import { registerBidder } from '../src/adapters/bidderFactory'; -// import { config } from 'src/config'; import { BANNER } from '../src/mediaTypes' - -// const VIDEONOW_CALLBACK_NAME = 'videoNowResponse' -// const VIDEONOW_REQUESTS_MAP = 'videoNowRequests' - -// import { addBidResponse } from '../src/bidmanager' -// import { registerBidAdapter } from '../src/adaptermanager' +import { pixel } from './justpremiumBidAdapter' +// import { pixel } from './justpremiumBidAdapter' const RTB_URL = '//localhost:8085/bid' // 'rtb.videonow.com/bid' // const RTB_URL = 'rtb.videonow.com/bid' @@ -17,35 +13,34 @@ const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5; function isBidRequestValid(bid) { - const params = bid.params || {}; - return !!(params.cId); + return !!(bid.pId); } function buildRequest(bid, size, bidderRequest) { - const {params, bidId, bidFloor, cId, url: rtbUrl} = bid; - const {placementId} = params || {}; + const {refererInfo} = bidderRequest + const {ext, bidId, pId, placementId, code, url: rtbUrl} = bid; const [width, height] = size.split('x'); let url = rtbUrl || RTB_URL - url = `${url}${~url.indexOf('?') ? '&' : '?'}cId=${cId}` + url = `${url}${~url.indexOf('?') ? '&' : '?'}pId=${pId}` const dto = { method: 'GET', url, data: { + referer: refererInfo && refererInfo.referer, cb: Date.now(), - bidFloor, placementId, bidId: bidId, - // publisherId: pId, - // consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString, + code, width, height } } - // utils._each(ext, (value, key) => { - // dto.data['ext.' + key] = value; - // }); - // + + ext && Object.keys(ext).forEach(key => { + dto[key] = ext.key + }) + return dto; } @@ -89,7 +84,7 @@ function interpretResponse(serverResponse, bidRequest) { } function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { - const {id, code, price, crid, adm, ttl, netRevenue} = bidInfo + const {id, nurl, code, price, crid, adm, ttl, netRevenue} = bidInfo if (!id || !price) { return null; @@ -106,6 +101,7 @@ function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { netRevenue: netRevenue !== undefined ? netRevenue : true, ttl: ttl || TTL_SECONDS, ad: code, + nurl, renderer: { url: dataUrl || vastUrl, /** @@ -134,6 +130,35 @@ function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { } } +function getUserSyncs(syncOptions, serverResponses) { + const syncs = [] + + if (!serverResponses || !serverResponses.length) return sync + + serverResponses.forEach(response => { + const {ext} = (response && response.body) || {} + const {pixels, iframes} = ext || {} + + if (syncOptions.iframeEnabled && iframes && iframes.length) { + iframes.forEach(i => syncs.push({ + type: 'iframe', + url: i + }) + ) + } + + if (syncOptions.pixelEnabled && pixels && pixels.length) { + pixels.forEach(p => syncs.push({ + type: 'image', + url: p + }) + ) + } + }) + + return syncs; +} + export const spec = { code: BIDDER_CODE, aliases: ['videonow'], // short code @@ -141,41 +166,12 @@ export const spec = { isBidRequestValid, buildRequests, interpretResponse, - getUserSyncs: function(syncOptions, serverResponses) { - - }, + getUserSyncs, onTimeout: function(timeoutData) {}, onBidWon: function(bid) { - - }, - onSetTargeting: function(bid) {} + const { nurl } = bid + nurl && pixel.fire(nurl) + } } registerBidder(spec); - -// const json = { -// 'id': '2955a162-699e-4811-ce88-5c3ac973e73c', -// 'seatbid': [{ -// 'bid': [{ -// 'id': '1', -// 'impid': '0005110c-8db7-44d8-d47c-cea0908dea9e', -// 'price': 0.1, -// 'adid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', -// 'nurl': 'http://rtb.videonow.ru/?profile_id=111', -// 'adomain': ['www.paulig.ru'], -// 'ext': { -// 'pixels': ['http://sync.videonow.ru/ssp?uuid=1&dsp_id=1', 'http://sync.videonow.ru/ssp?uuid=1&dsp_id=2'], -// adm: { -// vastUrl: 'vast', -// moduleUrl: 'vn_module.js' -// } -// }, -// 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', -// }], -// 'group': 0, -// }], -// 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', -// 'cur': 'USD', -// } - -// const bidResponse = JSON.stringify(json) From d3d846210721ca070f887610c970e5fcf590a4a8 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Tue, 13 Aug 2019 18:22:03 +0300 Subject: [PATCH 06/25] -- bid params --- modules/videoNowBidAdapter.js | 54 +++++++++++++++++++++++------------ modules/videoNowBidAdapter.md | 4 +-- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 7be11d3a5a1..a05cafcb7fa 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -2,8 +2,6 @@ import * as utils from '../src/utils'; // import {config} from '../src/config'; import { registerBidder } from '../src/adapters/bidderFactory'; import { BANNER } from '../src/mediaTypes' -import { pixel } from './justpremiumBidAdapter' -// import { pixel } from './justpremiumBidAdapter' const RTB_URL = '//localhost:8085/bid' // 'rtb.videonow.com/bid' // const RTB_URL = 'rtb.videonow.com/bid' @@ -13,16 +11,19 @@ const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5; function isBidRequestValid(bid) { - return !!(bid.pId); + const { params } = bid || {} + return !!(params.pId); } function buildRequest(bid, size, bidderRequest) { - const {refererInfo} = bidderRequest - const {ext, bidId, pId, placementId, code, url: rtbUrl} = bid; + const { refererInfo } = bidderRequest + const { ext, bidId, params, code } = bid; const [width, height] = size.split('x'); + const { pId, placementId, bidFloor, url: rtbUrl } = params || {} let url = rtbUrl || RTB_URL url = `${url}${~url.indexOf('?') ? '&' : '?'}pId=${pId}` + const dto = { method: 'GET', url, @@ -31,6 +32,7 @@ function buildRequest(bid, size, bidderRequest) { cb: Date.now(), placementId, bidId: bidId, + bidFloor, code, width, height @@ -38,15 +40,14 @@ function buildRequest(bid, size, bidderRequest) { } ext && Object.keys(ext).forEach(key => { - dto[key] = ext.key + dto[`ext_${key}`] = ext.key }) return dto; } function buildRequests(validBidRequests, bidderRequest) { - console.log('buildRequests') - // const topWindowUrl = utils.getTopWindowUrl(); + utils.logInfo(`${BIDDER_CODE}. buildRequests`) const requests = []; validBidRequests.forEach(validBidRequest => { const sizes = utils.parseSizesInput(validBidRequest.sizes); @@ -65,7 +66,7 @@ function interpretResponse(serverResponse, bidRequest) { const { bidId, width, height, placementId } = (bidRequest && bidRequest.data) || {} if (!bidId) return [] - const {seatbid, cur} = serverResponse.body; + const { seatbid, cur } = serverResponse.body; if (!seatbid || !seatbid.length) return [] @@ -75,7 +76,7 @@ function interpretResponse(serverResponse, bidRequest) { if (bid && bid.length) { bid.forEach(b => { const res = createResponseBid(b, bidId, cur, width, height, placementId) - bids.push(res) + res && bids.push(res) }) } }) @@ -84,12 +85,22 @@ function interpretResponse(serverResponse, bidRequest) { } function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { - const {id, nurl, code, price, crid, adm, ttl, netRevenue} = bidInfo + const { id, nurl, code, price, crid, adm, ttl, netRevenue } = bidInfo if (!id || !price) { return null; } const { dataUrl, vastUrl, moduleUrl, vast, options, profileId } = adm || {} + + if (!dataUrl && !vastUrl) { + utils.logError(`${BIDDER_CODE}. createResponseBid(): Nor dataUrl neither vastUrl are not defined`) + return null + } + if (!profileId) { + utils.logError(`${BIDDER_CODE}. createResponseBid(): profileId is not defined`) + return null + } + try { return { requestId: bidId, @@ -133,7 +144,7 @@ function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { function getUserSyncs(syncOptions, serverResponses) { const syncs = [] - if (!serverResponses || !serverResponses.length) return sync + if (!serverResponses || !serverResponses.length) return syncs serverResponses.forEach(response => { const {ext} = (response && response.body) || {} @@ -156,22 +167,29 @@ function getUserSyncs(syncOptions, serverResponses) { } }) - return syncs; + utils.logInfo(`${BIDDER_CODE} getUserSyncs() syncs=${syncs.length}`) + return syncs +} + +function onBidWon(bid) { + const { nurl } = bid + if (nurl) { + const img = document.createElement('img') + img.src = nurl + img.style.cssText = 'display:none !important;' + document.body.appendChild(img) + } } export const spec = { code: BIDDER_CODE, - aliases: ['videonow'], // short code supportedMediaTypes: [BANNER], isBidRequestValid, buildRequests, interpretResponse, getUserSyncs, onTimeout: function(timeoutData) {}, - onBidWon: function(bid) { - const { nurl } = bid - nurl && pixel.fire(nurl) - } + onBidWon } registerBidder(spec); diff --git a/modules/videoNowBidAdapter.md b/modules/videoNowBidAdapter.md index 5f7f82f12f8..2ac2a431378 100644 --- a/modules/videoNowBidAdapter.md +++ b/modules/videoNowBidAdapter.md @@ -26,8 +26,8 @@ var adUnits = [ }, bids: [{ bidder: 'videonow', - pId: 1, - ext: { + params: { + pId: 1, placementId: '36891' } }] From 56b0d23039dffaa926c7370faa4f376356aec766 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Tue, 13 Aug 2019 20:36:05 +0300 Subject: [PATCH 07/25] -- tests added --- test/spec/modules/videoNowBidAdapter_spec.js | 204 +++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 test/spec/modules/videoNowBidAdapter_spec.js diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js new file mode 100644 index 00000000000..d930282106f --- /dev/null +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -0,0 +1,204 @@ +import { expect } from 'chai'; +import { spec } from 'modules/videoNowBidAdapter'; + +describe('videonowAdapterTests', function () { + describe('bidRequestValidity', function () { + it('bidRequest with pId', function () { + expect(spec.isBidRequestValid({ + bidder: 'videonow', + params: { + pId: '86858', + } + })).to.equal(true); + }); + + it('bidRequest without pId', function () { + expect(spec.isBidRequestValid({ + bidder: 'videonow', + params: { + nomater: 86858 + } + })).to.equal(false); + }); + }); + + describe('bidRequest', function () { + const validBidRequests = [{ + 'bidder': 'videonow', + 'params': { + 'pId': '1', + 'placementId': 'div-gpt-ad-1438287399331-0', + 'url': 'http://localhost:8086/bid', + 'bidFloor': 10 + }, + 'crumbs': { + 'pubcid': '9ab37692-3798-4eee-8510-9cc76e8be8f6' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480]] + } + }, + 'adUnitCode': 'test-ad', + 'transactionId': '1c48a82f-aaf0-4e70-8b13-5b63c1259fb7', + 'sizes': [[640, 480]], + 'bidId': '2dccf547f2c736', + 'bidderRequestId': '1c495372b6c6b2', + 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', + 'src': 'client', + 'bidRequestsCount': 1 + }]; + + const bidderRequest = { + 'bidderCode': 'videonow', + 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', + 'bidderRequestId': '1c495372b6c6b2', + 'bids': [ + { + 'bidder': 'videonow', + 'params': { + 'pId': '1', + 'placementId': 'div-gpt-ad-1438287399331-0', + 'url': 'http://localhost:8086/bid', + 'bidFloor': 10 + }, + 'crumbs': { + 'pubcid': '9ab37692-3798-4eee-8510-9cc76e8be8f6' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480]] } + }, + 'adUnitCode': 'test-ad', + 'transactionId': '1c48a82f-aaf0-4e70-8b13-5b63c1259fb7', + 'sizes': [[640, 480]], + 'bidId': '2dccf547f2c736', + 'bidderRequestId': '1c495372b6c6b2', + 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', + 'src': 'client', + 'bidRequestsCount': 1 + } + ], + 'auctionStart': 1565711321749, + 'timeout': 3000, + 'refererInfo': { + 'referer': 'http://localhost:8086/page', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'http://localhost:8086/page' + ] + }, + 'start': 1565711321755 + }; + + const requests = spec.buildRequests(validBidRequests, bidderRequest); + const request = (requests && requests.length && requests[0]) || {} + + it('bidRequest count', function () { + expect(requests.length).to.equal(1); + }); + + it('bidRequest method', function () { + expect(request.method).to.equal('GET'); + }); + + it('bidRequest url', function () { + expect(request.url).to.equal('http://localhost:8086/bid?pId=1'); + }); + + it('bidRequest data', function () { + const data = request.data; + const w = validBidRequests[0].sizes[0][0] + '' + const h = validBidRequests[0].sizes[0][1] + '' + + expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); + expect(data.aid).to.be.eql(validBidRequests[0].params.aid); + expect(data.bidId).to.be.eql(validBidRequests[0].bidId); + expect(data.width).to.be.eql(w); + expect(data.height).to.be.eql(h); + }); + }); + + describe('interpretResponse', function () { + const serverResponse = { + 'body': { + 'id': '111-111', + 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', + 'cur': 'RUB', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'e3bf2b82e3e9485113fad6c9b27f8768.1', + 'impid': '11111111', + 'price': 10.97, + 'nurl': 'http://localhost:8086/event/nurl', + 'netRevenue': true, + 'ttl': 800, + 'adm': { + 'profileId': 1, + 'dataUrl': 'http://localhost:8086/init', + 'init': 'http://localhost:8086/vn_init.js' + }, + 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1' + } + ], + 'group': 0 + } + ], + 'ext': { + 'pixels': [ + 'http://localhost:8086/event/pxlcookiematching?uiid=1', + 'http://localhost:8086/event/pxlcookiematching?uiid=2' + ], + 'iframes': [ + 'http://localhost:8086/event/ifrcookiematching?uiid=1', + 'http://localhost:8086/event/ifrcookiematching?uiid=2' + ] + } + }, + 'headers': {} + }; + + const bidRequest = { + 'method': 'GET', + 'url': 'http://localhost:8086/bid?pId=1', + 'data': { + 'referer': 'http://localhost:8086/page', + 'cb': 1565715456073, + 'placementId': 'div-gpt-ad-1438287399331-0', + 'bidId': '2467b82a7afaf1', + 'bidFloor': 10, + 'width': '640', + 'height': '480' + } + }; + + const result = spec.interpretResponse(serverResponse, bidRequest); + + it('Should return an empty array if empty or no bids in response', function () { + expect(spec.interpretResponse({body: ''}, {}).length).to.equal(0); + }); + + it('Should have only one bid', function () { + expect(result.length).to.equal(1); + }); + + // it('d', function() { + // const res = result[0] + // const bid = serverResponse.body.seatbid[0].bid + // expect(res).to.be.eql(bid); + // }) + // + it('Should have required keys', function () { + const bid = serverResponse.body.seatbid[0].bid[0] + const res = result[0] + expect(res.requestId).to.be.eql(bidRequest.data.bidId); + expect(res.cpm).to.be.eql(bid.price); + expect(res.creativeId).to.be.eql(bid.crid); + expect(res.netRevenue).to.be.eql(true); + expect(res.ttl).to.be.eql(bid.ttl); + }) + }); +}); From c31fbb15c1ddbe8d025d4526509c40f41375baa4 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Wed, 14 Aug 2019 19:08:24 +0300 Subject: [PATCH 08/25] -- test fixed --- modules/videoNowBidAdapter.js | 124 +++++++++-------- test/spec/modules/videoNowBidAdapter_spec.js | 137 +++++++++---------- 2 files changed, 138 insertions(+), 123 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index a05cafcb7fa..6169110e926 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,11 +1,8 @@ import * as utils from '../src/utils'; -// import {config} from '../src/config'; import { registerBidder } from '../src/adapters/bidderFactory'; import { BANNER } from '../src/mediaTypes' -const RTB_URL = '//localhost:8085/bid' // 'rtb.videonow.com/bid' -// const RTB_URL = 'rtb.videonow.com/bid' -// const RTB_URL = '//poligon.videonow.ru/tests/hbiding.php' // 'localhost:8085/bid' // 'rtb.videonow.com/bid' +const RTB_URL = 'https://bidder.videonow.ru/prebid' const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5; @@ -15,27 +12,25 @@ function isBidRequestValid(bid) { return !!(params.pId); } -function buildRequest(bid, size, bidderRequest) { +function buildRequest(bid, bidderRequest) { const { refererInfo } = bidderRequest - const { ext, bidId, params, code } = bid; - const [width, height] = size.split('x'); - const { pId, placementId, bidFloor, url: rtbUrl } = params || {} + const { ext, bidId, params, code, sizes } = bid; + const { pId, bidFloor, cur, placementId, url: rtbUrl } = params || {} let url = rtbUrl || RTB_URL - url = `${url}${~url.indexOf('?') ? '&' : '?'}pId=${pId}` + url = `${url}${~url.indexOf('?') ? '&' : '?'}profile_id=${pId}` const dto = { - method: 'GET', + method: 'POST', url, data: { - referer: refererInfo && refererInfo.referer, - cb: Date.now(), - placementId, - bidId: bidId, - bidFloor, + id: bidId, + cpm: bidFloor, code, - width, - height + sizes, + cur: cur || 'RUB', + placementId, + ref: refererInfo && refererInfo.referer } } @@ -50,11 +45,8 @@ function buildRequests(validBidRequests, bidderRequest) { utils.logInfo(`${BIDDER_CODE}. buildRequests`) const requests = []; validBidRequests.forEach(validBidRequest => { - const sizes = utils.parseSizesInput(validBidRequest.sizes); - sizes.forEach(size => { - const request = buildRequest(validBidRequest, size, bidderRequest); - requests.push(request); - }); + const request = buildRequest(validBidRequest, bidderRequest); + request && requests.push(request); }); return requests; } @@ -63,19 +55,21 @@ function interpretResponse(serverResponse, bidRequest) { if (!serverResponse || !serverResponse.body) { return []; } - const { bidId, width, height, placementId } = (bidRequest && bidRequest.data) || {} + const { id: bidId } = (bidRequest && bidRequest.data) || {} if (!bidId) return [] - const { seatbid, cur } = serverResponse.body; - + const { seatbid, cur, ext } = serverResponse.body; if (!seatbid || !seatbid.length) return [] + const { placementId } = ext || {} + if (!placementId) return [] + const bids = [] seatbid.forEach(sb => { const { bid } = sb if (bid && bid.length) { bid.forEach(b => { - const res = createResponseBid(b, bidId, cur, width, height, placementId) + const res = createResponseBid(b, bidId, cur, placementId) res && bids.push(res) }) } @@ -84,20 +78,15 @@ function interpretResponse(serverResponse, bidRequest) { return bids } -function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { - const { id, nurl, code, price, crid, adm, ttl, netRevenue } = bidInfo +function createResponseBid(bidInfo, bidId, cur, placementId) { + const { id, nurl, code, price, crid, adm, ttl, netRevenue, w, h } = bidInfo if (!id || !price) { return null; } - const { dataUrl, vastUrl, moduleUrl, vast, options, profileId } = adm || {} - if (!dataUrl && !vastUrl) { - utils.logError(`${BIDDER_CODE}. createResponseBid(): Nor dataUrl neither vastUrl are not defined`) - return null - } - if (!profileId) { - utils.logError(`${BIDDER_CODE}. createResponseBid(): profileId is not defined`) + if (!adm) { + utils.logError(`${BIDDER_CODE}. adm not exists in the response`) return null } @@ -105,8 +94,8 @@ function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { return { requestId: bidId, cpm: price, - width: width, - height: height, + width: w, + height: h, creativeId: crid, currency: cur || 'RUB', netRevenue: netRevenue !== undefined ? netRevenue : true, @@ -114,25 +103,16 @@ function createResponseBid(bidInfo, bidId, cur, width, height, placementId) { ad: code, nurl, renderer: { - url: dataUrl || vastUrl, - /** - * injects javascript code into page - * - */ + url: nurl, render: function() { const d = window.document - const elem = d.createElement('script') - const params = {} - dataUrl && (params['data-url'] = dataUrl) - moduleUrl && (params['data-module-url'] = moduleUrl) - vast && (params['data-vast'] = JSON.stringify(vast)) - vastUrl && (params['data-vast-url'] = vastUrl) - options && (params['data-opts'] = JSON.stringify(options)) - Object.keys(params).forEach(key => elem.setAttribute(key, params[key])) - elem.src = adm.init + (profileId ? `?profileId=${profileId}` : '') - const el = placementId ? d.getElementById(placementId) : d.head; - - (el || d.head).appendChild(elem) + const el = placementId && d.getElementById(placementId) + if (!el) { + console.error(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) + } + + el.innerHTML = adm + reInitScripts(el) } } } @@ -193,3 +173,39 @@ export const spec = { } registerBidder(spec); + +function reInitScripts(container, shouldReInitInlineScripts = true, delay = 10) { + const oldScripts = container.querySelectorAll('script') + const innerScriptsInsertActions = [] + + oldScripts && oldScripts.length && Array.from(oldScripts).forEach(oldScr => { + const { parentNode } = oldScr + const scriptElement = document.createElement('script') + oldScr.attributes && Array.from(oldScr.attributes).forEach(attr => { + scriptElement.setAttribute(attr.name, attr.value) + }) + + if (oldScr.src) { + innerScriptsInsertActions.push(() => { + ((function(parent, scriptElm, src) { + scriptElm.src = src + parent.appendChild(scriptElm) + })(parentNode, scriptElement, oldScr.src)) + }) + } + + if (oldScr.innerHTML && shouldReInitInlineScripts) { + innerScriptsInsertActions.push(() => { + ((function(parent, scriptElm, scriptText) { + scriptElm.innerHTML = scriptText + parent.appendChild(scriptElm) + })(parentNode, scriptElement, oldScr.innerHTML)) + }) + } + parentNode.removeChild(oldScr) + }) + + innerScriptsInsertActions.length && setTimeout(() => { + innerScriptsInsertActions.forEach(si => si()) + }, delay) +} diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index d930282106f..910ff7c11e3 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -23,36 +23,39 @@ describe('videonowAdapterTests', function () { }); describe('bidRequest', function () { - const validBidRequests = [{ - 'bidder': 'videonow', - 'params': { - 'pId': '1', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'url': 'http://localhost:8086/bid', - 'bidFloor': 10 - }, - 'crumbs': { - 'pubcid': '9ab37692-3798-4eee-8510-9cc76e8be8f6' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 480]] - } - }, - 'adUnitCode': 'test-ad', - 'transactionId': '1c48a82f-aaf0-4e70-8b13-5b63c1259fb7', - 'sizes': [[640, 480]], - 'bidId': '2dccf547f2c736', - 'bidderRequestId': '1c495372b6c6b2', - 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', - 'src': 'client', - 'bidRequestsCount': 1 - }]; + const validBidRequests = [ + { + 'bidder': 'videonow', + 'params': { + 'pId': '1', + 'placementId': 'div-gpt-ad-1438287399331-0', + 'url': 'http://localhost:8086/bid', + 'bidFloor': 10, + 'cur': 'RUB' + }, + 'crumbs': { + 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480], [320, 200]] + } + }, + 'adUnitCode': 'test-ad', + 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', + 'sizes': [[640, 480], [320, 200]], + 'bidId': '268c309f46390d', + 'bidderRequestId': '1dfdd514c36ef6', + 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', + 'src': 'client', + 'bidRequestsCount': 1 + } + ]; const bidderRequest = { 'bidderCode': 'videonow', - 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', - 'bidderRequestId': '1c495372b6c6b2', + 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', + 'bidderRequestId': '1dfdd514c36ef6', 'bids': [ { 'bidder': 'videonow', @@ -60,26 +63,28 @@ describe('videonowAdapterTests', function () { 'pId': '1', 'placementId': 'div-gpt-ad-1438287399331-0', 'url': 'http://localhost:8086/bid', - 'bidFloor': 10 + 'bidFloor': 10, + 'cur': 'RUB' }, 'crumbs': { - 'pubcid': '9ab37692-3798-4eee-8510-9cc76e8be8f6' + 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' }, 'mediaTypes': { 'banner': { - 'sizes': [[640, 480]] } + 'sizes': [[640, 480], [320, 200]] + } }, 'adUnitCode': 'test-ad', - 'transactionId': '1c48a82f-aaf0-4e70-8b13-5b63c1259fb7', - 'sizes': [[640, 480]], - 'bidId': '2dccf547f2c736', - 'bidderRequestId': '1c495372b6c6b2', - 'auctionId': '8fd34e56-ae49-4d9e-ad04-9ce627cdbcbd', + 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', + 'sizes': [[640, 480], [320, 200]], + 'bidId': '268c309f46390d', + 'bidderRequestId': '1dfdd514c36ef6', + 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', 'src': 'client', 'bidRequestsCount': 1 } ], - 'auctionStart': 1565711321749, + 'auctionStart': 1565794308584, 'timeout': 3000, 'refererInfo': { 'referer': 'http://localhost:8086/page', @@ -89,7 +94,7 @@ describe('videonowAdapterTests', function () { 'http://localhost:8086/page' ] }, - 'start': 1565711321755 + 'start': 1565794308589 }; const requests = spec.buildRequests(validBidRequests, bidderRequest); @@ -100,23 +105,23 @@ describe('videonowAdapterTests', function () { }); it('bidRequest method', function () { - expect(request.method).to.equal('GET'); + expect(request.method).to.equal('POST'); }); it('bidRequest url', function () { - expect(request.url).to.equal('http://localhost:8086/bid?pId=1'); + expect(request.url).to.equal('http://localhost:8086/bid?profile_id=1'); }); it('bidRequest data', function () { const data = request.data; - const w = validBidRequests[0].sizes[0][0] + '' - const h = validBidRequests[0].sizes[0][1] + '' + // const w = validBidRequests[0].sizes[0][0] + '' + // const h = validBidRequests[0].sizes[0][1] + '' - expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); + // expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); expect(data.aid).to.be.eql(validBidRequests[0].params.aid); - expect(data.bidId).to.be.eql(validBidRequests[0].bidId); - expect(data.width).to.be.eql(w); - expect(data.height).to.be.eql(h); + expect(data.id).to.be.eql(validBidRequests[0].bidId); + expect(data.sizes).to.be.eql(validBidRequests[0].sizes); + // expect(data.height).to.be.eql(h); }); }); @@ -131,23 +136,22 @@ describe('videonowAdapterTests', function () { 'bid': [ { 'id': 'e3bf2b82e3e9485113fad6c9b27f8768.1', - 'impid': '11111111', + 'impid': '1', 'price': 10.97, 'nurl': 'http://localhost:8086/event/nurl', - 'netRevenue': true, + 'netRevenue': false, 'ttl': 800, - 'adm': { - 'profileId': 1, - 'dataUrl': 'http://localhost:8086/init', - 'init': 'http://localhost:8086/vn_init.js' - }, - 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1' + 'adm': 'stub', + 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', + 'h': 640, + 'w': 480 } ], 'group': 0 } ], 'ext': { + 'placementId': 'div-gpt-ad-1438287399331-0', 'pixels': [ 'http://localhost:8086/event/pxlcookiematching?uiid=1', 'http://localhost:8086/event/pxlcookiematching?uiid=2' @@ -162,16 +166,15 @@ describe('videonowAdapterTests', function () { }; const bidRequest = { - 'method': 'GET', - 'url': 'http://localhost:8086/bid?pId=1', + 'method': 'POST', + 'url': 'http://localhost:8086/bid?profile_id=1', 'data': { - 'referer': 'http://localhost:8086/page', - 'cb': 1565715456073, + 'id': '217b8ab59a18e8', + 'cpm': 10, + 'sizes': [[640, 480], [320, 200]], + 'cur': 'RUB', 'placementId': 'div-gpt-ad-1438287399331-0', - 'bidId': '2467b82a7afaf1', - 'bidFloor': 10, - 'width': '640', - 'height': '480' + 'ref': 'http://localhost:8086/page' } }; @@ -185,20 +188,16 @@ describe('videonowAdapterTests', function () { expect(result.length).to.equal(1); }); - // it('d', function() { - // const res = result[0] - // const bid = serverResponse.body.seatbid[0].bid - // expect(res).to.be.eql(bid); - // }) - // it('Should have required keys', function () { const bid = serverResponse.body.seatbid[0].bid[0] const res = result[0] - expect(res.requestId).to.be.eql(bidRequest.data.bidId); + expect(res.requestId).to.be.eql(bidRequest.data.id); expect(res.cpm).to.be.eql(bid.price); expect(res.creativeId).to.be.eql(bid.crid); - expect(res.netRevenue).to.be.eql(true); + expect(res.netRevenue).to.be.a('boolean'); expect(res.ttl).to.be.eql(bid.ttl); + expect(res.renderer).to.be.a('Object'); + expect(res.renderer.render).to.be.a('function'); }) }); }); From 615c3f32fb330a8909d78635aaa2b9354ca9b4a0 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Wed, 21 Aug 2019 17:06:54 +0300 Subject: [PATCH 09/25] -- replace placeholder in the onBidWon pixel's url --- modules/videoNowBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 6169110e926..45c53ca136c 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -155,7 +155,7 @@ function onBidWon(bid) { const { nurl } = bid if (nurl) { const img = document.createElement('img') - img.src = nurl + img.src = utils.replaceAuctionPrice(nurl, bid.cpm) img.style.cssText = 'display:none !important;' document.body.appendChild(img) } From 4142f07deac597fea200a26a0c0cca5b1e3f3532 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Wed, 21 Aug 2019 18:29:01 +0300 Subject: [PATCH 10/25] -- commit for restart tests --- modules/videoNowBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 45c53ca136c..ce8390bb8d3 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -9,7 +9,7 @@ const TTL_SECONDS = 60 * 5; function isBidRequestValid(bid) { const { params } = bid || {} - return !!(params.pId); + return !!(params.pId) } function buildRequest(bid, bidderRequest) { From 36ce34a02c3fe5b11eb904cccaaf2d24f4fa0365 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 2 Sep 2019 19:09:41 +0300 Subject: [PATCH 11/25] -- change response data format for display ad --- modules/videoNowBidAdapter.js | 65 +++++++------------- test/spec/modules/videoNowBidAdapter_spec.js | 7 ++- 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index ce8390bb8d3..4c9595b204b 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -79,15 +79,15 @@ function interpretResponse(serverResponse, bidRequest) { } function createResponseBid(bidInfo, bidId, cur, placementId) { - const { id, nurl, code, price, crid, adm, ttl, netRevenue, w, h } = bidInfo + const { id, nurl, code, price, crid, ext, ttl, netRevenue, w, h } = bidInfo if (!id || !price) { return null; } - if (!adm) { - utils.logError(`${BIDDER_CODE}. adm not exists in the response`) - return null + const { vnInitModule, vnModule, dataXml, format } = ext || {} + if (!vnInitModule || !dataXml || !vnModule) { + utils.logError('vnInitModule or dataXml or vnModule is not defined') } try { @@ -108,11 +108,26 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { const d = window.document const el = placementId && d.getElementById(placementId) if (!el) { - console.error(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) + utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) + } + + // prepare data for vn_init script + const profileData = { + url: `${vnModule}`, + dataXml + } + + format && (profileData.format = format) + + // add init data for vn_init on the page + window.videonow = { + 'init': { '1': profileData } } - el.innerHTML = adm - reInitScripts(el) + // add vn_init js on the page + const scr = document.createElement('script') + scr.src = `${vnInitModule}?profileId=1` + el.appendChild(scr) } } } @@ -173,39 +188,3 @@ export const spec = { } registerBidder(spec); - -function reInitScripts(container, shouldReInitInlineScripts = true, delay = 10) { - const oldScripts = container.querySelectorAll('script') - const innerScriptsInsertActions = [] - - oldScripts && oldScripts.length && Array.from(oldScripts).forEach(oldScr => { - const { parentNode } = oldScr - const scriptElement = document.createElement('script') - oldScr.attributes && Array.from(oldScr.attributes).forEach(attr => { - scriptElement.setAttribute(attr.name, attr.value) - }) - - if (oldScr.src) { - innerScriptsInsertActions.push(() => { - ((function(parent, scriptElm, src) { - scriptElm.src = src - parent.appendChild(scriptElm) - })(parentNode, scriptElement, oldScr.src)) - }) - } - - if (oldScr.innerHTML && shouldReInitInlineScripts) { - innerScriptsInsertActions.push(() => { - ((function(parent, scriptElm, scriptText) { - scriptElm.innerHTML = scriptText - parent.appendChild(scriptElm) - })(parentNode, scriptElement, oldScr.innerHTML)) - }) - } - parentNode.removeChild(oldScr) - }) - - innerScriptsInsertActions.length && setTimeout(() => { - innerScriptsInsertActions.forEach(si => si()) - }, delay) -} diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index 910ff7c11e3..8292173876c 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -174,7 +174,12 @@ describe('videonowAdapterTests', function () { 'sizes': [[640, 480], [320, 200]], 'cur': 'RUB', 'placementId': 'div-gpt-ad-1438287399331-0', - 'ref': 'http://localhost:8086/page' + 'ref': 'http://localhost:8086/page', + 'ext': { + vnInitModule: 'http://localhost:8086/vn_init.js', + vnModule: 'http://localhost:8086/vn_module.js', + dataXml: '' + } } }; From 7310341e71b420599ff541de0993169e86393e0a Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Tue, 3 Sep 2019 20:31:21 +0300 Subject: [PATCH 12/25] -- tests updated --- modules/videoNowBidAdapter.js | 134 +++-- test/spec/modules/videoNowBidAdapter_spec.js | 495 +++++++++++++------ 2 files changed, 398 insertions(+), 231 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 4c9595b204b..9984da95e8a 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,11 +1,11 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils' +import { registerBidder } from '../src/adapters/bidderFactory' import { BANNER } from '../src/mediaTypes' const RTB_URL = 'https://bidder.videonow.ru/prebid' const BIDDER_CODE = 'videonow' -const TTL_SECONDS = 60 * 5; +const TTL_SECONDS = 60 * 5 function isBidRequestValid(bid) { const { params } = bid || {} @@ -14,7 +14,7 @@ function isBidRequestValid(bid) { function buildRequest(bid, bidderRequest) { const { refererInfo } = bidderRequest - const { ext, bidId, params, code, sizes } = bid; + const { ext, bidId, params, code, sizes } = bid const { pId, bidFloor, cur, placementId, url: rtbUrl } = params || {} let url = rtbUrl || RTB_URL @@ -35,30 +35,30 @@ function buildRequest(bid, bidderRequest) { } ext && Object.keys(ext).forEach(key => { - dto[`ext_${key}`] = ext.key + dto.data[`ext_${key}`] = ext[key] }) - return dto; + return dto } function buildRequests(validBidRequests, bidderRequest) { utils.logInfo(`${BIDDER_CODE}. buildRequests`) - const requests = []; + const requests = [] validBidRequests.forEach(validBidRequest => { - const request = buildRequest(validBidRequest, bidderRequest); - request && requests.push(request); - }); - return requests; + const request = buildRequest(validBidRequest, bidderRequest) + request && requests.push(request) + }) + return requests } function interpretResponse(serverResponse, bidRequest) { if (!serverResponse || !serverResponse.body) { - return []; + return [] } const { id: bidId } = (bidRequest && bidRequest.data) || {} if (!bidId) return [] - const { seatbid, cur, ext } = serverResponse.body; + const { seatbid, cur, ext } = serverResponse.body if (!seatbid || !seatbid.length) return [] const { placementId } = ext || {} @@ -67,12 +67,10 @@ function interpretResponse(serverResponse, bidRequest) { const bids = [] seatbid.forEach(sb => { const { bid } = sb - if (bid && bid.length) { - bid.forEach(b => { - const res = createResponseBid(b, bidId, cur, placementId) - res && bids.push(res) - }) - } + bid && bid.length && bid.forEach(b => { + const res = createResponseBid(b, bidId, cur, placementId) + res && bids.push(res) + }) }) return bids @@ -82,57 +80,54 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { const { id, nurl, code, price, crid, ext, ttl, netRevenue, w, h } = bidInfo if (!id || !price) { - return null; + return null } const { vnInitModule, vnModule, dataXml, format } = ext || {} if (!vnInitModule || !dataXml || !vnModule) { utils.logError('vnInitModule or dataXml or vnModule is not defined') + return null } - try { - return { - requestId: bidId, - cpm: price, - width: w, - height: h, - creativeId: crid, - currency: cur || 'RUB', - netRevenue: netRevenue !== undefined ? netRevenue : true, - ttl: ttl || TTL_SECONDS, - ad: code, - nurl, - renderer: { - url: nurl, - render: function() { - const d = window.document - const el = placementId && d.getElementById(placementId) - if (!el) { - utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) - } - - // prepare data for vn_init script - const profileData = { - url: `${vnModule}`, - dataXml - } - - format && (profileData.format = format) - - // add init data for vn_init on the page - window.videonow = { - 'init': { '1': profileData } - } - - // add vn_init js on the page - const scr = document.createElement('script') - scr.src = `${vnInitModule}?profileId=1` - el.appendChild(scr) + return { + requestId: bidId, + cpm: price, + width: w, + height: h, + creativeId: crid, + currency: cur || 'RUB', + netRevenue: netRevenue !== undefined ? netRevenue : true, + ttl: ttl || TTL_SECONDS, + ad: code, + nurl, + renderer: { + url: nurl, + render: function() { + const d = window.document + const el = placementId && d.getElementById(placementId) + if (!el) { + utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) + } + + // prepare data for vn_init script + const profileData = { + url: `${vnModule}`, + dataXml } + + format && (profileData.format = format) + + // add init data for vn_init on the page + window.videonow = { + 'init': { '1': profileData } + } + + // add vn_init js on the page + const scr = document.createElement('script') + scr.src = `${vnInitModule}?profileId=1` + el.appendChild(scr) } } - } catch (e) { - return null } } @@ -142,22 +137,22 @@ function getUserSyncs(syncOptions, serverResponses) { if (!serverResponses || !serverResponses.length) return syncs serverResponses.forEach(response => { - const {ext} = (response && response.body) || {} - const {pixels, iframes} = ext || {} + const { ext } = (response && response.body) || {} + const { pixels, iframes } = ext || {} if (syncOptions.iframeEnabled && iframes && iframes.length) { iframes.forEach(i => syncs.push({ - type: 'iframe', - url: i - }) + type: 'iframe', + url: i + }) ) } if (syncOptions.pixelEnabled && pixels && pixels.length) { pixels.forEach(p => syncs.push({ - type: 'image', - url: p - }) + type: 'image', + url: p + }) ) } }) @@ -183,8 +178,7 @@ export const spec = { buildRequests, interpretResponse, getUserSyncs, - onTimeout: function(timeoutData) {}, onBidWon } -registerBidder(spec); +registerBidder(spec) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index 8292173876c..d6ece8ce489 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -1,68 +1,42 @@ -import { expect } from 'chai'; -import { spec } from 'modules/videoNowBidAdapter'; +import { expect } from 'chai' +import { spec } from 'modules/videoNowBidAdapter' -describe('videonowAdapterTests', function () { - describe('bidRequestValidity', function () { - it('bidRequest with pId', function () { +describe('videonowAdapterTests', function() { + describe('bidRequestValidity', function() { + it('bidRequest with pId', function() { expect(spec.isBidRequestValid({ bidder: 'videonow', params: { pId: '86858', } - })).to.equal(true); - }); + })).to.equal(true) + }) - it('bidRequest without pId', function () { + it('bidRequest without pId', function() { expect(spec.isBidRequestValid({ bidder: 'videonow', params: { nomater: 86858 } - })).to.equal(false); - }); - }); - - describe('bidRequest', function () { - const validBidRequests = [ - { - 'bidder': 'videonow', - 'params': { - 'pId': '1', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'url': 'http://localhost:8086/bid', - 'bidFloor': 10, - 'cur': 'RUB' - }, - 'crumbs': { - 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 480], [320, 200]] - } - }, - 'adUnitCode': 'test-ad', - 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', - 'sizes': [[640, 480], [320, 200]], - 'bidId': '268c309f46390d', - 'bidderRequestId': '1dfdd514c36ef6', - 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', - 'src': 'client', - 'bidRequestsCount': 1 - } - ]; + })).to.equal(false) - const bidderRequest = { - 'bidderCode': 'videonow', - 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', - 'bidderRequestId': '1dfdd514c36ef6', - 'bids': [ + it('bidRequest is empty', function() { + expect(spec.isBidRequestValid({})).to.equal(false) + }) + + it('bidRequest is undefned', function() { + expect(spec.isBidRequestValid(undefined)).to.equal(false) + }) + }) + + describe('bidRequest', function() { + const validBidRequests = [ { 'bidder': 'videonow', 'params': { 'pId': '1', 'placementId': 'div-gpt-ad-1438287399331-0', - 'url': 'http://localhost:8086/bid', + 'url': 'http://localhost:8086/bid?p=exists', 'bidFloor': 10, 'cur': 'RUB' }, @@ -83,126 +57,325 @@ describe('videonowAdapterTests', function () { 'src': 'client', 'bidRequestsCount': 1 } - ], - 'auctionStart': 1565794308584, - 'timeout': 3000, - 'refererInfo': { - 'referer': 'http://localhost:8086/page', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://localhost:8086/page' - ] - }, - 'start': 1565794308589 - }; - - const requests = spec.buildRequests(validBidRequests, bidderRequest); - const request = (requests && requests.length && requests[0]) || {} - - it('bidRequest count', function () { - expect(requests.length).to.equal(1); - }); - - it('bidRequest method', function () { - expect(request.method).to.equal('POST'); - }); - - it('bidRequest url', function () { - expect(request.url).to.equal('http://localhost:8086/bid?profile_id=1'); - }); - - it('bidRequest data', function () { - const data = request.data; - // const w = validBidRequests[0].sizes[0][0] + '' - // const h = validBidRequests[0].sizes[0][1] + '' - - // expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); - expect(data.aid).to.be.eql(validBidRequests[0].params.aid); - expect(data.id).to.be.eql(validBidRequests[0].bidId); - expect(data.sizes).to.be.eql(validBidRequests[0].sizes); - // expect(data.height).to.be.eql(h); - }); - }); - - describe('interpretResponse', function () { - const serverResponse = { - 'body': { - 'id': '111-111', - 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', - 'cur': 'RUB', - 'seatbid': [ + ] + + const bidderRequest = { + 'bidderCode': 'videonow', + 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', + 'bidderRequestId': '1dfdd514c36ef6', + 'bids': [ { - 'bid': [ - { - 'id': 'e3bf2b82e3e9485113fad6c9b27f8768.1', - 'impid': '1', - 'price': 10.97, - 'nurl': 'http://localhost:8086/event/nurl', - 'netRevenue': false, - 'ttl': 800, - 'adm': 'stub', - 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', - 'h': 640, - 'w': 480 + 'bidder': 'videonow', + 'params': { + 'pId': '1', + 'placementId': 'div-gpt-ad-1438287399331-0', + 'url': 'http://localhost:8086/bid', + 'bidFloor': 10, + 'cur': 'RUB' + }, + 'crumbs': { + 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480], [320, 200]] } - ], - 'group': 0 + }, + 'adUnitCode': 'test-ad', + 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', + 'sizes': [[640, 480], [320, 200]], + 'bidId': '268c309f46390d', + 'bidderRequestId': '1dfdd514c36ef6', + 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', + 'src': 'client', + 'bidRequestsCount': 1 } ], - 'ext': { - 'placementId': 'div-gpt-ad-1438287399331-0', - 'pixels': [ - 'http://localhost:8086/event/pxlcookiematching?uiid=1', - 'http://localhost:8086/event/pxlcookiematching?uiid=2' - ], - 'iframes': [ - 'http://localhost:8086/event/ifrcookiematching?uiid=1', - 'http://localhost:8086/event/ifrcookiematching?uiid=2' + 'auctionStart': 1565794308584, + 'timeout': 3000, + 'refererInfo': { + 'referer': 'http://localhost:8086/page', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'http://localhost:8086/page' ] + }, + 'start': 1565794308589 + } + + const requests = spec.buildRequests(validBidRequests, bidderRequest) + const request = (requests && requests.length && requests[0]) || {} + + it('bidRequest count', function() { + expect(requests.length).to.equal(1) + }) + + it('bidRequest method', function() { + expect(request.method).to.equal('POST') + }) + + it('bidRequest url', function() { + expect(request.url).to.equal('http://localhost:8086/bid?p=exists&profile_id=1') + }) + + it('bidRequest data', function() { + const data = request.data + // const w = validBidRequests[0].sizes[0][0] + '' + // const h = validBidRequests[0].sizes[0][1] + '' + + // expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); + expect(data.aid).to.be.eql(validBidRequests[0].params.aid) + expect(data.id).to.be.eql(validBidRequests[0].bidId) + expect(data.sizes).to.be.eql(validBidRequests[0].sizes) + // expect(data.height).to.be.eql(h); + }) + + describe('bidRequest advanced', function() { + const bidderRequestEmptyParamsAndExtParams = { + 'bidder': 'videonow', + 'params': { + 'pId': '1', + }, + 'ext': { + 'p1': 'ext1', + 'p2': 'ext2', + } } - }, - 'headers': {} - }; - - const bidRequest = { - 'method': 'POST', - 'url': 'http://localhost:8086/bid?profile_id=1', - 'data': { - 'id': '217b8ab59a18e8', - 'cpm': 10, - 'sizes': [[640, 480], [320, 200]], - 'cur': 'RUB', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'ref': 'http://localhost:8086/page', - 'ext': { - vnInitModule: 'http://localhost:8086/vn_init.js', - vnModule: 'http://localhost:8086/vn_module.js', - dataXml: '' + + it('bidRequest count', function() { + const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) + expect(requests.length).to.equal(1) + }) + + it('bidRequest default url', function() { + const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) + const request = (requests && requests.length && requests[0]) || {} + expect(request.url).to.equal('https://bidder.videonow.ru/prebid?profile_id=1') + }) + + it('bidRequest default currency', function() { + const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) + const request = (requests && requests.length && requests[0]) || {} + const data = request && request.data || {} + expect(data.cur).to.equal('RUB') + }) + + it('bidRequest ext parameters ', function() { + const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) + const request = (requests && requests.length && requests[0]) || {} + const data = request && request.data || {} + expect(data['ext_p1']).to.equal('ext1') + expect(data['ext_p2']).to.equal('ext2') + }) + + it('bidRequest without params', function() { + const bidderReq = { + 'bidder': 'videonow' + } + const requests = spec.buildRequests([bidderReq], bidderRequest) + expect(requests.length).to.equal(1) + }) + + }) + }) + + describe('interpretResponse', function() { + const getValidServerResponse = () => { + const serverResponse = { + 'body': { + 'id': '111-111', + 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', + 'cur': 'RUB', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'e3bf2b82e3e9485113fad6c9b27f8768.1', + 'impid': '1', + 'price': 10.97, + 'nurl': 'http://localhost:8086/event/nurl', + 'netRevenue': false, + 'ttl': 800, + 'adm': 'stub', + 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', + 'h': 640, + 'w': 480, + 'ext': { + vnInitModule: 'http://localhost:8086/vn_init.js', + vnModule: 'http://localhost:8086/vn_module.js', + dataXml: '' + } + + } + ], + 'group': 0 + } + ], + 'price': 10, + 'ext': { + 'placementId': 'div-gpt-ad-1438287399331-0', + 'pixels': [ + 'http://localhost:8086/event/pxlcookiematching?uiid=1', + 'http://localhost:8086/event/pxlcookiematching?uiid=2' + ], + 'iframes': [ + 'http://localhost:8086/event/ifrcookiematching?uiid=1', + 'http://localhost:8086/event/ifrcookiematching?uiid=2' + ] + } + }, + 'headers': {} + } + + return JSON.parse(JSON.stringify(serverResponse)) + } + + const bidRequest = { + 'method': 'POST', + 'url': 'http://localhost:8086/bid?profile_id=1', + 'data': { + 'id': '217b8ab59a18e8', + 'cpm': 10, + 'sizes': [[640, 480], [320, 200]], + 'cur': 'RUB', + 'placementId': 'div-gpt-ad-1438287399331-0', + 'ref': 'http://localhost:8086/page' } } - }; - - const result = spec.interpretResponse(serverResponse, bidRequest); - - it('Should return an empty array if empty or no bids in response', function () { - expect(spec.interpretResponse({body: ''}, {}).length).to.equal(0); - }); - - it('Should have only one bid', function () { - expect(result.length).to.equal(1); - }); - - it('Should have required keys', function () { - const bid = serverResponse.body.seatbid[0].bid[0] - const res = result[0] - expect(res.requestId).to.be.eql(bidRequest.data.id); - expect(res.cpm).to.be.eql(bid.price); - expect(res.creativeId).to.be.eql(bid.crid); - expect(res.netRevenue).to.be.a('boolean'); - expect(res.ttl).to.be.eql(bid.ttl); - expect(res.renderer).to.be.a('Object'); - expect(res.renderer.render).to.be.a('function'); + + + it('Should have only one bid', function() { + const serverResponse = getValidServerResponse() + const result = spec.interpretResponse(serverResponse, bidRequest) + expect(result.length).to.equal(1) + }) + + it('Should have required keys', function() { + const serverResponse = getValidServerResponse() + const result = spec.interpretResponse(serverResponse, bidRequest) + const bid = serverResponse.body.seatbid[0].bid[0] + const res = result[0] + expect(res.requestId).to.be.eql(bidRequest.data.id) + expect(res.cpm).to.be.eql(bid.price) + expect(res.creativeId).to.be.eql(bid.crid) + expect(res.netRevenue).to.be.a('boolean') + expect(res.ttl).to.be.eql(bid.ttl) + expect(res.renderer).to.be.a('Object') + expect(res.renderer.render).to.be.a('function') + }) + + it('Should return an empty array if empty or no bids in response', function() { + expect(spec.interpretResponse({ body: '' }, {}).length).to.equal(0) + }) + + it('Should return an empty array if bidRequest\'s data is absent', function() { + const serverResponse = getValidServerResponse() + expect(spec.interpretResponse(serverResponse, undefined).length).to.equal(0) + }) + + it('Should return an empty array if bidRequest\'s data is not contains bidId ', function() { + const serverResponse = getValidServerResponse() + expect(spec.interpretResponse(serverResponse, { data: {} }).length).to.equal(0) + }) + + it('Should return an empty array if bidRequest\'s data bidId is undefined', function() { + const serverResponse = getValidServerResponse() + expect(spec.interpretResponse(serverResponse, { data: { id: null } }).length).to.equal(0) + }) + + it('Should return an empty array if serverResponse do not contains seatbid', function() { + expect(spec.interpretResponse({ body: {} }, bidRequest).length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s seatbid is empty', function() { + expect(spec.interpretResponse({ body: { seatbid: [] } }, bidRequest).length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s placementId is undefined', function() { + expect(spec.interpretResponse({ body: { seatbid: [1,2] } }, bidRequest).length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s id in the bid is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].id + let res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(0) + }) + + + it('Should return an empty array if serverResponse\'s price in the bid is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].price + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s price in the bid is 0', function() { + const serverResp = getValidServerResponse() + serverResp.body.seatbid[0].bid[0].price = 0 + const res = spec.interpretResponse(serverResp, bidRequest) + + expect(res.length).to.equal(0) + }) + + + it('Should return an empty array if serverResponse\'s vnInitModule in the bid\'s ext is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].ext.vnInitModule + const res = spec.interpretResponse(serverResp, bidRequest) + + expect(res.length).to.equal(0) + }) + + + it('Should return an empty array if serverResponse\'s vnModule in the bid\'s ext is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].ext.vnModule + const res = spec.interpretResponse(serverResp, bidRequest) + + expect(res.length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s dataXml in the bid\'s ext is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].ext.dataXml + const res = spec.interpretResponse(serverResp, bidRequest) + + expect(res.length).to.equal(0) + }) + + it('Should return an empty array if serverResponse\'s the bid\'s ext is undefined', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].ext + const res = spec.interpretResponse(serverResp, bidRequest) + + expect(res.length).to.equal(0) + }) + + it('Default ttl is 300', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].ttl + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + expect(res[0].ttl).to.equal(300) + }) + + it('Default netRevenue is true', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.seatbid[0].bid[0].netRevenue + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + expect(res[0].netRevenue).to.equal(true) + }) + + it('Default currency is RUB', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.cur + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + expect(res[0].currency).to.equal('RUB') + }) }) - }); -}); + }) +}) From 4c659f6f63eb4c04943f9a49ccb5186c6dfae00e Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Wed, 4 Sep 2019 15:22:03 +0300 Subject: [PATCH 13/25] -- 100% tests coverage --- modules/videoNowBidAdapter.js | 55 ++- test/spec/modules/videoNowBidAdapter_spec.js | 377 ++++++++++++------- 2 files changed, 274 insertions(+), 158 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 9984da95e8a..69785864187 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -8,8 +8,7 @@ const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5 function isBidRequestValid(bid) { - const { params } = bid || {} - return !!(params.pId) + return !!(bid && bid.params && bid.params.pId) } function buildRequest(bid, bidderRequest) { @@ -30,8 +29,8 @@ function buildRequest(bid, bidderRequest) { sizes, cur: cur || 'RUB', placementId, - ref: refererInfo && refererInfo.referer - } + ref: refererInfo && refererInfo.referer, + }, } ext && Object.keys(ext).forEach(key => { @@ -105,27 +104,27 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { render: function() { const d = window.document const el = placementId && d.getElementById(placementId) - if (!el) { + if (el) { + // prepare data for vn_init script + const profileData = { + url: `${vnModule}`, + dataXml, + } + + format && (profileData.format = format); + + // add init data for vn_init on the page + window.videonow = { + 'init': { '1': profileData }, + } + + // add vn_init js on the page + const scr = document.createElement('script') + scr.src = `${vnInitModule}?profileId=1` + el && el.appendChild(scr) + } else { utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) } - - // prepare data for vn_init script - const profileData = { - url: `${vnModule}`, - dataXml - } - - format && (profileData.format = format) - - // add init data for vn_init on the page - window.videonow = { - 'init': { '1': profileData } - } - - // add vn_init js on the page - const scr = document.createElement('script') - scr.src = `${vnInitModule}?profileId=1` - el.appendChild(scr) } } } @@ -143,16 +142,16 @@ function getUserSyncs(syncOptions, serverResponses) { if (syncOptions.iframeEnabled && iframes && iframes.length) { iframes.forEach(i => syncs.push({ type: 'iframe', - url: i - }) + url: i, + }), ) } if (syncOptions.pixelEnabled && pixels && pixels.length) { pixels.forEach(p => syncs.push({ type: 'image', - url: p - }) + url: p, + }), ) } }) @@ -162,7 +161,7 @@ function getUserSyncs(syncOptions, serverResponses) { } function onBidWon(bid) { - const { nurl } = bid + const { nurl } = bid || {} if (nurl) { const img = document.createElement('img') img.src = utils.replaceAuctionPrice(nurl, bid.cpm) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index d6ece8ce489..ce61c2b4715 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -1,5 +1,61 @@ import { expect } from 'chai' import { spec } from 'modules/videoNowBidAdapter' +import { replaceAuctionPrice } from '../../../src/utils' + +const placementId = 'div-gpt-ad-1438287399331-0' + +const getValidServerResponse = () => { + const serverResponse = { + body: { + id: '111-111', + bidid: '2955a162-699e-4811-ce88-5c3ac973e73c', + cur: 'RUB', + seatbid: [ + { + bid: [ + { + id: 'e3bf2b82e3e9485113fad6c9b27f8768.1', + impid: '1', + price: 10.97, + nurl: 'http://localhost:8086/event/nurl', + netRevenue: false, + ttl: 800, + adm: 'stub', + crid: 'e3bf2b82e3e9485113fad6c9b27f8768.1', + h: 640, + w: 480, + ext: { + vnInitModule: 'http://localhost:8086/vn_init.js', + vnModule: 'http://localhost:8086/vn_module.js', + dataXml: '', + format: { + name: 'flyRoll', + }, + }, + + }, + ], + group: 0, + }, + ], + price: 10, + ext: { + placementId, + pixels: [ + 'http://localhost:8086/event/pxlcookiematching?uiid=1', + 'http://localhost:8086/event/pxlcookiematching?uiid=2', + ], + iframes: [ + 'http://localhost:8086/event/ifrcookiematching?uiid=1', + 'http://localhost:8086/event/ifrcookiematching?uiid=2', + ], + }, + }, + headers: {}, + } + + return JSON.parse(JSON.stringify(serverResponse)) +} describe('videonowAdapterTests', function() { describe('bidRequestValidity', function() { @@ -8,7 +64,7 @@ describe('videonowAdapterTests', function() { bidder: 'videonow', params: { pId: '86858', - } + }, })).to.equal(true) }) @@ -16,8 +72,8 @@ describe('videonowAdapterTests', function() { expect(spec.isBidRequestValid({ bidder: 'videonow', params: { - nomater: 86858 - } + nomater: 86858, + }, })).to.equal(false) it('bidRequest is empty', function() { @@ -32,76 +88,76 @@ describe('videonowAdapterTests', function() { describe('bidRequest', function() { const validBidRequests = [ { - 'bidder': 'videonow', - 'params': { - 'pId': '1', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'url': 'http://localhost:8086/bid?p=exists', - 'bidFloor': 10, - 'cur': 'RUB' + bidder: 'videonow', + params: { + pId: '1', + placementId, + url: 'http://localhost:8086/bid?p=exists', + bidFloor: 10, + cur: 'RUB' }, - 'crumbs': { - 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' + crumbs: { + pubcid: 'feded041-35dd-4b54-979a-6d7805abfa75', }, - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 480], [320, 200]] - } + mediaTypes: { + banner: { + sizes: [[640, 480], [320, 200]] + }, }, - 'adUnitCode': 'test-ad', - 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', - 'sizes': [[640, 480], [320, 200]], - 'bidId': '268c309f46390d', - 'bidderRequestId': '1dfdd514c36ef6', - 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', - 'src': 'client', - 'bidRequestsCount': 1 - } + adUnitCode: 'test-ad', + transactionId: '676403c7-09c9-4b56-be82-e7cae81f40b9', + sizes: [[640, 480], [320, 200]], + bidId: '268c309f46390d', + bidderRequestId: '1dfdd514c36ef6', + auctionId: '4d523546-889a-4029-9a79-13d3c69f9922', + src: 'client', + bidRequestsCount: 1, + }, ] const bidderRequest = { - 'bidderCode': 'videonow', - 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', - 'bidderRequestId': '1dfdd514c36ef6', - 'bids': [ + bidderCode: 'videonow', + auctionId: '4d523546-889a-4029-9a79-13d3c69f9922', + bidderRequestId: '1dfdd514c36ef6', + bids: [ { - 'bidder': 'videonow', - 'params': { - 'pId': '1', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'url': 'http://localhost:8086/bid', - 'bidFloor': 10, - 'cur': 'RUB' + bidder: 'videonow', + params: { + pId: '1', + placementId, + url: 'http://localhost:8086/bid', + bidFloor: 10, + cur: 'RUB', }, - 'crumbs': { - 'pubcid': 'feded041-35dd-4b54-979a-6d7805abfa75' + crumbs: { + pubcid: 'feded041-35dd-4b54-979a-6d7805abfa75', }, - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 480], [320, 200]] - } + mediaTypes: { + banner: { + sizes: [[640, 480], [320, 200]], + }, }, - 'adUnitCode': 'test-ad', - 'transactionId': '676403c7-09c9-4b56-be82-e7cae81f40b9', - 'sizes': [[640, 480], [320, 200]], - 'bidId': '268c309f46390d', - 'bidderRequestId': '1dfdd514c36ef6', - 'auctionId': '4d523546-889a-4029-9a79-13d3c69f9922', - 'src': 'client', - 'bidRequestsCount': 1 - } + adUnitCode: 'test-ad', + transactionId: '676403c7-09c9-4b56-be82-e7cae81f40b9', + sizes: [[640, 480], [320, 200]], + bidId: '268c309f46390d', + bidderRequestId: '1dfdd514c36ef6', + auctionId: '4d523546-889a-4029-9a79-13d3c69f9922', + src: 'client', + bidRequestsCount: 1, + }, ], - 'auctionStart': 1565794308584, - 'timeout': 3000, - 'refererInfo': { - 'referer': 'http://localhost:8086/page', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://localhost:8086/page' - ] + auctionStart: 1565794308584, + timeout: 3000, + refererInfo: { + referer: 'http://localhost:8086/page', + reachedTop: true, + numIframes: 0, + stack: [ + 'http://localhost:8086/page', + ], }, - 'start': 1565794308589 + start: 1565794308589, } const requests = spec.buildRequests(validBidRequests, bidderRequest) @@ -133,14 +189,14 @@ describe('videonowAdapterTests', function() { describe('bidRequest advanced', function() { const bidderRequestEmptyParamsAndExtParams = { - 'bidder': 'videonow', - 'params': { - 'pId': '1', + bidder: 'videonow', + params: { + pId: '1', + }, + ext: { + p1: 'ext1', + p2: 'ext2', }, - 'ext': { - 'p1': 'ext1', - 'p2': 'ext2', - } } it('bidRequest count', function() { @@ -171,7 +227,7 @@ describe('videonowAdapterTests', function() { it('bidRequest without params', function() { const bidderReq = { - 'bidder': 'videonow' + bidder: 'videonow', } const requests = spec.buildRequests([bidderReq], bidderRequest) expect(requests.length).to.equal(1) @@ -180,68 +236,92 @@ describe('videonowAdapterTests', function() { }) }) - describe('interpretResponse', function() { - const getValidServerResponse = () => { - const serverResponse = { - 'body': { - 'id': '111-111', - 'bidid': '2955a162-699e-4811-ce88-5c3ac973e73c', - 'cur': 'RUB', - 'seatbid': [ - { - 'bid': [ - { - 'id': 'e3bf2b82e3e9485113fad6c9b27f8768.1', - 'impid': '1', - 'price': 10.97, - 'nurl': 'http://localhost:8086/event/nurl', - 'netRevenue': false, - 'ttl': 800, - 'adm': 'stub', - 'crid': 'e3bf2b82e3e9485113fad6c9b27f8768.1', - 'h': 640, - 'w': 480, - 'ext': { - vnInitModule: 'http://localhost:8086/vn_init.js', - vnModule: 'http://localhost:8086/vn_module.js', - dataXml: '' - } - - } - ], - 'group': 0 - } - ], - 'price': 10, - 'ext': { - 'placementId': 'div-gpt-ad-1438287399331-0', - 'pixels': [ - 'http://localhost:8086/event/pxlcookiematching?uiid=1', - 'http://localhost:8086/event/pxlcookiematching?uiid=2' - ], - 'iframes': [ - 'http://localhost:8086/event/ifrcookiematching?uiid=1', - 'http://localhost:8086/event/ifrcookiematching?uiid=2' - ] - } - }, - 'headers': {} - } + describe('onBidWon', function() { + const cpm = 10 + const nurl = 'http://fakedomain.nld?price=${AUCTION_PRICE}' + const imgSrc = replaceAuctionPrice(nurl, cpm) + const foundPixels = () => window.document.body.querySelectorAll(`img[src="${imgSrc}"]`) - return JSON.parse(JSON.stringify(serverResponse)) - } + + it('Should not create nurl pixel if bid is undefined', function(){ + spec.onBidWon() + expect(foundPixels().length).to.equal(0) + }) + + it('Should not create nurl pixel if bid does not contains nurl', function(){ + spec.onBidWon({}) + expect(foundPixels().length).to.equal(0) + }) + + it('Should create nurl pixel if bid nurl', function(){ + spec.onBidWon({ nurl, cpm }) + expect(foundPixels().length).to.equal(1) + }) + + }) + + describe('getUserSyncs', function() { + + it('Should return an empty array if not get serverResponses', function() { + expect(spec.getUserSyncs({}).length).to.equal(0) + }) + + it('Should return an empty array if get serverResponses as empty array', function() { + expect(spec.getUserSyncs({}, []).length).to.equal(0) + }) + + it('Should return an empty array if serverResponses has no body', function() { + const serverResp = getValidServerResponse() + delete serverResp.body + const syncs = spec.getUserSyncs({}, [serverResp]) + expect(syncs.length).to.equal(0) + }) + + it('Should return an empty array if serverResponses has no ext', function() { + const serverResp = getValidServerResponse() + delete serverResp.body.ext + const syncs = spec.getUserSyncs({}, [serverResp]) + expect(syncs.length).to.equal(0) + }) + + it('Should return an array', function() { + const serverResp = getValidServerResponse() + const syncs = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [serverResp]) + expect(syncs.length).to.equal(4) + }) + + it('Should return pixels', function() { + const serverResp = getValidServerResponse() + const syncs = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [serverResp]) + expect(syncs.length).to.equal(2) + expect(syncs[0].type).to.equal('image') + expect(syncs[1].type).to.equal('image') + }) + + it('Should return iframes', function() { + const serverResp = getValidServerResponse() + const syncs = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [serverResp]) + expect(syncs.length).to.equal(2) + expect(syncs[0].type).to.equal('iframe') + expect(syncs[1].type).to.equal('iframe') + }) + + }) + + + describe('interpretResponse', function() { const bidRequest = { - 'method': 'POST', - 'url': 'http://localhost:8086/bid?profile_id=1', - 'data': { - 'id': '217b8ab59a18e8', - 'cpm': 10, - 'sizes': [[640, 480], [320, 200]], - 'cur': 'RUB', - 'placementId': 'div-gpt-ad-1438287399331-0', - 'ref': 'http://localhost:8086/page' - } + method: 'POST', + url: 'http://localhost:8086/bid?profile_id=1', + data: { + id: '217b8ab59a18e8', + cpm: 10, + sizes: [[640, 480], [320, 200]], + cur: 'RUB', + placementId, + ref: 'http://localhost:8086/page', + }, } @@ -293,7 +373,7 @@ describe('videonowAdapterTests', function() { }) it('Should return an empty array if serverResponse\'s placementId is undefined', function() { - expect(spec.interpretResponse({ body: { seatbid: [1,2] } }, bidRequest).length).to.equal(0) + expect(spec.interpretResponse({ body: { seatbid: [1, 2] } }, bidRequest).length).to.equal(0) }) it('Should return an empty array if serverResponse\'s id in the bid is undefined', function() { @@ -366,7 +446,7 @@ describe('videonowAdapterTests', function() { delete serverResp.body.seatbid[0].bid[0].netRevenue const res = spec.interpretResponse(serverResp, bidRequest) expect(res.length).to.equal(1) - expect(res[0].netRevenue).to.equal(true) + expect(res[0].netRevenue).to.be.true; }) it('Default currency is RUB', function() { @@ -376,6 +456,43 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(1) expect(res[0].currency).to.equal('RUB') }) + + describe('renderer object', function() { + + it('execute renderer.render() should create window.videonow object', function() { + const serverResp = getValidServerResponse() + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + + const renderer = res[0].renderer + expect(renderer).to.be.an('object') + expect(renderer.render).to.a('function') + + const doc = window.document + const placementElement = doc.createElement('div') + placementElement.setAttribute('id', placementId) + doc.body.appendChild(placementElement) + + renderer.render() + expect(window.videonow).to.an('object') + }) + }) + + it('execute renderer.render() should not create window.videonow object if placement element not found', function() { + const serverResp = getValidServerResponse() + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + + const renderer = res[0].renderer + expect(renderer).to.be.an('object') + expect(renderer.render).to.a('function') + + renderer.render() + expect(window.videonow).to.be.undefined + }) + }) + }) + }) From a786ef50354feb11531502f8ce19472c15828355 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Wed, 4 Sep 2019 15:24:34 +0300 Subject: [PATCH 14/25] -- a few clean the test's code --- test/spec/modules/videoNowBidAdapter_spec.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index ce61c2b4715..0c80e03c545 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -177,14 +177,9 @@ describe('videonowAdapterTests', function() { it('bidRequest data', function() { const data = request.data - // const w = validBidRequests[0].sizes[0][0] + '' - // const h = validBidRequests[0].sizes[0][1] + '' - - // expect(decodeURIComponent(data.referer)).to.be.eql(bidderRequest.refererInfo.referer); expect(data.aid).to.be.eql(validBidRequests[0].params.aid) expect(data.id).to.be.eql(validBidRequests[0].bidId) expect(data.sizes).to.be.eql(validBidRequests[0].sizes) - // expect(data.height).to.be.eql(h); }) describe('bidRequest advanced', function() { From 11f54ac84fa4926c6f08bad0d40268402a725392 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 5 Sep 2019 18:22:41 +0300 Subject: [PATCH 15/25] -- custom urls from localStorage --- modules/videoNowBidAdapter.js | 44 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 69785864187..4c6c7c8b55f 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -6,6 +6,7 @@ const RTB_URL = 'https://bidder.videonow.ru/prebid' const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5 +const LS_ITEM_NAME = 'VN_DATA' function isBidRequestValid(bid) { return !!(bid && bid.params && bid.params.pId) @@ -76,15 +77,26 @@ function interpretResponse(serverResponse, bidRequest) { } function createResponseBid(bidInfo, bidId, cur, placementId) { - const { id, nurl, code, price, crid, ext, ttl, netRevenue, w, h } = bidInfo + const { id, nurl, code, price, crid, ext, ttl, netRevenue, w, h, adm } = bidInfo - if (!id || !price) { + if (!id || !price || !adm) { return null } - const { vnInitModule, vnModule, dataXml, format } = ext || {} - if (!vnInitModule || !dataXml || !vnModule) { - utils.logError('vnInitModule or dataXml or vnModule is not defined') + const { vnInitModule, vnModule, format } = ext || {} + + const vnData = JSON.parse(localStorage.getItem(LS_ITEM_NAME) || '{}') + let { vnModule: vnModuleCustom, vnInitModule: vnInitModuleCustom } = vnData + + const vnInitModulePath = vnInitModuleCustom || vnInitModule + if (!vnInitModulePath) { + utils.logError(`vnInitModulePath is not defined`) + return null + } + + const vntModulePath = vnModuleCustom || vnModule + if (!vntModulePath) { + utils.logError(`vntModulePath is not defined`) return null } @@ -100,18 +112,18 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { ad: code, nurl, renderer: { - url: nurl, + url: vntModulePath, render: function() { const d = window.document const el = placementId && d.getElementById(placementId) if (el) { // prepare data for vn_init script const profileData = { - url: `${vnModule}`, - dataXml, + url: vntModulePath, + dataXml: adm, } - format && (profileData.format = format); + format && (profileData.format = format) // add init data for vn_init on the page window.videonow = { @@ -120,7 +132,7 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { // add vn_init js on the page const scr = document.createElement('script') - scr.src = `${vnInitModule}?profileId=1` + scr.src = `${vnInitModulePath}${~vnInitModulePath.indexOf('?') ? '&' : '?'}profileId=1` el && el.appendChild(scr) } else { utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) @@ -141,17 +153,17 @@ function getUserSyncs(syncOptions, serverResponses) { if (syncOptions.iframeEnabled && iframes && iframes.length) { iframes.forEach(i => syncs.push({ - type: 'iframe', - url: i, - }), + type: 'iframe', + url: i, + }), ) } if (syncOptions.pixelEnabled && pixels && pixels.length) { pixels.forEach(p => syncs.push({ - type: 'image', - url: p, - }), + type: 'image', + url: p, + }), ) } }) From 77691e565ffc5234244ffb183be8defd4c1eddc5 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 5 Sep 2019 18:22:55 +0300 Subject: [PATCH 16/25] -- tests updated --- test/spec/modules/videoNowBidAdapter_spec.js | 111 +++++++++++++++---- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index 0c80e03c545..09632ee13c0 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -3,6 +3,7 @@ import { spec } from 'modules/videoNowBidAdapter' import { replaceAuctionPrice } from '../../../src/utils' const placementId = 'div-gpt-ad-1438287399331-0' +const LS_ITEM_NAME = 'VN_DATA' const getValidServerResponse = () => { const serverResponse = { @@ -20,14 +21,13 @@ const getValidServerResponse = () => { nurl: 'http://localhost:8086/event/nurl', netRevenue: false, ttl: 800, - adm: 'stub', + adm: '', crid: 'e3bf2b82e3e9485113fad6c9b27f8768.1', h: 640, w: 480, ext: { vnInitModule: 'http://localhost:8086/vn_init.js', vnModule: 'http://localhost:8086/vn_module.js', - dataXml: '', format: { name: 'flyRoll', }, @@ -208,14 +208,14 @@ describe('videonowAdapterTests', function() { it('bidRequest default currency', function() { const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) const request = (requests && requests.length && requests[0]) || {} - const data = request && request.data || {} + const data = (request && request.data) || {} expect(data.cur).to.equal('RUB') }) it('bidRequest ext parameters ', function() { const requests = spec.buildRequests([bidderRequestEmptyParamsAndExtParams], bidderRequest) const request = (requests && requests.length && requests[0]) || {} - const data = request && request.data || {} + const data = (request && request.data) || {} expect(data['ext_p1']).to.equal('ext1') expect(data['ext_p2']).to.equal('ext2') }) @@ -227,7 +227,6 @@ describe('videonowAdapterTests', function() { const requests = spec.buildRequests([bidderReq], bidderRequest) expect(requests.length).to.equal(1) }) - }) }) @@ -237,26 +236,23 @@ describe('videonowAdapterTests', function() { const imgSrc = replaceAuctionPrice(nurl, cpm) const foundPixels = () => window.document.body.querySelectorAll(`img[src="${imgSrc}"]`) - - it('Should not create nurl pixel if bid is undefined', function(){ + it('Should not create nurl pixel if bid is undefined', function() { spec.onBidWon() expect(foundPixels().length).to.equal(0) }) - it('Should not create nurl pixel if bid does not contains nurl', function(){ + it('Should not create nurl pixel if bid does not contains nurl', function() { spec.onBidWon({}) expect(foundPixels().length).to.equal(0) }) - it('Should create nurl pixel if bid nurl', function(){ + it('Should create nurl pixel if bid nurl', function() { spec.onBidWon({ nurl, cpm }) expect(foundPixels().length).to.equal(1) }) - }) describe('getUserSyncs', function() { - it('Should return an empty array if not get serverResponses', function() { expect(spec.getUserSyncs({}).length).to.equal(0) }) @@ -300,12 +296,9 @@ describe('videonowAdapterTests', function() { expect(syncs[0].type).to.equal('iframe') expect(syncs[1].type).to.equal('iframe') }) - }) - describe('interpretResponse', function() { - const bidRequest = { method: 'POST', url: 'http://localhost:8086/bid?profile_id=1', @@ -319,7 +312,6 @@ describe('videonowAdapterTests', function() { }, } - it('Should have only one bid', function() { const serverResponse = getValidServerResponse() const result = spec.interpretResponse(serverResponse, bidRequest) @@ -378,7 +370,6 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) - it('Should return an empty array if serverResponse\'s price in the bid is undefined', function() { const serverResp = getValidServerResponse() delete serverResp.body.seatbid[0].bid[0].price @@ -394,7 +385,6 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) - it('Should return an empty array if serverResponse\'s vnInitModule in the bid\'s ext is undefined', function() { const serverResp = getValidServerResponse() delete serverResp.body.seatbid[0].bid[0].ext.vnInitModule @@ -403,7 +393,6 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) - it('Should return an empty array if serverResponse\'s vnModule in the bid\'s ext is undefined', function() { const serverResp = getValidServerResponse() delete serverResp.body.seatbid[0].bid[0].ext.vnModule @@ -412,9 +401,9 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) - it('Should return an empty array if serverResponse\'s dataXml in the bid\'s ext is undefined', function() { + it('Should return an empty array if serverResponse\'s adm in the bid is undefined', function() { const serverResp = getValidServerResponse() - delete serverResp.body.seatbid[0].bid[0].ext.dataXml + delete serverResp.body.seatbid[0].bid[0].adm const res = spec.interpretResponse(serverResp, bidRequest) expect(res.length).to.equal(0) @@ -452,8 +441,85 @@ describe('videonowAdapterTests', function() { expect(res[0].currency).to.equal('RUB') }) - describe('renderer object', function() { + describe('different module paths', function() { + beforeEach(function() { + window.localStorage && localStorage.setItem(LS_ITEM_NAME, '{}') + }) + + afterEach(function() { + const serverResp = getValidServerResponse() + let src = serverResp.body.seatbid[0].bid[0].ext.vnInitModule + let d = document.querySelectorAll(`script[src^="${src}"]`) + d && d.forEach(el => el && el.remove()) + src = serverResp.body.seatbid[0].bid[0].ext.vnModule + d = document.querySelectorAll(`script[src^="${src}"]`) + d && d.forEach(el => el && el.remove()) + }) + + it('should use prod modules by default', function() { + const serverResp = getValidServerResponse() + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + + const renderer = res[0].renderer + expect(renderer).to.be.an('object') + expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.vnModule) + }) + + it('should use custom path for vnModule', function() { + const serverResp = getValidServerResponse() + const vnInitModule = serverResp.body.seatbid[0].bid[0].ext.vnInitModule + '?dev=1' + const vnModule = serverResp.body.seatbid[0].bid[0].ext.vnModule + '?dev=1' + localStorage.setItem(LS_ITEM_NAME, JSON.stringify({ + vnInitModule, + vnModule + })) + + const src = `${vnInitModule}&profileId=1` + const placementElement = document.createElement('div') + placementElement.setAttribute('id', placementId) + const resp = spec.interpretResponse(serverResp, bidRequest) + expect(resp.length).to.equal(1) + + const renderer = resp[0].renderer + expect(renderer).to.be.an('object') + expect(renderer.url).to.equal(vnModule) + + document.body.appendChild(placementElement) + + renderer.render() + + const res = document.querySelectorAll(`script[src="${src}"]`) + expect(res.length).to.equal(1) + }) + + it('should correct combine src for vnInitModule', function() { + // localStorage.setItem(LS_ITEM_NAME, '{}') + const serverResp = getValidServerResponse() + + const src = `${serverResp.body.seatbid[0].bid[0].ext.vnInitModule}?profileId=1` + const placementElement = document.createElement('div') + placementElement.setAttribute('id', placementId) + + const resp = spec.interpretResponse(serverResp, bidRequest) + expect(resp.length).to.equal(1) + + const renderer = resp[0].renderer + expect(renderer).to.be.an('object') + + document.body.appendChild(placementElement) + + renderer.render() + + // expect(Array.from(document.querySelectorAll('script')).map(s => s.src)).to.equal({}) + // + const res = document.querySelectorAll(`script[src="${src}"]`) + expect(res.length).to.equal(1) + }) + }) + + describe('renderer object', function() { it('execute renderer.render() should create window.videonow object', function() { const serverResp = getValidServerResponse() const res = spec.interpretResponse(serverResp, bidRequest) @@ -485,9 +551,6 @@ describe('videonowAdapterTests', function() { renderer.render() expect(window.videonow).to.be.undefined }) - }) - }) - }) From 833cc86b539a409f2db338811352032d488d71ba Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Fri, 6 Sep 2019 11:32:33 +0300 Subject: [PATCH 17/25] -- a few clean the test's code --- test/spec/modules/videoNowBidAdapter_spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index 09632ee13c0..d16edb49705 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -250,9 +250,11 @@ describe('videonowAdapterTests', function() { spec.onBidWon({ nurl, cpm }) expect(foundPixels().length).to.equal(1) }) + }) describe('getUserSyncs', function() { + it('Should return an empty array if not get serverResponses', function() { expect(spec.getUserSyncs({}).length).to.equal(0) }) @@ -393,6 +395,7 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) + it('Should return an empty array if serverResponse\'s vnModule in the bid\'s ext is undefined', function() { const serverResp = getValidServerResponse() delete serverResp.body.seatbid[0].bid[0].ext.vnModule @@ -520,6 +523,7 @@ describe('videonowAdapterTests', function() { }) describe('renderer object', function() { + it('execute renderer.render() should create window.videonow object', function() { const serverResp = getValidServerResponse() const res = spec.interpretResponse(serverResp, bidRequest) From 0f8c673f60266369522b145f4ee286c6b0345b94 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Fri, 6 Sep 2019 17:05:22 +0300 Subject: [PATCH 18/25] -- new init model --- modules/videoNowBidAdapter.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 4c6c7c8b55f..f62ad6c81a7 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,6 +1,7 @@ import * as utils from '../src/utils' import { registerBidder } from '../src/adapters/bidderFactory' import { BANNER } from '../src/mediaTypes' +import { walkUpWindows } from '../src/refererDetection' const RTB_URL = 'https://bidder.videonow.ru/prebid' @@ -83,20 +84,22 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { return null } - const { vnInitModule, vnModule, format } = ext || {} + const { init, module, format } = ext || {} const vnData = JSON.parse(localStorage.getItem(LS_ITEM_NAME) || '{}') - let { vnModule: vnModuleCustom, vnInitModule: vnInitModuleCustom } = vnData + let { module: { log, min }, init: customInit } = vnData - const vnInitModulePath = vnInitModuleCustom || vnInitModule - if (!vnInitModulePath) { + const initPath = customInit || init + if (!initPath) { utils.logError(`vnInitModulePath is not defined`) return null } - const vntModulePath = vnModuleCustom || vnModule - if (!vntModulePath) { - utils.logError(`vntModulePath is not defined`) + min && (module.min = min) + log && (module.log = log) + + if (!module.min && module.log) { + utils.logError('module\'s paths are not defined') return null } @@ -112,27 +115,28 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { ad: code, nurl, renderer: { - url: vntModulePath, + url: module.min || module.log, render: function() { const d = window.document const el = placementId && d.getElementById(placementId) if (el) { + const pId = 1 // prepare data for vn_init script const profileData = { - url: vntModulePath, + module, dataXml: adm, } format && (profileData.format = format) // add init data for vn_init on the page - window.videonow = { - 'init': { '1': profileData }, - } + const videonow = window.videonow = window.videonow || {} + const init = videonow.init = window.videonow.init || {} + init[pId] = [ profileData ] // add vn_init js on the page const scr = document.createElement('script') - scr.src = `${vnInitModulePath}${~vnInitModulePath.indexOf('?') ? '&' : '?'}profileId=1` + scr.src = `${initPath}${~initPath.indexOf('?') ? '&' : '?'}profileId=${pId}` el && el.appendChild(scr) } else { utils.logError(`bidAdapter ${BIDDER_CODE}: ${placementId} not found`) From dea7e2d27faa0086e6b21999b8d2a07f7d9585d4 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Fri, 6 Sep 2019 17:05:40 +0300 Subject: [PATCH 19/25] -- spec for new init model --- test/spec/modules/videoNowBidAdapter_spec.js | 55 +++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index d16edb49705..6fc416e8df0 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -26,8 +26,11 @@ const getValidServerResponse = () => { h: 640, w: 480, ext: { - vnInitModule: 'http://localhost:8086/vn_init.js', - vnModule: 'http://localhost:8086/vn_module.js', + init: 'http://localhost:8086/vn_init.js', + module: { + min: 'http://localhost:8086/vn_module.js', + log: 'http://localhost:8086/vn_module.js?log=1' + }, format: { name: 'flyRoll', }, @@ -250,11 +253,9 @@ describe('videonowAdapterTests', function() { spec.onBidWon({ nurl, cpm }) expect(foundPixels().length).to.equal(1) }) - }) describe('getUserSyncs', function() { - it('Should return an empty array if not get serverResponses', function() { expect(spec.getUserSyncs({}).length).to.equal(0) }) @@ -387,18 +388,17 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(0) }) - it('Should return an empty array if serverResponse\'s vnInitModule in the bid\'s ext is undefined', function() { + it('Should return an empty array if serverResponse\'s init in the bid\'s ext is undefined', function() { const serverResp = getValidServerResponse() - delete serverResp.body.seatbid[0].bid[0].ext.vnInitModule + delete serverResp.body.seatbid[0].bid[0].ext.init const res = spec.interpretResponse(serverResp, bidRequest) expect(res.length).to.equal(0) }) - - it('Should return an empty array if serverResponse\'s vnModule in the bid\'s ext is undefined', function() { + it('Should return an empty array if serverResponse\'s module in the bid\'s ext is undefined', function() { const serverResp = getValidServerResponse() - delete serverResp.body.seatbid[0].bid[0].ext.vnModule + delete serverResp.body.seatbid[0].bid[0].ext.module const res = spec.interpretResponse(serverResp, bidRequest) expect(res.length).to.equal(0) @@ -451,12 +451,16 @@ describe('videonowAdapterTests', function() { afterEach(function() { const serverResp = getValidServerResponse() - let src = serverResp.body.seatbid[0].bid[0].ext.vnInitModule - let d = document.querySelectorAll(`script[src^="${src}"]`) - d && d.forEach(el => el && el.remove()) - src = serverResp.body.seatbid[0].bid[0].ext.vnModule - d = document.querySelectorAll(`script[src^="${src}"]`) - d && d.forEach(el => el && el.remove()) + const { module: { log, min }, init } = serverResp.body.seatbid[0].bid[0].ext + remove(init) + remove(log) + remove(min) + + function remove(src) { + if (!src) return + d = document.querySelectorAll(`script[src^="${src}"]`) + d && d.forEach(el => el && el.remove()) + } }) it('should use prod modules by default', function() { @@ -466,19 +470,19 @@ describe('videonowAdapterTests', function() { const renderer = res[0].renderer expect(renderer).to.be.an('object') - expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.vnModule) + expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.module) }) - it('should use custom path for vnModule', function() { + it('should use custom path for module', function() { const serverResp = getValidServerResponse() - const vnInitModule = serverResp.body.seatbid[0].bid[0].ext.vnInitModule + '?dev=1' - const vnModule = serverResp.body.seatbid[0].bid[0].ext.vnModule + '?dev=1' + const init = serverResp.body.seatbid[0].bid[0].ext.init + '?dev=1' + const module = serverResp.body.seatbid[0].bid[0].ext.module.min + '?dev=1' localStorage.setItem(LS_ITEM_NAME, JSON.stringify({ - vnInitModule, - vnModule + init, + module })) - const src = `${vnInitModule}&profileId=1` + const src = `${init}&profileId=1` const placementElement = document.createElement('div') placementElement.setAttribute('id', placementId) @@ -487,7 +491,7 @@ describe('videonowAdapterTests', function() { const renderer = resp[0].renderer expect(renderer).to.be.an('object') - expect(renderer.url).to.equal(vnModule) + expect(renderer.url).to.equal(module) document.body.appendChild(placementElement) @@ -497,11 +501,11 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(1) }) - it('should correct combine src for vnInitModule', function() { + it('should correct combine src for init', function() { // localStorage.setItem(LS_ITEM_NAME, '{}') const serverResp = getValidServerResponse() - const src = `${serverResp.body.seatbid[0].bid[0].ext.vnInitModule}?profileId=1` + const src = `${serverResp.body.seatbid[0].bid[0].ext.init}?profileId=1` const placementElement = document.createElement('div') placementElement.setAttribute('id', placementId) @@ -523,7 +527,6 @@ describe('videonowAdapterTests', function() { }) describe('renderer object', function() { - it('execute renderer.render() should create window.videonow object', function() { const serverResp = getValidServerResponse() const res = spec.interpretResponse(serverResp, bidRequest) From fbbd777e7c49d8b653b792867c91eb722b5d7d0e Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Fri, 6 Sep 2019 17:08:14 +0300 Subject: [PATCH 20/25] -- fix for new init model --- modules/videoNowBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index f62ad6c81a7..c3c6074f6d9 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -132,7 +132,7 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { // add init data for vn_init on the page const videonow = window.videonow = window.videonow || {} const init = videonow.init = window.videonow.init || {} - init[pId] = [ profileData ] + init[pId] = profileData // add vn_init js on the page const scr = document.createElement('script') From 62811b7455a89f02b662ce37889945097df08575 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 9 Sep 2019 14:11:34 +0300 Subject: [PATCH 21/25] -- code cleaned --- modules/videoNowBidAdapter.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index c3c6074f6d9..7b358f64939 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,13 +1,11 @@ import * as utils from '../src/utils' import { registerBidder } from '../src/adapters/bidderFactory' import { BANNER } from '../src/mediaTypes' -import { walkUpWindows } from '../src/refererDetection' const RTB_URL = 'https://bidder.videonow.ru/prebid' const BIDDER_CODE = 'videonow' const TTL_SECONDS = 60 * 5 -const LS_ITEM_NAME = 'VN_DATA' function isBidRequestValid(bid) { return !!(bid && bid.params && bid.params.pId) @@ -84,21 +82,15 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { return null } - const { init, module, format } = ext || {} - - const vnData = JSON.parse(localStorage.getItem(LS_ITEM_NAME) || '{}') - let { module: { log, min }, init: customInit } = vnData - - const initPath = customInit || init + const { init: initPath, module, format } = ext || {} if (!initPath) { utils.logError(`vnInitModulePath is not defined`) return null } - min && (module.min = min) - log && (module.log = log) + const { log, min } = module || {} - if (!module.min && module.log) { + if (!min && !log) { utils.logError('module\'s paths are not defined') return null } @@ -115,7 +107,7 @@ function createResponseBid(bidInfo, bidId, cur, placementId) { ad: code, nurl, renderer: { - url: module.min || module.log, + url: min || log, render: function() { const d = window.document const el = placementId && d.getElementById(placementId) From a4d0bfd34be440108f7085ba2b7cb194c9653328 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 9 Sep 2019 14:12:03 +0300 Subject: [PATCH 22/25] -- 100% tests coverage --- test/spec/modules/videoNowBidAdapter_spec.js | 44 +++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index 6fc416e8df0..a36c6c64f14 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -3,7 +3,7 @@ import { spec } from 'modules/videoNowBidAdapter' import { replaceAuctionPrice } from '../../../src/utils' const placementId = 'div-gpt-ad-1438287399331-0' -const LS_ITEM_NAME = 'VN_DATA' +const LS_ITEM_NAME = 'videonow-config' const getValidServerResponse = () => { const serverResponse = { @@ -451,38 +451,43 @@ describe('videonowAdapterTests', function() { afterEach(function() { const serverResp = getValidServerResponse() - const { module: { log, min }, init } = serverResp.body.seatbid[0].bid[0].ext + const { module: { log, min }, init } = serverResp.body.seatbid[0].bid[0].ext remove(init) remove(log) remove(min) function remove(src) { if (!src) return - d = document.querySelectorAll(`script[src^="${src}"]`) + const d = document.querySelectorAll(`script[src^="${src}"]`) d && d.forEach(el => el && el.remove()) } }) - it('should use prod modules by default', function() { + it('should use prod module by default', function() { const serverResp = getValidServerResponse() const res = spec.interpretResponse(serverResp, bidRequest) expect(res.length).to.equal(1) const renderer = res[0].renderer expect(renderer).to.be.an('object') - expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.module) + expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.module.min) }) - it('should use custom path for module', function() { + it('should use "log" module if "prod" is not exists', function() { const serverResp = getValidServerResponse() - const init = serverResp.body.seatbid[0].bid[0].ext.init + '?dev=1' - const module = serverResp.body.seatbid[0].bid[0].ext.module.min + '?dev=1' - localStorage.setItem(LS_ITEM_NAME, JSON.stringify({ - init, - module - })) - - const src = `${init}&profileId=1` + delete serverResp.body.seatbid[0].bid[0].ext.module.min + const res = spec.interpretResponse(serverResp, bidRequest) + expect(res.length).to.equal(1) + + const renderer = res[0].renderer + expect(renderer).to.be.an('object') + expect(renderer.url).to.equal(serverResp.body.seatbid[0].bid[0].ext.module.log) + }) + + it('should correct combine src for init', function() { + const serverResp = getValidServerResponse() + + const src = `${serverResp.body.seatbid[0].bid[0].ext.init}?profileId=1` const placementElement = document.createElement('div') placementElement.setAttribute('id', placementId) @@ -491,7 +496,6 @@ describe('videonowAdapterTests', function() { const renderer = resp[0].renderer expect(renderer).to.be.an('object') - expect(renderer.url).to.equal(module) document.body.appendChild(placementElement) @@ -501,11 +505,12 @@ describe('videonowAdapterTests', function() { expect(res.length).to.equal(1) }) - it('should correct combine src for init', function() { - // localStorage.setItem(LS_ITEM_NAME, '{}') + it('should correct combine src for init if init url contains "?"', function() { const serverResp = getValidServerResponse() - const src = `${serverResp.body.seatbid[0].bid[0].ext.init}?profileId=1` + serverResp.body.seatbid[0].bid[0].ext.init += '?div=1' + const src = `${serverResp.body.seatbid[0].bid[0].ext.init}&profileId=1` + const placementElement = document.createElement('div') placementElement.setAttribute('id', placementId) @@ -519,11 +524,10 @@ describe('videonowAdapterTests', function() { renderer.render() - // expect(Array.from(document.querySelectorAll('script')).map(s => s.src)).to.equal({}) - // const res = document.querySelectorAll(`script[src="${src}"]`) expect(res.length).to.equal(1) }) + }) describe('renderer object', function() { From 53a3b952763de7fb180975eb3d38548a0f2d161c Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Mon, 9 Sep 2019 17:25:23 +0300 Subject: [PATCH 23/25] -- 100% tests coverage --- test/spec/modules/videoNowBidAdapter_spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index a36c6c64f14..ae34bbfacf6 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -508,7 +508,7 @@ describe('videonowAdapterTests', function() { it('should correct combine src for init if init url contains "?"', function() { const serverResp = getValidServerResponse() - serverResp.body.seatbid[0].bid[0].ext.init += '?div=1' + serverResp.body.seatbid[0].bid[0].ext.init += '?div=1' const src = `${serverResp.body.seatbid[0].bid[0].ext.init}&profileId=1` const placementElement = document.createElement('div') @@ -527,7 +527,6 @@ describe('videonowAdapterTests', function() { const res = document.querySelectorAll(`script[src="${src}"]`) expect(res.length).to.equal(1) }) - }) describe('renderer object', function() { From 5801534280f7758bc71bd567c8427b5d99b7f74b Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 12 Sep 2019 15:03:47 +0300 Subject: [PATCH 24/25] -- fixed test --- test/spec/modules/videoNowBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index ae34bbfacf6..ade996be2e3 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -459,7 +459,7 @@ describe('videonowAdapterTests', function() { function remove(src) { if (!src) return const d = document.querySelectorAll(`script[src^="${src}"]`) - d && d.forEach(el => el && el.remove()) + d && d.length && Array.from(d).forEach(el => el && el.remove()) } }) From 3c1f76fe1ae0c0d6facd320183ddbf11856ea004 Mon Sep 17 00:00:00 2001 From: sergeydaub Date: Thu, 12 Sep 2019 15:26:29 +0300 Subject: [PATCH 25/25] -- commit for restart tests --- test/spec/modules/videoNowBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/videoNowBidAdapter_spec.js b/test/spec/modules/videoNowBidAdapter_spec.js index ade996be2e3..337960c6edd 100644 --- a/test/spec/modules/videoNowBidAdapter_spec.js +++ b/test/spec/modules/videoNowBidAdapter_spec.js @@ -2,7 +2,7 @@ import { expect } from 'chai' import { spec } from 'modules/videoNowBidAdapter' import { replaceAuctionPrice } from '../../../src/utils' -const placementId = 'div-gpt-ad-1438287399331-0' +const placementId = 'div-gpt-ad-1438287399331-1' const LS_ITEM_NAME = 'videonow-config' const getValidServerResponse = () => {