From 2121f18a246fda7987461a302ecb2a3b1024ac3f Mon Sep 17 00:00:00 2001 From: TinchoF <50110327+TinchoF@users.noreply.github.com> Date: Tue, 8 Oct 2019 10:00:07 -0300 Subject: [PATCH 01/38] Outcon bid adapter. (#4161) * Outcon bid adapter. * Fix identation * Fixes * Fixes * Fixes * Spec fixes * Fixes * Fix urls * Fix * Fix parameters * Fix space operators * Fix bidder timeout * Update * Fix whitespace * no message * Outcon unit test * no message * no message * no message * no message * Fixes * Fixes * Change url * no message * no message * no message * Added bidId * no message * no message * no message * no message * Wrapping url with html * no message * no message * no message --- modules/outconAdapter.md | 26 ++++++ modules/outconBidAdapter.js | 59 +++++++++++++ test/spec/modules/outconBidAdapter_spec.js | 98 ++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 modules/outconAdapter.md create mode 100644 modules/outconBidAdapter.js create mode 100644 test/spec/modules/outconBidAdapter_spec.js diff --git a/modules/outconAdapter.md b/modules/outconAdapter.md new file mode 100644 index 00000000000..88ed45396bc --- /dev/null +++ b/modules/outconAdapter.md @@ -0,0 +1,26 @@ +# Overview + +``` +Module Name: outconAdapter +Module Type: Bidder Adapter +Maintainer: mfolmer@dokkogroup.com.ar +``` + +# Description + +Module that connects to Outcon demand sources + +# Test Parameters +``` + var adUnits = [ + { + bidder: 'outcon', + params: { + internalId: '12345678', + publisher: '5d5d66f2306ea4114a37c7c2', + bidId: '123456789', + env: 'test' + } + } + ]; +``` \ No newline at end of file diff --git a/modules/outconBidAdapter.js b/modules/outconBidAdapter.js new file mode 100644 index 00000000000..d691e807059 --- /dev/null +++ b/modules/outconBidAdapter.js @@ -0,0 +1,59 @@ +import {registerBidder} from '../src/adapters/bidderFactory'; +import {config} from '../src/config'; + +const BIDDER_CODE = 'outcon'; +export const spec = { + code: BIDDER_CODE, + isBidRequestValid: function(bid) { + return !!((bid.params.pod || (bid.params.internalId && bid.params.publisher)) && bid.params.env); + }, + buildRequests: function(validBidRequests) { + for (let i = 0; i < validBidRequests.length; i++) { + let par = ''; + let url = ''; + if (validBidRequests[i].params.pod != undefined) par = 'get?pod=' + validBidRequests[i].params.pod + '&bidId=' + validBidRequests[i].bidId; + else par = 'get?internalId=' + validBidRequests[i].params.internalId + '&publisher=' + validBidRequests[i].params.publisher + '&bidId=' + validBidRequests[i].bidId; + switch (validBidRequests[i].params.env) { + case 'test': + par = par + '&demo=true'; + url = 'http://test.outcondigital.com:8048/ad/' + par; + break; + case 'api': + url = 'http://api.outcondigital.com:8048/ad/' + par; + break; + case 'stg': + url = 'http://stg.outcondigital.com:8048/ad/' + par; + break; + } + return { + method: 'GET', + url: url, + data: {} + }; + } + }, + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + const bidResponse = { + requestId: serverResponse.body.bidId, + cpm: serverResponse.body.cpm, + width: serverResponse.body.creatives[0].width, + height: serverResponse.body.creatives[0].height, + creativeId: serverResponse.body.creatives[0].id, + currency: serverResponse.body.cur, + netRevenue: true, + ttl: config.getConfig('_bidderTimeout'), + ad: wrapDisplayUrl(serverResponse.body.creatives[0].url, serverResponse.body.type), + vastImpUrl: serverResponse.body.trackingURL + }; + bidResponses.push(bidResponse); + return bidResponses; + }, +} + +function wrapDisplayUrl(displayUrl, type) { + if (type == 'video') return `
`; + if (type == 'banner') return `
`; +} + +registerBidder(spec); diff --git a/test/spec/modules/outconBidAdapter_spec.js b/test/spec/modules/outconBidAdapter_spec.js new file mode 100644 index 00000000000..dc9c96ed3a3 --- /dev/null +++ b/test/spec/modules/outconBidAdapter_spec.js @@ -0,0 +1,98 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/outconBidAdapter'; + +describe('outconBidAdapter', function () { + describe('bidRequestValidity', function () { + it('Check the bidRequest with pod param', function () { + expect(spec.isBidRequestValid({ + bidder: 'outcon', + params: { + pod: '5d603538eba7192ae14e39a4', + env: 'test' + } + })).to.equal(true); + }); + it('Check the bidRequest with internalID and publisherID params', function () { + expect(spec.isBidRequestValid({ + bidder: 'outcon', + params: { + internalId: '12345678', + publisher: '5d5d66f2306ea4114a37c7c2', + env: 'test' + } + })).to.equal(true); + }); + }); + describe('buildRequests', function () { + it('Build requests with pod param', function () { + expect(spec.buildRequests([{ + bidder: 'outcon', + params: { + pod: '5d603538eba7192ae14e39a4', + env: 'test' + } + }])).to.have.keys('method', 'url', 'data'); + }); + + it('Build requests with internalID and publisherID params', function () { + expect(spec.buildRequests([{ + bidder: 'outcon', + params: { + internalId: '12345678', + publisher: '5d5d66f2306ea4114a37c7c2', + env: 'test' + } + }])).to.have.keys('method', 'url', 'data'); + }); + }); + + describe('interpretResponse', function () { + const bidRequest = { + method: 'GET', + url: 'http://test.outcondigital.com:8048/ad/', + data: { + pod: '5d603538eba7192ae14e39a4', + env: 'test' + } + }; + const bidResponse = { + body: { + cpm: 0.10, + cur: 'USD', + exp: 10, + creatives: [ + { + url: 'http://test.outcondigital.com/uploads/5d42e7a7306ea4689b67c122/frutas.mp4', + size: 3, + width: 1920, + height: 1080, + codec: 'video/mp4' + } + ], + id: '5d6e6aef22063e392bf7f564', + type: 'video', + campaign: '5d42e44b306ea469593c76a2', + trackingURL: 'http://test.outcondigital.com:8048/ad/track?track=5d6e6aef22063e392bf7f564' + }, + }; + it('check all the keys that are needed to interpret the response', function () { + const result = spec.interpretResponse(bidResponse, bidRequest); + let requiredKeys = [ + 'requestId', + 'cpm', + 'width', + 'height', + 'creativeId', + 'currency', + 'netRevenue', + 'ttl', + 'ad', + 'vastImpUrl' + ]; + let resultKeys = Object.keys(result[0]); + resultKeys.forEach(function(key) { + expect(requiredKeys.indexOf(key) !== -1).to.equal(true); + }); + }) + }); +}); From 3ee0d9795afcaff341ec322d662df183a1f564b9 Mon Sep 17 00:00:00 2001 From: Jaimin Panchal <7393273+jaiminpanchal27@users.noreply.github.com> Date: Tue, 8 Oct 2019 14:49:11 -0400 Subject: [PATCH 02/38] Adding workflow to run end to end tests (#4230) * Adding workflow to run end to end tests * trying self branch * Update to run at 12 every day * cleanup config using aliases * update branch and cron time * add command --- .circleci/config.yml | 133 ++++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 47 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 73ec23aa740..0d48ec13fa1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,54 +2,93 @@ # # Check https://circleci.com/docs/2.0/language-javascript/ for more details # + +aliases: + - &environment + docker: + # specify the version you desire here + - image: circleci/node:8.9.0 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/mongo:3.4.4 + working_directory: ~/Prebid.js + + - &restore_dep_cache + keys: + - v1-dependencies-{{ checksum "package.json" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + + - &save_dep_cache + paths: + - node_modules + key: v1-dependencies-{{ checksum "package.json" }} + + - &install + name: Install gulp cli + command: sudo npm install -g gulp-cli + + - &run_unit_test + name: BrowserStack testing + command: gulp test --browserstack --nolintfix + + - &run_endtoend_test + name: BrowserStack End to end testing + command: echo "127.0.0.1 test.localhost" | sudo tee -a /etc/hosts && gulp e2e-test --host=test.localhost + + # Download and run BrowserStack local + - &setup_browserstack + name : Download BrowserStack Local binary and start it. + command : | + # Download the browserstack binary file + wget "https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip" + # Unzip it + unzip BrowserStackLocal-linux-x64.zip + # Run the file with user's access key + ./BrowserStackLocal ${BROWSERSTACK_ACCESS_KEY} & + + - &unit_test_steps + - checkout + - restore_cache: *restore_dep_cache + - run: npm install + - save_cache: *save_dep_cache + - run: *install + - run: *setup_browserstack + - run: *run_unit_test + + - &endtoend_test_steps + - checkout + - restore_cache: *restore_dep_cache + - run: npm install + - save_cache: *save_dep_cache + - run: *install + - run: *setup_browserstack + - run: *run_endtoend_test + version: 2 jobs: build: - docker: - # specify the version you desire here - - image: circleci/node:8.9.0 + <<: *environment + steps: *unit_test_steps - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - # - image: circleci/mongo:3.4.4 - - working_directory: ~/Prebid.js - - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: npm install - - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - - run: sudo npm install -g gulp-cli - - # Download and run BrowserStack local - - run: - name : Download BrowserStack Local binary and start it. - command : | - # Download the browserstack binary file - wget "https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip" - # Unzip it - unzip BrowserStackLocal-linux-x64.zip - # Run the file with user's access key - ./BrowserStackLocal ${BROWSERSTACK_ACCESS_KEY} & - # run tests! - - run: - name: BrowserStack testing - command: gulp test --browserstack --nolintfix - # run e2e tests - - run: - name: Functional testing - command: echo "127.0.0.1 test.localhost" | sudo tee -a /etc/hosts && gulp e2e-test --host=test.localhost --file=./test/spec/e2e/banner/basic_banner_ad.spec.js + e2etest: + <<: *environment + steps: *endtoend_test_steps + +workflows: + version: 2 + commit: + jobs: + - build + nightly: + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: + - master + jobs: + - e2etest From 6af3e5fc8a4775b188ce4f587bb5cf450ab99dda Mon Sep 17 00:00:00 2001 From: Jaimin Panchal <7393273+jaiminpanchal27@users.noreply.github.com> Date: Tue, 8 Oct 2019 15:29:02 -0400 Subject: [PATCH 03/38] update prebid path for e2e test pages (#4274) --- integrationExamples/longform/basic_w_bidderSettings.html | 2 +- integrationExamples/longform/basic_w_priceGran.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationExamples/longform/basic_w_bidderSettings.html b/integrationExamples/longform/basic_w_bidderSettings.html index 4ccb01fbd6e..f9389686b1f 100644 --- a/integrationExamples/longform/basic_w_bidderSettings.html +++ b/integrationExamples/longform/basic_w_bidderSettings.html @@ -5,7 +5,7 @@ Prebid Freewheel Integration Demo - + + + data-player-host="${urls.vlHost}">
Date: Tue, 15 Oct 2019 19:49:51 +0200 Subject: [PATCH 24/38] [Orbidder-Adapter] Add bidRequestCount and remove bid.params.keyValues (#4264) * initial orbidder version in personal github repo * use adUnits from orbidder_example.html * replace obsolete functions * forgot to commit the test * check if bidderRequest object is available * try to fix weird safari/ie issue * ebayK: add more params * update orbidderBidAdapter.md * use spec. instead of this. for consistency reasons * add bidfloor parameter to params object * fix gdpr object handling * default to consentRequired: false when not explicitly given * wip - use onSetTargeting callback * add tests for onSetTargeting callback * fix params and respective tests * remove not used bid.params.keyValues * add bidRequestCount to orbidder.otto.de/bid Post request * add bidRequestCount to test object defaultBidRequest --- modules/orbidderBidAdapter.js | 2 +- test/spec/modules/orbidderBidAdapter_spec.js | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/modules/orbidderBidAdapter.js b/modules/orbidderBidAdapter.js index 954ad82261f..88534ae1596 100644 --- a/modules/orbidderBidAdapter.js +++ b/modules/orbidderBidAdapter.js @@ -19,7 +19,6 @@ export const spec = { (bid.params.accountId && (typeof bid.params.accountId === 'string')) && (bid.params.placementId && (typeof bid.params.placementId === 'string')) && ((typeof bid.params.bidfloor === 'undefined') || (typeof bid.params.bidfloor === 'number')) && - ((typeof bid.params.keyValues === 'undefined') || (typeof bid.params.keyValues === 'object')) && ((typeof bid.params.profile === 'undefined') || (typeof bid.params.profile === 'object'))); }, @@ -38,6 +37,7 @@ export const spec = { auctionId: bidRequest.auctionId, transactionId: bidRequest.transactionId, adUnitCode: bidRequest.adUnitCode, + bidRequestCount: bidRequest.bidRequestCount, sizes: bidRequest.sizes, params: bidRequest.params } diff --git a/test/spec/modules/orbidderBidAdapter_spec.js b/test/spec/modules/orbidderBidAdapter_spec.js index aeaa5f30446..1b76de9841a 100644 --- a/test/spec/modules/orbidderBidAdapter_spec.js +++ b/test/spec/modules/orbidderBidAdapter_spec.js @@ -10,6 +10,7 @@ describe('orbidderBidAdapter', () => { bidId: 'd66fa86787e0b0ca900a96eacfd5f0bb', auctionId: 'ccc4c7cdfe11cfbd74065e6dd28413d8', transactionId: 'd58851660c0c4461e4aa06344fc9c0c6', + bidRequestCount: 1, adUnitCode: 'adunit-code', sizes: [[300, 250], [300, 600]], params: { @@ -46,12 +47,6 @@ describe('orbidderBidAdapter', () => { expect(spec.isBidRequestValid(defaultBidRequest)).to.equal(true); }); - it('accepts optional keyValues object', () => { - const bidRequest = deepClone(defaultBidRequest); - bidRequest.params.keyValues = {'key': 'value'}; - expect(spec.isBidRequestValid(bidRequest)).to.equal(true); - }); - it('accepts optional profile object', () => { const bidRequest = deepClone(defaultBidRequest); bidRequest.params.profile = {'key': 'value'}; @@ -64,12 +59,6 @@ describe('orbidderBidAdapter', () => { expect(spec.isBidRequestValid(bidRequest)).to.equal(false); }); - it('doesn\'t accept malformed keyValues', () => { - const bidRequest = deepClone(defaultBidRequest); - bidRequest.params.keyValues = 'another not usable string'; - expect(spec.isBidRequestValid(bidRequest)).to.equal(false); - }); - it('doesn\'t accept malformed profile', () => { const bidRequest = deepClone(defaultBidRequest); bidRequest.params.profile = 'another not usable string'; From 6fb670620346c34c19b819661c1b59938cb06e41 Mon Sep 17 00:00:00 2001 From: Anand Venkatraman Date: Tue, 15 Oct 2019 23:23:37 +0530 Subject: [PATCH 25/38] PulsePoint: remove usage of deprecated utils method / prep for 3.0 (#4257) * ET-1691: Pulsepoint Analytics adapter for Prebid. (#1) * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: cleanup * ET-1691: minor * ET-1691: revert package.json change * Adding bidRequest to bidFactory.createBid method as per https://github.com/prebid/Prebid.js/issues/509 * ET-1765: Adding support for additional params in PulsePoint adapter (#2) * ET-1850: Fixing https://github.com/prebid/Prebid.js/issues/866 * Minor fix * Adding mandatory parameters to Bid * Removing usage of deprecated utils method * minor refactor --- modules/pulsepointBidAdapter.js | 12 +++--- .../spec/modules/pulsepointBidAdapter_spec.js | 42 +++++++++++-------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 9c0d67d9612..fee247ba31f 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -40,7 +40,7 @@ export const spec = { const request = { id: bidRequests[0].bidderRequestId, imp: bidRequests.map(slot => impression(slot)), - site: site(bidRequests), + site: site(bidRequests, bidderRequest), app: app(bidRequests), device: device(), bcat: bidRequests[0].params.bcat, @@ -100,7 +100,7 @@ function bidResponseAvailable(request, response) { idToBidMap[bid.impid] = bid; })); } - if (request.bidderRequest) { + if (request.bidderRequest && request.bidderRequest.bids) { request.bidderRequest.bids.forEach(bid => { idToSlotConfig[bid.bidId] = bid; }); @@ -307,16 +307,16 @@ function dataAsset(id, params, type, defaultLen) { /** * Produces an OpenRTB site object. */ -function site(bidderRequest) { - const pubId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.cp : '0'; - const appParams = bidderRequest[0].params.app; +function site(bidRequests, bidderRequest) { + const pubId = bidRequests && bidRequests.length > 0 ? bidRequests[0].params.cp : '0'; + const appParams = bidRequests[0].params.app; if (!appParams) { return { publisher: { id: pubId.toString(), }, ref: referrer(), - page: utils.getTopWindowLocation().href, + page: bidderRequest && bidderRequest.refererInfo ? bidderRequest.refererInfo.referer : '', } } return null; diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 1d22ca6eadc..9ed6d3631f5 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -1,7 +1,7 @@ /* eslint dot-notation:0, quote-props:0 */ import {expect} from 'chai'; import {spec} from 'modules/pulsepointBidAdapter'; -import {deepClone, getTopWindowLocation} from 'src/utils'; +import {deepClone} from 'src/utils'; describe('PulsePoint Adapter Tests', function () { const slotConfigs = [{ @@ -138,9 +138,14 @@ describe('PulsePoint Adapter Tests', function () { } } }]; + const bidderRequest = { + refererInfo: { + referer: 'https://publisher.com/home' + } + }; it('Verify build request', function () { - const request = spec.buildRequests(slotConfigs); + const request = spec.buildRequests(slotConfigs, bidderRequest); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -149,7 +154,7 @@ describe('PulsePoint Adapter Tests', function () { expect(ortbRequest.site.publisher).to.not.equal(null); expect(ortbRequest.site.publisher.id).to.equal('p10000'); expect(ortbRequest.site.ref).to.equal(window.top.document.referrer); - expect(ortbRequest.site.page).to.equal(getTopWindowLocation().href); + expect(ortbRequest.site.page).to.equal('https://publisher.com/home'); expect(ortbRequest.imp).to.have.lengthOf(2); // device object expect(ortbRequest.device).to.not.equal(null); @@ -167,7 +172,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify parse response', function () { - const request = spec.buildRequests(slotConfigs); + const request = spec.buildRequests(slotConfigs, bidderRequest); const ortbRequest = request.data; const ortbResponse = { seatbid: [{ @@ -196,7 +201,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify use ttl in ext', function () { - const request = spec.buildRequests(slotConfigs); + const request = spec.buildRequests(slotConfigs, bidderRequest); const ortbRequest = request.data; const ortbResponse = { seatbid: [{ @@ -222,13 +227,13 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify full passback', function () { - const request = spec.buildRequests(slotConfigs); + const request = spec.buildRequests(slotConfigs, bidderRequest); const bids = spec.interpretResponse({ body: null }, request) expect(bids).to.have.lengthOf(0); }); it('Verify Native request', function () { - const request = spec.buildRequests(nativeSlotConfig); + const request = spec.buildRequests(nativeSlotConfig, bidderRequest); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -266,7 +271,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify Native response', function () { - const request = spec.buildRequests(nativeSlotConfig); + const request = spec.buildRequests(nativeSlotConfig, bidderRequest); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -355,7 +360,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify app requests', function () { - const request = spec.buildRequests(appSlotConfig); + const request = spec.buildRequests(appSlotConfig, bidderRequest); const ortbRequest = request.data; // site object expect(ortbRequest.site).to.equal(null); @@ -368,13 +373,13 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify GDPR', function () { - const bidderRequest = { + const bidderRequestGdpr = { gdprConsent: { gdprApplies: true, consentString: 'serialized_gpdr_data' } }; - const request = spec.buildRequests(slotConfigs, bidderRequest); + const request = spec.buildRequests(slotConfigs, Object.assign({}, bidderRequest, bidderRequestGdpr)); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -389,7 +394,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify Video request', function () { - const request = spec.buildRequests(videoSlotConfig); + const request = spec.buildRequests(videoSlotConfig, bidderRequest); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -409,7 +414,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify Video response', function () { - const request = spec.buildRequests(videoSlotConfig); + const request = spec.buildRequests(videoSlotConfig, bidderRequest); expect(request.url).to.equal('https://bid.contextweb.com/header/ortb?src=prebid'); expect(request.method).to.equal('POST'); const ortbRequest = request.data; @@ -433,7 +438,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify extra parameters', function () { - let request = spec.buildRequests(additionalParamsConfig); + let request = spec.buildRequests(additionalParamsConfig, bidderRequest); let ortbRequest = request.data; expect(ortbRequest).to.not.equal(null); expect(ortbRequest.imp).to.have.lengthOf(1); @@ -448,7 +453,7 @@ describe('PulsePoint Adapter Tests', function () { expect(ortbRequest.imp[0].ext.prebid.extra_key4).to.eql([1, 2, 3]); expect(Object.keys(ortbRequest.imp[0].ext.prebid)).to.eql(['extra_key1', 'extra_key2', 'extra_key3', 'extra_key4']); // attempting with a configuration with no unknown params. - request = spec.buildRequests(outstreamSlotConfig); + request = spec.buildRequests(outstreamSlotConfig, bidderRequest); ortbRequest = request.data; expect(ortbRequest).to.not.equal(null); expect(ortbRequest.imp).to.have.lengthOf(1); @@ -456,7 +461,7 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify ortb parameters', function () { - const request = spec.buildRequests(ortbParamsSlotConfig); + const request = spec.buildRequests(ortbParamsSlotConfig, bidderRequest); const ortbRequest = request.data; expect(ortbRequest).to.not.equal(null); expect(ortbRequest.bcat).to.eql(['IAB-1', 'IAB-20']); @@ -472,7 +477,8 @@ describe('PulsePoint Adapter Tests', function () { }); it('Verify outstream renderer', function () { - const request = spec.buildRequests(outstreamSlotConfig, {bids: [outstreamSlotConfig[0]]}); + const bidderRequestOutstream = Object.assign({}, bidderRequest, {bids: [outstreamSlotConfig[0]]}); + const request = spec.buildRequests(outstreamSlotConfig, bidderRequestOutstream); const ortbRequest = request.data; expect(ortbRequest).to.not.be.null; expect(ortbRequest.imp[0]).to.not.be.null; @@ -521,7 +527,7 @@ describe('PulsePoint Adapter Tests', function () { } } }; - const request = spec.buildRequests(bidRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request).to.be.not.null; const ortbRequest = request.data; expect(request.data).to.be.not.null; From d549a409db808f16a40b68f85d3dafdeeca4b32a Mon Sep 17 00:00:00 2001 From: Jaimin Panchal <7393273+jaiminpanchal27@users.noreply.github.com> Date: Tue, 15 Oct 2019 13:59:18 -0400 Subject: [PATCH 26/38] Use isArray method (#4288) --- src/adapters/bidderFactory.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 90cab154fd4..4ccbfd89457 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -9,7 +9,7 @@ import CONSTANTS from '../constants.json'; import events from '../events'; import includes from 'core-js/library/fn/array/includes'; import { ajax } from '../ajax'; -import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest, flatten, uniques, timestamp, setDataInLocalStorage, getDataFromLocalStorage, deepAccess } from '../utils'; +import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest, flatten, uniques, timestamp, setDataInLocalStorage, getDataFromLocalStorage, deepAccess, isArray } from '../utils'; import { ADPOD } from '../mediaTypes'; import { getHook } from '../hook'; @@ -290,7 +290,7 @@ export function newBidder(spec) { } if (bids) { - if (bids.forEach) { + if (isArray(bids)) { bids.forEach(addBidUsingRequestMap); } else { addBidUsingRequestMap(bids); From fceb471e7d1e61698e6e8c6141d551c01ed7a3db Mon Sep 17 00:00:00 2001 From: Eyas Ranjous Date: Tue, 15 Oct 2019 15:03:09 -0500 Subject: [PATCH 27/38] Add Parrable ID submodule (#4266) * add parrable id submodule * fix integration test config * fix var name * always refresh sotredId for parrable * add submodulesThatAlwaysRefresh concept * remove comment * add parrable url as one string * add parrable prod endpoint * use .indexOf instead of .includes * add params to test config * comment failing test * uncomment failing assertion * add parrable ID to prebid server adapter * add parrableIdSystem to .submodules.json * extract parrableId unit tests from userId spec * remove breakline between imports * remove unused param * remove userId generic feature from parrableId module * remove trailing space * fix failing test due to none merged conflict --- integrationExamples/gpt/userId_example.html | 11 +++ modules/.submodules.json | 1 + modules/parrableIdSystem.js | 92 +++++++++++++++++++ modules/prebidServerBidAdapter/index.js | 11 ++- modules/userId/index.js | 1 + modules/userId/userId.md | 11 +++ test/spec/modules/parrableIdSystem_spec.js | 77 ++++++++++++++++ .../modules/prebidServerBidAdapter_spec.js | 3 + 8 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 modules/parrableIdSystem.js create mode 100644 test/spec/modules/parrableIdSystem_spec.js diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index 09e9e4147fc..6d2c2ce677a 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -152,6 +152,17 @@ refreshInSeconds: 8*3600 // Refresh frequency of cookies, defaulting to 'expires' }, + }, { + name: "parrableId", + params: { + // change to Parrable Partner Client ID(s) you received from the Parrable Partners you are using + partner: '30182847-e426-4ff9-b2b5-9ca1324ea09b' + }, + storage: { + type: "cookie", + name: "_parrable_eid", // create a cookie with this name + expires: 365 // cookie can last for a year + } }, { name: "pubCommonId", storage: { diff --git a/modules/.submodules.json b/modules/.submodules.json index 81c82603083..09063deea40 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -3,6 +3,7 @@ "digiTrustIdSystem", "id5IdSystem", "criteortusIdSystem", + "parrableIdSystem", "liveIntentIdSystem" ], "adpod": [ diff --git a/modules/parrableIdSystem.js b/modules/parrableIdSystem.js new file mode 100644 index 00000000000..e8ad7f9acc1 --- /dev/null +++ b/modules/parrableIdSystem.js @@ -0,0 +1,92 @@ +/** + * This module adds Parrable to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/parrableIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils' +import {ajax} from '../src/ajax'; +import {submodule} from '../src/hook'; + +const PARRABLE_URL = 'https://h.parrable.com/prebid'; + +function isValidConfig(configParams) { + if (!configParams) { + utils.logError('User ID - parrableId submodule requires configParams'); + return false; + } + if (!configParams.partner) { + utils.logError('User ID - parrableId submodule requires partner list'); + return false; + } + return true; +} + +function fetchId(configParams, consentData, currentStoredId) { + if (!isValidConfig(configParams)) return; + + const data = { + eid: currentStoredId || null, + trackers: configParams.partner.split(',') + }; + + const searchParams = { + data: btoa(JSON.stringify(data)), + _rand: Math.random() + }; + + const options = { + method: 'GET', + withCredentials: true + }; + + const callback = function (cb) { + const onSuccess = (response) => { + let eid; + if (response) { + try { + let responseObj = JSON.parse(response); + eid = responseObj ? responseObj.eid : undefined; + } catch (error) { + utils.logError(error); + } + } + cb(eid); + }; + ajax(PARRABLE_URL, onSuccess, searchParams, options); + }; + + return { callback }; +}; + +/** @type {Submodule} */ +export const parrableIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'parrableId', + /** + * decode the stored id value for passing to bid requests + * @function + * @param {Object|string} value + * @return {(Object|undefined} + */ + decode(value) { + return (value && typeof value === 'string') ? { 'parrableid': value } : undefined; + }, + + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleParams} [configParams] + * @param {ConsentData} [consentData] + * @returns {function(callback:function)} + */ + getId(configParams, consentData, currentStoredId) { + return fetchId(configParams, consentData, currentStoredId); + } +}; + +submodule('userId', parrableIdSubmodule); diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 7776db714dd..872e0bb81d9 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -698,7 +698,7 @@ const OPEN_RTB_PROTOCOL = { } const bidUserId = utils.deepAccess(bidRequests, '0.bids.0.userId'); - if (bidUserId && typeof bidUserId === 'object' && (bidUserId.tdid || bidUserId.pubcid || bidUserId.lipb)) { + if (bidUserId && typeof bidUserId === 'object' && (bidUserId.tdid || bidUserId.pubcid || bidUserId.parrableid || bidUserId.lipb)) { utils.deepSetValue(request, 'user.ext.eids', []); if (bidUserId.tdid) { @@ -722,6 +722,15 @@ const OPEN_RTB_PROTOCOL = { }); } + if (bidUserId.parrableid) { + request.user.ext.eids.push({ + source: 'parrable.com', + uids: [{ + id: bidUserId.parrableid + }] + }); + } + if (bidUserId.lipb && bidUserId.lipb.lipbid) { request.user.ext.eids.push({ source: 'liveintent.com', diff --git a/modules/userId/index.js b/modules/userId/index.js index baeb1e2574c..ac96fd2cec8 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -371,6 +371,7 @@ function initSubmodules(submodules, consentData) { utils.logWarn(`${MODULE_NAME} - gdpr permission not valid for local storage or cookies, exit module`); return []; } + return submodules.reduce((carry, submodule) => { // There are two submodule configuration types to handle: storage or value // 1. storage: retrieve user id data from cookie/html storage or with the submodule's getId method diff --git a/modules/userId/userId.md b/modules/userId/userId.md index b5b8c216ead..9b363bbcf64 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -32,6 +32,17 @@ pbjs.setConfig({ name: "id5id", expires: 5, // Expiration of cookies in days refreshInSeconds: 8*3600 // User Id cache lifetime in seconds, defaulting to 'expires' + }, + }, { + name: 'parrableId', + params: { + // Replace the list contents with the Parrable Partner Client IDs for Parrable-aware bid adapters in use + partners: [ "30182847-e426-4ff9-b2b5-9ca1324ea09b" ] + }, + storage: { + type: 'cookie', + name: '_parrable_eid', + expires: 365 } }, { name: 'identityLink', diff --git a/test/spec/modules/parrableIdSystem_spec.js b/test/spec/modules/parrableIdSystem_spec.js new file mode 100644 index 00000000000..540e63aa630 --- /dev/null +++ b/test/spec/modules/parrableIdSystem_spec.js @@ -0,0 +1,77 @@ +import { expect } from 'chai'; +import {config} from 'src/config'; +import * as utils from 'src/utils'; +import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js'; +import { parrableIdSubmodule } from 'modules/parrableIdSystem'; + +const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; +const P_COOKIE_NAME = '_parrable_eid'; +const P_COOKIE_VALUE = '01.1563917337.test-eid'; +const P_CONFIG_MOCK = { + name: 'parrableId', + params: { + partner: 'parrable_test_partner_123,parrable_test_partner_456' + }, + storage: { + name: '_parrable_eid', + type: 'cookie', + expires: 364 + } +}; + +describe('Parrable ID System', function() { + function getConfigMock() { + return { + userSync: { + syncDelay: 0, + userIds: [P_CONFIG_MOCK] + } + } + } + function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: {banner: {}, native: {}}, + sizes: [ + [300, 200], + [300, 600] + ], + bids: [{ + bidder: 'sampleBidder', + params: { placementId: 'banner-only-bidder' } + }] + }; + } + + describe('Parrable ID in Bid Request', function() { + let adUnits; + + beforeEach(function() { + adUnits = [getAdUnitMock()]; + }); + + it('should append parrableid to bid request', function(done) { + // simulate existing browser local storage values + utils.setCookie( + P_COOKIE_NAME, + P_COOKIE_VALUE, + (new Date(Date.now() + 5000).toUTCString()) + ); + + setSubmoduleRegistry([parrableIdSubmodule]); + init(config); + config.setConfig(getConfigMock()); + + requestBidsHook(function() { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.parrableid'); + expect(bid.userId.parrableid).to.equal(P_COOKIE_VALUE); + }); + }); + utils.setCookie(P_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); + done(); + }, { adUnits }); + }); + }); +}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 1c10130a84e..658f130d144 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1044,6 +1044,7 @@ describe('S2S Adapter', function () { userIdBidRequest[0].bids[0].userId = { tdid: 'abc123', pubcid: '1234', + parrableid: '01.1563917337.test-eid', lipb: { lipbid: 'li-xyz' } @@ -1057,6 +1058,8 @@ describe('S2S Adapter', function () { expect(requestBid.user.ext.eids.filter(eid => eid.source === 'adserver.org')[0].uids[0].id).is.equal('abc123'); expect(requestBid.user.ext.eids.filter(eid => eid.source === 'pubcommon')).is.not.empty; expect(requestBid.user.ext.eids.filter(eid => eid.source === 'pubcommon')[0].uids[0].id).is.equal('1234'); + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'parrable.com')).is.not.empty; + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'parrable.com')[0].uids[0].id).is.equal('01.1563917337.test-eid'); expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveintent.com')).is.not.empty; expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveintent.com')[0].uids[0].id).is.equal('li-xyz'); }); From 29520f396781647a377d60b34b3d9effac465102 Mon Sep 17 00:00:00 2001 From: Bret Gorsline Date: Tue, 15 Oct 2019 16:58:50 -0400 Subject: [PATCH 28/38] Prebid 2.36.0 Release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca06ddb8b24..fbbf5ef66d3 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "2.36.0-pre", + "version": "2.36.0", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From f498ba8fbbf95bc0d26183a160dcf72fcaec1351 Mon Sep 17 00:00:00 2001 From: Bret Gorsline Date: Tue, 15 Oct 2019 17:11:39 -0400 Subject: [PATCH 29/38] Increment pre version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fbbf5ef66d3..0200db4eace 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "2.36.0", + "version": "2.37.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { From b363e97ed3e4aa2f3799a54d832c7b341392d863 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 15 Oct 2019 15:20:11 -0700 Subject: [PATCH 30/38] Support schain module and send bidfloor param in Sharethrough adapter (#4271) * Add support for supply chain object module Story: [#168742394](https://www.pivotaltracker.com/story/show/168742394) Co-authored-by: Josh Becker * Add bidfloor parameter to bid request sent to STX Story: [#168742573](https://www.pivotaltracker.com/story/show/168742573) --- modules/sharethroughBidAdapter.js | 8 ++++ .../modules/sharethroughBidAdapter_spec.js | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index 7fe41b2b7ae..117088f5355 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -41,6 +41,14 @@ export const sharethroughAdapterSpec = { query.ttduid = bidRequest.userId.tdid; } + if (bidRequest.schain) { + query.schain = JSON.stringify(bidRequest.schain); + } + + if (bidRequest.bidfloor) { + query.bidfloor = parseFloat(bidRequest.bidfloor); + } + // Data that does not need to go to the server, // but we need as part of interpretResponse() const strData = { diff --git a/test/spec/modules/sharethroughBidAdapter_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js index afa5f44959c..8a8ccdbbeb3 100644 --- a/test/spec/modules/sharethroughBidAdapter_spec.js +++ b/test/spec/modules/sharethroughBidAdapter_spec.js @@ -280,6 +280,44 @@ describe('sharethrough adapter spec', function () { } }); }); + + it('should add a supply chain parameter if schain is present', function() { + // shallow copy of the first bidRequest obj, so we don't mutate + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest['schain'] = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'directseller.com', + sid: '00001', + rid: 'BidRequest1', + hp: 1 + } + ] + }; + + const builtBidRequest = spec.buildRequests([bidRequest])[0]; + expect(builtBidRequest.data.schain).to.eq(JSON.stringify(bidRequest.schain)); + }); + + it('should not add a supply chain parameter if schain is missing', function() { + const bidRequest = spec.buildRequests(bidRequests)[0]; + expect(bidRequest.data).to.not.include.any.keys('schain'); + }); + + it('should include the bidfloor parameter if it is present in the bid request', function() { + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest['bidfloor'] = 0.50; + const builtBidRequest = spec.buildRequests([bidRequest])[0]; + expect(builtBidRequest.data.bidfloor).to.eq(0.5); + }); + + it('should not include the bidfloor parameter if it is missing in the bid request', function() { + const bidRequest = Object.assign({}, bidRequests[0]); + const builtBidRequest = spec.buildRequests([bidRequest])[0]; + expect(builtBidRequest.data).to.not.include.any.keys('bidfloor'); + }); }); describe('.interpretResponse', function () { From 493bd5e0d7d97b00b3908c3e47372e8f69410817 Mon Sep 17 00:00:00 2001 From: hbanalytics <55453525+hbanalytics@users.noreply.github.com> Date: Wed, 16 Oct 2019 01:30:50 +0300 Subject: [PATCH 31/38] Platform One Analytics Adapter (#4233) * Added Y1 Analytics Adapter * rename y1AnalyticsAdapter in yieldoneAnalyticsAdapter * Yieldone Bid Adapter: fixes from lint check * Yieldone Analytics Adapter: fix endpoint protocol * Added spec file for yieldone Analytics Adapter --- modules/yieldoneAnalyticsAdapter.js | 122 +++++++++ modules/yieldoneAnalyticsAdapter.md | 21 ++ .../modules/yieldoneAnalyticsAdapter_spec.js | 256 ++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 modules/yieldoneAnalyticsAdapter.js create mode 100644 modules/yieldoneAnalyticsAdapter.md create mode 100644 test/spec/modules/yieldoneAnalyticsAdapter_spec.js diff --git a/modules/yieldoneAnalyticsAdapter.js b/modules/yieldoneAnalyticsAdapter.js new file mode 100644 index 00000000000..94dd0daa0b2 --- /dev/null +++ b/modules/yieldoneAnalyticsAdapter.js @@ -0,0 +1,122 @@ +import {ajax} from '../src/ajax'; +import adapter from '../src/AnalyticsAdapter'; +import CONSTANTS from '../src/constants.json'; +import adapterManager from '../src/adapterManager'; +import { targeting } from '../src/targeting'; +import { auctionManager } from '../src/auctionManager'; +import * as utils from '../src/utils'; + +const ANALYTICS_CODE = 'yieldone'; +const analyticsType = 'endpoint'; +// const VERSION = '1.0.0'; +const defaultUrl = '//pool.tsukiji.iponweb.net/hba'; +const requestedBidders = {}; +const requestedBids = {}; +const referrers = {}; + +let currentAuctionId = ''; +let url = defaultUrl; +let pubId = ''; + +const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { + getUrl() { return url; }, + track({eventType, args = {}}) { + if (eventType === CONSTANTS.EVENTS.BID_REQUESTED) { + const reqBidderId = `${args.bidderCode}_${args.auctionId}`; + requestedBidders[reqBidderId] = utils.deepClone(args); + requestedBidders[reqBidderId].bids = []; + args.bids.forEach((bid) => { + requestedBids[`${bid.bidId}_${bid.auctionId}`] = bid; + }); + } + if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT && utils.isArray(args)) { + const eventsStorage = yieldoneAnalytics.eventsStorage; + const reqBidders = {}; + args.forEach((bid) => { + const reqBidId = `${bid.bidId}_${bid.auctionId}`; + const reqBidderId = `${bid.bidder}_${bid.auctionId}`; + if (!eventsStorage[bid.auctionId]) eventsStorage[bid.auctionId] = []; + if (requestedBidders[reqBidderId] && requestedBids[reqBidId]) { + if (!reqBidders[bid.bidder]) { + reqBidders[bid.bidder] = requestedBidders[reqBidderId]; + reqBidders[bid.bidder].pubId = pubId; + eventsStorage[bid.auctionId].push({eventType, params: reqBidders[bid.bidder]}); + delete requestedBidders[reqBidderId]; + } + reqBidders[bid.bidder].bids.push(requestedBids[reqBidId]); + delete requestedBids[reqBidId]; + } + }); + } else { + args.pubId = pubId; + currentAuctionId = args.auctionId || currentAuctionId; + if (currentAuctionId) { + const eventsStorage = yieldoneAnalytics.eventsStorage; + if (!eventsStorage[currentAuctionId]) eventsStorage[currentAuctionId] = []; + const referrer = args.refererInfo && args.refererInfo.referer; + if (referrer && referrers[currentAuctionId] !== referrer) { + referrers[currentAuctionId] = referrer; + } + eventsStorage[currentAuctionId].push({ + eventType, + params: args + }); + } + } + if ( + eventType === CONSTANTS.EVENTS.AUCTION_END || eventType === CONSTANTS.EVENTS.BID_WON + ) { + args.adServerTargeting = targeting.getAllTargeting( + auctionManager.getAdUnitCodes(), + auctionManager.getBidsReceived() + ); + if (yieldoneAnalytics.eventsStorage[args.auctionId]) { + yieldoneAnalytics.eventsStorage[args.auctionId].forEach((it) => { + it.page = {url: referrers[currentAuctionId]}; + }); + } + yieldoneAnalytics.sendStat(yieldoneAnalytics.eventsStorage[args.auctionId], args.auctionId); + } + }, + sendStat(events, auctionId) { + if (!events) return; + delete yieldoneAnalytics.eventsStorage[auctionId]; + ajax( + url, + { + success: function() {}, + error: function() {} + }, + JSON.stringify(events), + { + method: 'POST' + } + ); + } +}); + +yieldoneAnalytics.eventsStorage = {}; + +// save the base class function +yieldoneAnalytics.originEnableAnalytics = yieldoneAnalytics.enableAnalytics; + +// override enableAnalytics so we can get access to the config passed in from the page +yieldoneAnalytics.enableAnalytics = function (config) { + const options = config && config.options; + if (options) { + if (typeof options.url === 'string') { + url = options.url; + } + if (options.pubId) { + pubId = options.pubId.toString(); + } + } + yieldoneAnalytics.originEnableAnalytics(config); // call the base class function +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: yieldoneAnalytics, + code: ANALYTICS_CODE +}); + +export default yieldoneAnalytics; diff --git a/modules/yieldoneAnalyticsAdapter.md b/modules/yieldoneAnalyticsAdapter.md new file mode 100644 index 00000000000..43be87b114b --- /dev/null +++ b/modules/yieldoneAnalyticsAdapter.md @@ -0,0 +1,21 @@ +# Overview +Module Name: Platform One Analytics + +Module Type: Analytics Adapter + +Maintainer: y1s@platform-one.co.jp + +# Description + +Analytics adapter for Platform One. Please contact y1s@platform-one.co.jp for any additional information. Official website link to the vendor: www.platform-one.co.jp/. + +# Test Parameters + +``` +{ + provider: 'yieldone', + options : { + pubId : 'TestAnalyticsPublisher', //id provided by Platform One publisher team + } +} +``` \ No newline at end of file diff --git a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..a297403b2e0 --- /dev/null +++ b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js @@ -0,0 +1,256 @@ +import yieldoneAnalytics from 'modules/yieldoneAnalyticsAdapter'; +import { targeting } from 'src/targeting'; +import { expect } from 'chai'; +let events = require('src/events'); +let adapterManager = require('src/adapterManager').default; +let constants = require('src/constants.json'); + +describe('Yieldone Prebid Analytic', function () { + let sendStatStub; + let getAllTargetingStub; + const fakeTargeting = { + '0000': {'someId': 'someValue'} + }; + + describe('enableAnalytics', function () { + beforeEach(function () { + sendStatStub = sinon.stub(yieldoneAnalytics, 'sendStat'); + getAllTargetingStub = sinon.stub(targeting, 'getAllTargeting').returns(fakeTargeting); + sinon.stub(events, 'getEvents').returns([]); + }); + + afterEach(function () { + sendStatStub.restore(); + getAllTargetingStub.restore(); + events.getEvents.restore(); + }); + + after(function () { + yieldoneAnalytics.disableAnalytics(); + }); + + it('should catch all events', function (done) { + adapterManager.registerAnalyticsAdapter({ + code: 'yieldone', + adapter: yieldoneAnalytics + }); + + const initOptions = { + pubId: '123456' + }; + + const auctionId = 'test-test-test'; + const testReferrer = 'http://test'; + + const request = [ + { + bidderCode: 'biddertest_1', + auctionId: auctionId, + refererInfo: {referer: testReferrer}, + bids: [ + { + adUnitCode: '0000', + auctionId: auctionId, + bidId: '1234', + bidder: 'biddertest_1', + mediaTypes: {banner: {sizes: [[300, 250], [336, 280]]}}, + params: {param1: '111', param2: '222'}, + sizes: [[300, 250], [336, 280]] + }, + { + adUnitCode: '0000', + auctionId: auctionId, + bidId: '5678', + bidder: 'biddertest_1', + mediaTypes: {banner: {sizes: [[300, 250], [336, 280]]}}, + params: {param1: '222', param2: '222'}, + sizes: [[300, 250], [336, 280]] + } + ] + }, + { + bidderCode: 'biddertest_2', + auctionId: auctionId, + refererInfo: {referer: testReferrer}, + bids: [ + { + adUnitCode: '0000', + auctionId: auctionId, + bidId: '91011', + bidder: 'biddertest_2', + mediaTypes: {banner: {sizes: [[300, 250], [336, 280]]}}, + params: {paramA: '111', paramB: '222'}, + sizes: [[300, 250], [336, 280]] + } + ] + }, + { + bidderCode: 'biddertest_3', + auctionId: auctionId, + refererInfo: {referer: testReferrer}, + bids: [ + { + adUnitCode: '0000', + auctionId: auctionId, + bidId: '12131', + bidder: 'biddertest_3', + mediaTypes: {banner: {sizes: [[300, 250], [336, 280]]}}, + params: {param_1: '111', param_2: '222'}, + sizes: [[300, 250], [336, 280]] + } + ] + } + ]; + + const responses = [ + { + width: 300, + height: 250, + statusMessage: 'Bid available', + bidId: '1234', + auctionId: auctionId, + cpm: 0.1, + bidder: 'biddertest_1', + adUnitCode: '0000', + timeToRespond: 100 + }, + { + width: 336, + height: 280, + statusMessage: 'Bid available', + bidId: '5678', + auctionId: auctionId, + cpm: 0.2, + bidder: 'biddertest_1', + adUnitCode: '0000', + timeToRespond: 100 + }, + { + width: 300, + height: 250, + statusMessage: 'Bid available', + bidId: '91011', + auctionId: auctionId, + cpm: 0.3, + bidder: 'biddertest_2', + adUnitCode: '0000', + timeToRespond: 100 + }, + { + bidId: '12131', + auctionId: auctionId, + bidder: 'biddertest_3' + } + ]; + + const winner = { + width: 300, + height: 250, + statusMessage: 'Bid available', + bidId: '91011', + auctionId: auctionId, + cpm: 0.3, + bidder: 'biddertest_2', + adUnitCode: '0000', + timeToRespond: 100 + }; + + const expectedEvents = [ + { + eventType: constants.EVENTS.AUCTION_INIT, + page: {url: testReferrer}, + params: { + config: initOptions, + auctionId: auctionId, + pubId: initOptions.pubId + } + }, + { + eventType: constants.EVENTS.BID_REQUESTED, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, request[0]) + }, + { + eventType: constants.EVENTS.BID_REQUESTED, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, request[1]) + }, + { + eventType: constants.EVENTS.BID_REQUESTED, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, request[2]) + }, + { + eventType: constants.EVENTS.BID_RESPONSE, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, responses[0]) + }, + { + eventType: constants.EVENTS.BID_RESPONSE, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, responses[1]) + }, + { + eventType: constants.EVENTS.BID_RESPONSE, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, responses[2]) + }, + { + eventType: constants.EVENTS.BID_TIMEOUT, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId}, request[2]) + }, + { + eventType: constants.EVENTS.AUCTION_END, + page: {url: testReferrer}, + params: { + auctionId: auctionId, + pubId: initOptions.pubId, + adServerTargeting: fakeTargeting + } + } + ]; + + const wonExpectedEvents = [ + { + eventType: constants.EVENTS.BID_WON, + page: {url: testReferrer}, + params: Object.assign({pubId: initOptions.pubId, adServerTargeting: fakeTargeting}, winner) + } + ]; + + adapterManager.enableAnalytics({ + provider: 'yieldone', + options: initOptions + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {config: initOptions, auctionId: auctionId}); + + events.emit(constants.EVENTS.BID_REQUESTED, request[0]); + events.emit(constants.EVENTS.BID_REQUESTED, request[1]); + events.emit(constants.EVENTS.BID_REQUESTED, request[2]); + + events.emit(constants.EVENTS.BID_RESPONSE, responses[0]); + events.emit(constants.EVENTS.BID_RESPONSE, responses[1]); + events.emit(constants.EVENTS.BID_RESPONSE, responses[2]); + + events.emit(constants.EVENTS.BID_TIMEOUT, [responses[3]]); + + events.emit(constants.EVENTS.AUCTION_END, {auctionId: auctionId}); + + expect(yieldoneAnalytics.eventsStorage[auctionId]).to.deep.equal(expectedEvents); + + delete yieldoneAnalytics.eventsStorage[auctionId]; + + setTimeout(function() { + events.emit(constants.EVENTS.BID_WON, winner); + + sinon.assert.callCount(sendStatStub, 2); + expect(yieldoneAnalytics.eventsStorage[auctionId]).to.deep.equal(wonExpectedEvents); + + delete yieldoneAnalytics.eventsStorage[auctionId]; + done(); + }, 1000); + }); + }); +}); From 44192a8cdd0a92aac852c46bfe6ef0b9248be518 Mon Sep 17 00:00:00 2001 From: Eyas Ranjous Date: Wed, 16 Oct 2019 09:07:40 -0500 Subject: [PATCH 32/38] Fix parrable id integration example (#4317) * fix parrableId integration example * add parentheses --- modules/userId/userId.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/userId/userId.md b/modules/userId/userId.md index 9b363bbcf64..b10aa2adc20 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -36,8 +36,8 @@ pbjs.setConfig({ }, { name: 'parrableId', params: { - // Replace the list contents with the Parrable Partner Client IDs for Parrable-aware bid adapters in use - partners: [ "30182847-e426-4ff9-b2b5-9ca1324ea09b" ] + // Replace partner with comma-separated (if more than one) Parrable Partner Client ID(s) for Parrable-aware bid adapters in use + partner: "30182847-e426-4ff9-b2b5-9ca1324ea09b" }, storage: { type: 'cookie', From cb3c457b0d3c1bbbb397d7d21dd6a9658036a946 Mon Sep 17 00:00:00 2001 From: Jozef Bartek <31618107+jbartek25@users.noreply.github.com> Date: Wed, 16 Oct 2019 17:55:43 +0200 Subject: [PATCH 33/38] Improve Digital adapter: support for video (#4318) * Bid floor, https, native ad update * Update the ad server protocol module * Adding referrer * Improve Digital support for video * Improve Digital adapter: video * adapter version -> 6.0.0 --- modules/improvedigitalBidAdapter.js | 14 +++- .../modules/improvedigitalBidAdapter_spec.js | 82 +++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index 61074985597..4ee2226395b 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -1,15 +1,15 @@ import * as utils from '../src/utils'; import { registerBidder } from '../src/adapters/bidderFactory'; import { config } from '../src/config'; -import { BANNER, NATIVE } from '../src/mediaTypes'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; const BIDDER_CODE = 'improvedigital'; export const spec = { - version: '5.3.0', + version: '6.0.0', code: BIDDER_CODE, aliases: ['id'], - supportedMediaTypes: [BANNER, NATIVE], + supportedMediaTypes: [BANNER, NATIVE, VIDEO], /** * Determines whether or not the given bid request is valid. @@ -87,6 +87,9 @@ export const spec = { bid.native.impressionTrackers.unshift(bidObject.nurl); } bid.mediaType = NATIVE; + } else if (bidObject.ad_type && bidObject.ad_type === 'video') { + bid.vastXml = bidObject.adm; + bid.mediaType = VIDEO; } else { // Banner let nurl = ''; @@ -186,6 +189,11 @@ function getNormalizedBidRequest(bid) { const bidFloorCur = utils.getBidIdParameter('bidFloorCur', bid.params); let normalizedBidRequest = {}; + const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); + const context = utils.deepAccess(bid, 'mediaTypes.video.context'); + if (bid.mediaType === 'video' || (videoMediaType && context !== 'outstream')) { + normalizedBidRequest.adTypes = [ VIDEO ]; + } if (placementId) { normalizedBidRequest.placementId = placementId; } else { diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index 2bff6fba5bc..2d9d51c0d68 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -193,6 +193,38 @@ describe('Improve Digital Adapter Tests', function () { expect(params.bid_request.referrer).to.equal('https://blah.com/test.html'); }); + it('should add ad type for instream video', function () { + let bidRequest = Object.assign({}, simpleBidRequest); + bidRequest.mediaType = 'video'; + let request = spec.buildRequests([bidRequest])[0]; + let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']); + + bidRequest = Object.assign({}, simpleBidRequest); + bidRequest.mediaTypes = { + video: { + context: 'instream', + playerSize: [640, 480] + } + }; + request = spec.buildRequests([bidRequest])[0]; + params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']); + }); + + it('should not set ad type for outstream video', function() { + const bidRequest = Object.assign({}, simpleBidRequest); + bidRequest.mediaTypes = { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }; + const request = spec.buildRequests([bidRequest])[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].ad_types).to.not.exist; + }); + it('should add schain', function () { const schain = '{"ver":"1.0","complete":1,"nodes":[{"asi":"headerlift.com","sid":"xyz","hp":1}]}'; const bidRequest = Object.assign({}, simpleBidRequest); @@ -456,6 +488,34 @@ describe('Improve Digital Adapter Tests', function () { } }; + const serverResponseVideo = { + 'body': { + 'id': '687a06c541d8d1', + 'site_id': 191642, + 'bid': [ + { + 'isNet': false, + 'id': '33e9500b21129f', + 'advid': '5279', + 'price': 1.45888594164456, + 'nurl': 'http://ice.360yield.com/imp_pixel?ic=wVmhKI07hCVyGC1sNdFp.6buOSiGYOw8jPyZLlcMY2RCwD4ek3Fy6.xUI7U002skGBs3objMBoNU-Frpvmb9js3NKIG0YZJgWaNdcpXY9gOXE9hY4-wxybCjVSNzhOQB-zic73hzcnJnKeoGgcfvt8fMy18-yD0aVdYWt4zbqdoITOkKNCPBEgbPFu1rcje-o7a64yZ7H3dKvtnIixXQYc1Ep86xGSBGXY6xW2KfUOMT6vnkemxO72divMkMdhR8cAuqIubbx-ZID8-xf5c9k7p6DseeBW0I8ionrlTHx.rGosgxhiFaMqtr7HiA7PBzKvPdeEYN0hQ8RYo8JzYL82hA91A3V2m9Ij6y0DfIJnnrKN8YORffhxmJ6DzwEl1zjrVFbD01bqB3Vdww8w8PQJSkKQkd313tr-atU8LS26fnBmOngEkVHwAr2WCKxuUvxHmuVBTA-Lgz7wKwMoOJCA3hFxMavVb0ZFB7CK0BUTVU6z0De92Q.FJKNCHLMbjX3vcAQ90=', + 'h': 290, + 'pid': 1053688, + 'sync': [ + 'http://link1', + 'http://link2' + ], + 'crid': '422031', + 'w': 600, + 'cid': '99006', + 'adm': '', + 'ad_type': 'video' + } + ], + 'debug': '' + } + }; + const nativeEventtrackers = [ { event: 1, @@ -552,6 +612,22 @@ describe('Improve Digital Adapter Tests', function () { } ]; + let expectedBidVideo = [ + { + 'vastXml': '', + 'adId': '33e9500b21129f', + 'creativeId': '422031', + 'cpm': 1.45888594164456, + 'currency': 'USD', + 'height': 290, + 'mediaType': 'video', + 'netRevenue': false, + 'requestId': '33e9500b21129f', + 'ttl': 300, + 'width': 600 + } + ]; + it('should return a well-formed bid', function () { const bids = spec.interpretResponse(serverResponse); expect(bids).to.deep.equal(expectedBid); @@ -667,6 +743,12 @@ describe('Improve Digital Adapter Tests', function () { delete bids[0].ortbNative; expect(bids).to.deep.equal(expectedBids); }); + + // Video + it('should return a well-formed video bid', function () { + const bids = spec.interpretResponse(serverResponseVideo); + expect(bids).to.deep.equal(expectedBidVideo); + }); }); describe('getUserSyncs', function () { From fd865b1626ceebdaa5d6b4e346515c92317bc497 Mon Sep 17 00:00:00 2001 From: Salomon Rada Date: Wed, 16 Oct 2019 19:04:57 +0300 Subject: [PATCH 34/38] Gamoshi: Update aliases list. Add support for userSync. (#4319) * Add support for multi-format ad units. Add favoredMediaType property to params. * Add tests for gdpr consent. * Add adId to outbids * Modify media type resolving * Refactor multi-format ad units handler. * Modify the way of sending GDPR data. Update aliases. * Add new consent fields. Add unit test. * Add new consent fields. Add unit test. * Add support for id5 and unified id cookie sync. * Add support for id5 and unified id cookie sync. * Add restricted check for gdpr consent. --- modules/gamoshiBidAdapter.js | 58 ++++++++++++++++----- test/spec/modules/gamoshiBidAdapter_spec.js | 38 +++++++++++++- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/modules/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js index ec146b77c70..b18188cf33a 100644 --- a/modules/gamoshiBidAdapter.js +++ b/modules/gamoshiBidAdapter.js @@ -42,17 +42,16 @@ export const helper = { export const spec = { code: 'gamoshi', - aliases: ['gambid', 'cleanmedia', 'viewdeos', '9MediaOnline'], + aliases: ['gambid', 'cleanmedia', '9MediaOnline'], supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { - return !!bid.params.supplyPartnerId && - typeof bid.params.supplyPartnerId === 'string' && - (typeof bid.params['rtbEndpoint'] === 'undefined' || typeof bid.params['rtbEndpoint'] === 'string') && - (typeof bid.params.bidfloor === 'undefined' || typeof bid.params.bidfloor === 'number') && - (typeof bid.params['adpos'] === 'undefined' || typeof bid.params['adpos'] === 'number') && - (typeof bid.params['protocols'] === 'undefined' || Array.isArray(bid.params['protocols'])) && - (typeof bid.params.instl === 'undefined' || bid.params.instl === 0 || bid.params.instl === 1); + return !!bid.params.supplyPartnerId && utils.isStr(bid.params.supplyPartnerId) && + (!bid.params['rtbEndpoint'] || utils.isStr(bid.params['rtbEndpoint'])) && + (!bid.params.bidfloor || utils.isNumber(bid.params.bidfloor)) && + (!bid.params['adpos'] || utils.isNumber(bid.params['adpos'])) && + (!bid.params['protocols'] || Array.isArray(bid.params['protocols'])) && + (!bid.params.instl || bid.params.instl === 0 || bid.params.instl === 1); }, buildRequests: function (validBidRequests, bidderRequest) { @@ -75,16 +74,24 @@ export const spec = { 'imp': [], 'ext': {} }; + const gdprConsent = bidderRequest.gdprConsent; - if (bidderRequest.gdprConsent && - bidderRequest.gdprConsent.consentString && - bidderRequest.gdprConsent.gdprApplies) { + if (gdprConsent && gdprConsent.consentString && gdprConsent.gdprApplies) { rtbBidRequest.ext.gdpr_consent = { - consent_string: bidderRequest.gdprConsent.consentString, - consent_required: bidderRequest.gdprConsent.gdprApplies + consent_string: gdprConsent.consentString, + consent_required: gdprConsent.gdprApplies }; + rtbBidRequest.regs = { + ext: { + gdpr: gdprConsent.gdprApplies === true ? 1 : 0 + } + }; + rtbBidRequest.user = { + ext: { + consent: gdprConsent.consentString + } + } } - const imp = { 'id': transactionId, 'instl': params.instl === 1 ? 1 : 0, @@ -129,6 +136,15 @@ export const spec = { } } + let eids = []; + if (bidRequest && bidRequest.userId) { + addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 'ID5ID'); + addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 'TDID'); + } + if (eids.length > 0) { + rtbBidRequest.user.ext.eids = eids; + } + if (rtbBidRequest.imp.length === 0) { return; } @@ -243,4 +259,18 @@ function renderOutstream(bid) { }); } +function addExternalUserId(eids, value, source, rtiPartner) { + if (utils.isStr(value)) { + eids.push({ + source, + uids: [{ + id: value, + ext: { + rtiPartner + } + }] + }); + } +} + registerBidder(spec); diff --git a/test/spec/modules/gamoshiBidAdapter_spec.js b/test/spec/modules/gamoshiBidAdapter_spec.js index a2c4eebc213..2d63d47a73e 100644 --- a/test/spec/modules/gamoshiBidAdapter_spec.js +++ b/test/spec/modules/gamoshiBidAdapter_spec.js @@ -227,13 +227,49 @@ describe('GamoshiAdapter', function () { it('builds request with gdpr consent', function () { let response = spec.buildRequests([bidRequest], bidRequest)[0]; + expect(response.data.ext.gdpr_consent).to.exist; expect(response.data.ext).to.have.property('gdpr_consent'); expect(response.data.ext.gdpr_consent.consent_string).to.equal('some string'); expect(response.data.ext.gdpr_consent.consent_required).to.equal(true); + + expect(response.data.regs.ext.gdpr).to.exist; + expect(response.data.user.ext.consent).to.equal('some string'); + }); + + it('build request with ID5 Id', function () { + const bidRequestClone = utils.deepClone(bidRequest); + bidRequestClone.userId = {}; + bidRequestClone.userId.id5id = 'id5-user-id'; + let request = spec.buildRequests([bidRequestClone], bidRequestClone)[0]; + expect(request.data.user.ext.eids).to.deep.equal([{ + 'source': 'id5-sync.com', + 'uids': [{ + 'id': 'id5-user-id', + 'ext': { + 'rtiPartner': 'ID5ID' + } + }] + }]); + }); + + it('build request with unified Id', function () { + const bidRequestClone = utils.deepClone(bidRequest); + bidRequestClone.userId = {}; + bidRequestClone.userId.tdid = 'tdid-user-id'; + let request = spec.buildRequests([bidRequestClone], bidRequestClone)[0]; + expect(request.data.user.ext.eids).to.deep.equal([{ + 'source': 'adserver.org', + 'uids': [{ + 'id': 'tdid-user-id', + 'ext': { + 'rtiPartner': 'TDID' + } + }] + }]); }); }); - describe('interpretResponse', function () { + describe('interpretResponse', () => { const bannerBidRequest = { 'adUnitCode': 'adunit-code', 'auctionId': '1d1a030790a475', From 2da0604cfc8eacb716b6d560579f5660215f4d57 Mon Sep 17 00:00:00 2001 From: Ankit Prakash Date: Wed, 2 Oct 2019 16:56:28 -0600 Subject: [PATCH 35/38] schain and digitrust --- modules/sovrnBidAdapter.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 8b08b3ad6be..a7084ca7b5f 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -27,7 +27,11 @@ export const spec = { const loc = utils.getTopWindowLocation(); let sovrnImps = []; let iv; + let schain; utils._each(bidReqs, function (bid) { + if(bid.schain) { + schain = schain || bid.schain; + } iv = iv || utils.getBidIdParameter('iv', bid.params); bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]) bid.sizes = bid.sizes.filter(size => utils.isArray(size)) @@ -52,6 +56,14 @@ export const spec = { } }; + if(schain) { + sovrnBidReq.source = { + ext: { + schain + } + }; + } + if (bidderRequest && bidderRequest.gdprConsent) { sovrnBidReq.regs = { ext: { @@ -63,6 +75,16 @@ export const spec = { }}; } + const bidRequestDigitrust = utils.deepAccess(bidRequest, 'userId.digitrustid.data'); + if (bidRequestDigitrust && !bidRequestDigitrust.privacy.optout) { + sovrnBidReq.user = sovrnBidReq.user || {}; + sovrnBidReq.user.ext = sovrnBidReq.user.ext || {} + sovrnBidReq.user.ext.digitrust = { + id: bidRequestDigitrust.id, + keyv: bidRequestDigitrust.keyv + } + } + let url = `//ap.lijit.com/rtb/bid?` + `src=$$REPO_AND_VERSION$$`; if (iv) url += `&iv=${iv}`; From 38337c06d3241cfe39cb8f1539dfcbbb2ae9dbb7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 7 Oct 2019 14:09:44 -0600 Subject: [PATCH 36/38] pixel beacons --- modules/sovrnBidAdapter.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index a7084ca7b5f..dc240bfd0ce 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -139,8 +139,8 @@ export const spec = { try { let tracks = [] if (serverResponses && serverResponses.length !== 0 && syncOptions.iframeEnabled) { - let iidArr = serverResponses.filter(rsp => rsp.body && rsp.body.ext && rsp.body.ext.iid) - .map(rsp => { return rsp.body.ext.iid }); + let iidArr = serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.iid) + .map(resp => resp.body.ext.iid); let consentString = ''; if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { consentString = gdprConsent.consentString @@ -152,9 +152,17 @@ export const spec = { }); } } - if (errorpxls.length && syncOptions.pixelEnabled) { - tracks = tracks.concat(errorpxls) + if(syncOptions.pixelEnabled) { + if (serverResponses && serverResponses.length !== 0) { + serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.sync && resp.body.ext.sync.pixels) + .map(resp => resp.body.ext.sync.pixels.url) + .forEach(url => tracks.push({ type: 'image', url})) + } + if (errorpxls.length) { + tracks = tracks.concat(errorpxls) + } } + return tracks } catch (e) { if (syncOptions.pixelEnabled) { From 0dd6eb519a8ea7b3661ba1cf0a9614cf036cca98 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 8 Oct 2019 13:28:16 -0600 Subject: [PATCH 37/38] unit tests and fixes from testing --- modules/sovrnBidAdapter.js | 65 ++++++----- test/spec/modules/sovrnBidAdapter_spec.js | 128 ++++++++++++++++++---- 2 files changed, 143 insertions(+), 50 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index dc240bfd0ce..fed3958cf16 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -28,8 +28,19 @@ export const spec = { let sovrnImps = []; let iv; let schain; + let digitrust; + utils._each(bidReqs, function (bid) { - if(bid.schain) { + if (!digitrust) { + const bidRequestDigitrust = utils.deepAccess(bid, 'userId.digitrustid.data'); + if (bidRequestDigitrust && (!bidRequestDigitrust.privacy || !bidRequestDigitrust.privacy.optout)) { + digitrust = { + id: bidRequestDigitrust.id, + keyv: bidRequestDigitrust.keyv + } + } + } + if (bid.schain) { schain = schain || bid.schain; } iv = iv || utils.getBidIdParameter('iv', bid.params); @@ -56,7 +67,7 @@ export const spec = { } }; - if(schain) { + if (schain) { sovrnBidReq.source = { ext: { schain @@ -75,13 +86,12 @@ export const spec = { }}; } - const bidRequestDigitrust = utils.deepAccess(bidRequest, 'userId.digitrustid.data'); - if (bidRequestDigitrust && !bidRequestDigitrust.privacy.optout) { + if (digitrust) { sovrnBidReq.user = sovrnBidReq.user || {}; sovrnBidReq.user.ext = sovrnBidReq.user.ext || {} sovrnBidReq.user.ext.digitrust = { - id: bidRequestDigitrust.id, - keyv: bidRequestDigitrust.keyv + id: digitrust.id, + keyv: digitrust.keyv } } @@ -138,28 +148,31 @@ export const spec = { getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { try { let tracks = [] - if (serverResponses && serverResponses.length !== 0 && syncOptions.iframeEnabled) { - let iidArr = serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.iid) - .map(resp => resp.body.ext.iid); - let consentString = ''; - if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { - consentString = gdprConsent.consentString - } - if (iidArr[0]) { - tracks.push({ - type: 'iframe', - url: '//ap.lijit.com/beacon?informer=' + iidArr[0] + '&gdpr_consent=' + consentString, - }); + if (serverResponses && serverResponses.length !== 0) { + if (syncOptions.iframeEnabled) { + let iidArr = serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.iid) + .map(resp => resp.body.ext.iid); + let consentString = ''; + if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { + consentString = gdprConsent.consentString + } + if (iidArr[0]) { + tracks.push({ + type: 'iframe', + url: '//ap.lijit.com/beacon?informer=' + iidArr[0] + '&gdpr_consent=' + consentString, + }); + } } - } - if(syncOptions.pixelEnabled) { - if (serverResponses && serverResponses.length !== 0) { + + if (syncOptions.pixelEnabled) { serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.sync && resp.body.ext.sync.pixels) - .map(resp => resp.body.ext.sync.pixels.url) - .forEach(url => tracks.push({ type: 'image', url})) - } - if (errorpxls.length) { - tracks = tracks.concat(errorpxls) + .flatMap(resp => resp.body.ext.sync.pixels) + .map(pixel => pixel.url) + .forEach(url => tracks.push({ type: 'image', url })) + + if (errorpxls.length) { + tracks = tracks.concat(errorpxls) + } } } diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 7179ec00bc3..5f385008f54 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -1,7 +1,6 @@ -import { expect } from 'chai'; -import { spec, LogError } from 'modules/sovrnBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { SSL_OP_SINGLE_ECDH_USE } from 'constants'; +import {expect} from 'chai'; +import {LogError, spec} from 'modules/sovrnBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory'; const ENDPOINT = `//ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; @@ -128,13 +127,12 @@ describe('sovrnBidAdapter', function() { }; bidderRequest.bids = bidRequests; - const request = spec.buildRequests(bidRequests, bidderRequest); - const payload = JSON.parse(request.data); + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data); - expect(payload.regs.ext.gdpr).to.exist.and.to.be.a('number'); - expect(payload.regs.ext.gdpr).to.equal(1); - expect(payload.user.ext.consent).to.exist.and.to.be.a('string'); - expect(payload.user.ext.consent).to.equal(consentString); + expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.user.ext.consent).to.exist.and.to.be.a('string'); + expect(data.user.ext.consent).to.equal(consentString); }); it('converts tagid to string', function () { @@ -156,7 +154,68 @@ describe('sovrnBidAdapter', function() { const request = spec.buildRequests(ivBidRequests); expect(request.data).to.contain('"tagid":"403370"') - }) + }); + + it('should add schain if present', () => { + const schainRequests = [{ + 'bidder': 'sovrn', + 'params': { + 'tagid': 403370 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'directseller.com', + 'sid': '00001', + 'rid': 'BidRequest1', + 'hp': 1 + } + ] + } + }].concat(bidRequests); + const data = JSON.parse(spec.buildRequests(schainRequests).data); + + expect(data.source.ext.schain.nodes.length).to.equal(1) + }); + + it('should add digitrust data if present', () => { + const digitrustRequests = [{ + 'bidder': 'sovrn', + 'params': { + 'tagid': 403370 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'userId': { + 'digitrustid': { + 'data': { + 'id': 'digitrust-id-123', + 'keyv': 4 + } + } + } + }].concat(bidRequests); + const data = JSON.parse(spec.buildRequests(digitrustRequests).data); + + expect(data.user.ext.digitrust.id).to.equal('digitrust-id-123'); + expect(data.user.ext.digitrust.keyv).to.equal(4); + }); }); describe('interpretResponse', function () { @@ -254,8 +313,8 @@ describe('sovrnBidAdapter', function() { }); describe('getUserSyncs ', () => { - let syncOptions = {iframeEnabled: true, pixelEnabled: true}; - let iframeDisabledSyncOptions = {iframeEnabled: false, pixelEnabled: true}; + let syncOptions = { iframeEnabled: true, pixelEnabled: false }; + let iframeDisabledSyncOptions = { iframeEnabled: false, pixelEnabled: false }; let serverResponse = [ { 'body': { @@ -287,33 +346,54 @@ describe('sovrnBidAdapter', function() { } ], 'ext': { - 'iid': 13487408 + 'iid': 13487408, + sync: { + pixels: [ + { + url: 'http://idprovider1.com' + }, + { + url: 'http://idprovider2.com' + } + ] + } } }, 'headers': {} } ]; + it('should return if iid present on server response & iframe syncs enabled', () => { - let expectedReturnStatement = [ + const expectedReturnStatement = [ { 'type': 'iframe', 'url': '//ap.lijit.com/beacon?informer=13487408&gdpr_consent=', } - ] - let returnStatement = spec.getUserSyncs(syncOptions, serverResponse); + ]; + const returnStatement = spec.getUserSyncs(syncOptions, serverResponse); expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]); - }) + }); it('should not return if iid missing on server response', () => { - let returnStatement = spec.getUserSyncs(syncOptions, []) + const returnStatement = spec.getUserSyncs(syncOptions, []); expect(returnStatement).to.be.empty; - }) + }); it('should not return if iframe syncs disabled', () => { - let returnStatement = spec.getUserSyncs(iframeDisabledSyncOptions, serverResponse) - expect(returnStatement).to.be.empty - }) - }) + const returnStatement = spec.getUserSyncs(iframeDisabledSyncOptions, serverResponse); + expect(returnStatement).to.be.empty; + }); + + it('should include pixel syncs', () => { + let pixelEnabledOptions = { iframeEnabled: false, pixelEnabled: true }; + const returnStatement = spec.getUserSyncs(pixelEnabledOptions, serverResponse); + console.log(returnStatement) + expect(returnStatement.length).to.equal(2); + expect(returnStatement).to.deep.include.members([{ type: 'image', url: 'http://idprovider1.com' }, + { type: 'image', url: 'http://idprovider2.com' }]); + }); + }); + describe('LogError', () => { it('should build and append an error object', () => { const thrown = { From 1bbab9e28083f1f10e134d2c49678f8baab63750 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 16 Oct 2019 14:17:00 -0600 Subject: [PATCH 38/38] Prebid 3.0 updates --- modules/sovrnBidAdapter.js | 73 +++------- test/spec/modules/sovrnBidAdapter_spec.js | 162 ++++++++++------------ 2 files changed, 95 insertions(+), 140 deletions(-) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index fed3958cf16..b953f3bc19f 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -1,8 +1,6 @@ import * as utils from '../src/utils' import { registerBidder } from '../src/adapters/bidderFactory' import { BANNER } from '../src/mediaTypes' -const errorUrl = 'https://pcb.aws.lijit.com/c' -let errorpxls = [] export const spec = { code: 'sovrn', @@ -24,7 +22,6 @@ export const spec = { */ buildRequests: function(bidReqs, bidderRequest) { try { - const loc = utils.getTopWindowLocation(); let sovrnImps = []; let iv; let schain; @@ -44,9 +41,11 @@ export const spec = { schain = schain || bid.schain; } iv = iv || utils.getBidIdParameter('iv', bid.params); - bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]) - bid.sizes = bid.sizes.filter(size => utils.isArray(size)) - const processedSizes = bid.sizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})) + + let bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes; + bidSizes = ((utils.isArray(bidSizes) && utils.isArray(bidSizes[0])) ? bidSizes : [bidSizes]) + bidSizes = bidSizes.filter(size => utils.isArray(size)) + const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})) sovrnImps.push({ id: bid.bidId, banner: { @@ -58,12 +57,19 @@ export const spec = { bidfloor: utils.getBidIdParameter('bidfloor', bid.params) }); }); + + const page = bidderRequest.refererInfo.referer + // clever trick to get the domain + const el = document.createElement('a'); + el.href = page; + const domain = el.hostname; + const sovrnBidReq = { id: utils.getUniqueIdentifierStr(), imp: sovrnImps, site: { - domain: loc.host, - page: loc.host + loc.pathname + loc.search + loc.hash + page, + domain } }; @@ -95,7 +101,7 @@ export const spec = { } } - let url = `//ap.lijit.com/rtb/bid?` + + let url = `https://ap.lijit.com/rtb/bid?` + `src=$$REPO_AND_VERSION$$`; if (iv) url += `&iv=${iv}`; @@ -106,7 +112,8 @@ export const spec = { options: {contentType: 'text/plain'} } } catch (e) { - new LogError(e, {bidReqs, bidderRequest}).append() + console.log('error in build:') + console.log(e) } }, @@ -141,7 +148,8 @@ export const spec = { } return sovrnBidResponses } catch (e) { - new LogError(e, {id, seatbid}).append() + console.log('error in interpret:') + console.log(e) } }, @@ -169,57 +177,14 @@ export const spec = { .flatMap(resp => resp.body.ext.sync.pixels) .map(pixel => pixel.url) .forEach(url => tracks.push({ type: 'image', url })) - - if (errorpxls.length) { - tracks = tracks.concat(errorpxls) - } } } return tracks } catch (e) { - if (syncOptions.pixelEnabled) { - return errorpxls - } return [] } }, } -export class LogError { - constructor(e, data) { - utils.logError(e) - this.error = {} - this.error.t = utils.timestamp() - this.error.m = e.message - this.error.s = e.stack - this.error.d = data - this.error.v = $$REPO_AND_VERSION$$ - this.error.u = utils.getTopWindowLocation().href - this.error.ua = navigator.userAgent - } - buildErrorString(obj) { - return errorUrl + '?b=' + btoa(JSON.stringify(obj)) - } - append() { - let errstr = this.buildErrorString(this.error) - if (errstr.length > 2083) { - delete this.error.d - errstr = this.buildErrorString(this.error) - if (errstr.length > 2083) { - delete this.error.s - errstr = this.buildErrorString(this.error) - if (errstr.length > 2083) { - errstr = this.buildErrorString({m: 'unknown error message', t: this.error.t, u: this.error.u}) - } - } - } - let obj = {type: 'image', url: errstr} - errorpxls.push(obj) - } - static getErrPxls() { - return errorpxls - } -} - registerBidder(spec); diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 5f385008f54..af27e6e74a6 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -2,7 +2,7 @@ import {expect} from 'chai'; import {LogError, spec} from 'modules/sovrnBidAdapter'; import {newBidder} from 'src/adapters/bidderFactory'; -const ENDPOINT = `//ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; +const ENDPOINT = `https://ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; describe('sovrnBidAdapter', function() { const adapter = newBidder(spec); @@ -54,8 +54,12 @@ describe('sovrnBidAdapter', function() { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }]; - - const request = spec.buildRequests(bidRequests); + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); it('sends bid request to our endpoint via POST', function () { expect(request.method).to.equal('POST'); @@ -72,7 +76,7 @@ describe('sovrnBidAdapter', function() { expect(payload.imp[0].banner.h).to.equal(1) }) - it('accepts a single array as a size', function() { + it('accepts a single array as a size', () => { const singleSize = [{ 'bidder': 'sovrn', 'params': { @@ -84,8 +88,13 @@ describe('sovrnBidAdapter', function() { 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' - }]; - const request = spec.buildRequests(singleSize) + }] + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + } + const request = spec.buildRequests(singleSize, bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]) expect(payload.imp[0].banner.w).to.equal(1) @@ -108,7 +117,12 @@ describe('sovrnBidAdapter', function() { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }]; - const request = spec.buildRequests(ivBidRequests); + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + const request = spec.buildRequests(ivBidRequests, bidderRequest); expect(request.url).to.contain('iv=vet') }); @@ -120,9 +134,12 @@ describe('sovrnBidAdapter', function() { 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, - 'gdprConsent': { + gdprConsent: { consentString: consentString, gdprApplies: true + }, + refererInfo: { + referer: 'http://example.com/page.html', } }; bidderRequest.bids = bidRequests; @@ -151,7 +168,12 @@ describe('sovrnBidAdapter', function() { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }]; - const request = spec.buildRequests(ivBidRequests); + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + const request = spec.buildRequests(ivBidRequests, bidderRequest); expect(request.data).to.contain('"tagid":"403370"') }); @@ -183,7 +205,12 @@ describe('sovrnBidAdapter', function() { ] } }].concat(bidRequests); - const data = JSON.parse(spec.buildRequests(schainRequests).data); + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + const data = JSON.parse(spec.buildRequests(schainRequests, bidderRequest).data); expect(data.source.ext.schain.nodes.length).to.equal(1) }); @@ -211,7 +238,12 @@ describe('sovrnBidAdapter', function() { } } }].concat(bidRequests); - const data = JSON.parse(spec.buildRequests(digitrustRequests).data); + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + const data = JSON.parse(spec.buildRequests(digitrustRequests, bidderRequest).data); expect(data.user.ext.digitrust.id).to.equal('digitrust-id-123'); expect(data.user.ext.digitrust.keyv).to.equal(4); @@ -394,84 +426,42 @@ describe('sovrnBidAdapter', function() { }); }); - describe('LogError', () => { - it('should build and append an error object', () => { - const thrown = { - message: 'message', - stack: 'stack' - } - const data = {name: 'Oscar Hathenswiotch'} - const err = new LogError(thrown, data) - err.append() - const errList = LogError.getErrPxls() - expect(errList.length).to.equal(1) - const errdata = JSON.parse(atob(errList[0].url.split('=')[1])) - expect(errdata.d.name).to.equal('Oscar Hathenswiotch') - }) - it('should drop data when there is too much', () => { - const thrown = { - message: 'message', - stack: 'stack' - } - const tooLong = () => { - let str = '' - for (let i = 0; i < 10000; i++) { - str = str + String.fromCharCode(i % 100) - } - return str - } - const data = {name: 'Oscar Hathenswiotch', tooLong: tooLong()} - const err = new LogError(thrown, data) - err.append() - const errList = LogError.getErrPxls() - expect(errList.length).to.equal(2) - const errdata = JSON.parse(atob(errList[1].url.split('=')[1])) - expect(errdata.d).to.be.an('undefined') - }) - it('should drop data and stack when there is too much', () => { - const thrown = { - message: 'message', - stack: 'stack' - } - const tooLong = () => { - let str = '' - for (let i = 0; i < 10000; i++) { - str = str + String.fromCharCode(i % 100) + describe('prebid 3 upgrade', () => { + const bidRequests = [{ + 'bidder': 'sovrn', + 'params': { + 'tagid': '403370' + }, + 'adUnitCode': 'adunit-code', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600] + ] } - return str + }, + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }]; + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', } - const data = {name: 'Oscar Hathenswiotch'} - thrown.stack = tooLong() - const err = new LogError(thrown, data) - err.append() - const errList = LogError.getErrPxls() - expect(errList.length).to.equal(3) - const errdata = JSON.parse(atob(errList[2].url.split('=')[1])) - expect(errdata.d).to.be.an('undefined') - expect(errdata.s).to.be.an('undefined') + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + it('gets sizes from mediaTypes.banner', () => { + expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]) + expect(payload.imp[0].banner.w).to.equal(1) + expect(payload.imp[0].banner.h).to.equal(1) }) - it('should drop send a reduced message when other reduction methods fail', () => { - const thrown = { - message: 'message', - stack: 'stack' - } - const tooLong = () => { - let str = '' - for (let i = 0; i < 10000; i++) { - str = str + String.fromCharCode(i % 100) - } - return str - } - const data = {name: 'Oscar Hathenswiotch'} - thrown.message = tooLong() - const err = new LogError(thrown, data) - err.append() - const errList = LogError.getErrPxls() - expect(errList.length).to.equal(4) - const errdata = JSON.parse(atob(errList[3].url.split('=')[1])) - expect(errdata.d).to.be.an('undefined') - expect(errdata.s).to.be.an('undefined') - expect(errdata.m).to.equal('unknown error message') + + it('gets correct site info', () => { + expect(payload.site.page).to.equal('http://example.com/page.html'); + expect(payload.site.domain).to.equal('example.com'); }) }) })