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 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/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}">
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: { @@ -43,15 +57,30 @@ 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 } }; + if (schain) { + sovrnBidReq.source = { + ext: { + schain + } + }; + } + if (bidderRequest && bidderRequest.gdprConsent) { sovrnBidReq.regs = { ext: { @@ -63,7 +92,16 @@ export const spec = { }}; } - let url = `//ap.lijit.com/rtb/bid?` + + if (digitrust) { + sovrnBidReq.user = sovrnBidReq.user || {}; + sovrnBidReq.user.ext = sovrnBidReq.user.ext || {} + sovrnBidReq.user.ext.digitrust = { + id: digitrust.id, + keyv: digitrust.keyv + } + } + + let url = `https://ap.lijit.com/rtb/bid?` + `src=$$REPO_AND_VERSION$$`; if (iv) url += `&iv=${iv}`; @@ -74,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) } }, @@ -109,74 +148,43 @@ export const spec = { } return sovrnBidResponses } catch (e) { - new LogError(e, {id, seatbid}).append() + console.log('error in interpret:') + console.log(e) } }, getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { 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 consentString = ''; - if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { - consentString = gdprConsent.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 (iidArr[0]) { - tracks.push({ - type: 'iframe', - url: '//ap.lijit.com/beacon?informer=' + iidArr[0] + '&gdpr_consent=' + consentString, - }); + + if (syncOptions.pixelEnabled) { + serverResponses.filter(resp => resp.body && resp.body.ext && resp.body.ext.sync && resp.body.ext.sync.pixels) + .flatMap(resp => resp.body.ext.sync.pixels) + .map(pixel => pixel.url) + .forEach(url => tracks.push({ type: 'image', url })) } } - if (errorpxls.length && syncOptions.pixelEnabled) { - 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/modules/spotxBidAdapter.js b/modules/spotxBidAdapter.js index 6e374b991d3..45a3c925221 100644 --- a/modules/spotxBidAdapter.js +++ b/modules/spotxBidAdapter.js @@ -6,6 +6,7 @@ import { VIDEO } from '../src/mediaTypes'; const BIDDER_CODE = 'spotx'; const URL = '//search.spotxchange.com/openrtb/2.3/dados/'; const ORTB_VERSION = '2.3'; +export const GOOGLE_CONSENT = { consented_providers: ['3', '7', '11', '12', '15', '20', '22', '35', '43', '46', '48', '55', '57', '61', '62', '66', '70', '80', '83', '85', '86', '89', '93', '108', '122', '124', '125', '126', '131', '134', '135', '136', '143', '144', '147', '149', '153', '154', '159', '161', '162', '165', '167', '171', '178', '184', '188', '192', '195', '196', '202', '209', '211', '218', '221', '228', '229', '230', '236', '239', '241', '253', '255', '259', '266', '271', '272', '274', '286', '291', '294', '303', '308', '310', '311', '313', '314', '316', '317', '322', '323', '327', '336', '338', '340', '348', '350', '358', '359', '363', '367', '370', '371', '384', '385', '389', '393', '394', '397', '398', '407', '414', '415', '424', '429', '430', '432', '436', '438', '440', '442', '443', '445', '448', '449', '453', '459', '479', '482', '486', '491', '492', '494', '495', '503', '505', '510', '522', '523', '528', '537', '540', '550', '559', '560', '568', '571', '574', '575', '576', '584', '585', '587', '588', '590', '591', '592', '595', '609', '621', '624', '723', '725', '733', '737', '776', '780', '782', '787', '797', '798', '802', '803', '814', '817', '820', '821', '827', '829', '839', '853', '864', '867', '874', '899', '904', '922', '926', '931', '932', '933', '938', '955', '973', '976', '979', '981', '985', '987', '991', '1003', '1024', '1025', '1027', '1028', '1029', '1033', '1034', '1040', '1047', '1048', '1051', '1052', '1053', '1054', '1062', '1063', '1067', '1072', '1085', '1092', '1095', '1097', '1099', '1100', '1107', '1126', '1127', '1143', '1149', '1152', '1162', '1166', '1167', '1170', '1171', '1172', '1188', '1192', '1199', '1201', '1204', '1205', '1211', '1212', '1215', '1220', '1225', '1226', '1227', '1230', '1232', '1236', '1241', '1248', '1250', '1252', '1268', '1275', '1276', '1284', '1286', '1298', '1301', '1307', '1312', '1313', '1317', '1329', '1336', '1344', '1345', '1356', '1362', '1365', '1375', '1403', '1409', '1411', '1415', '1416', '1419', '1423', '1440', '1442', '1449', '1451', '1455', '1456', '1468', '1496', '1503', '1509', '1512', '1514', '1517', '1520', '1525', '1540', '1547', '1548', '1555', '1558', '1570', '1575', '1577', '1579', '1583', '1584', '1591', '1598', '1603', '1608', '1613', '1616', '1626', '1631', '1633', '1638', '1642', '1648', '1651', '1652', '1653', '1660', '1665', '1667', '1669', '1671', '1674', '1677', '1678', '1682', '1684', '1697', '1703', '1705', '1716', '1720', '1721', '1722', '1725', '1732', '1733', '1735', '1739', '1741', '1745', '1750', '1753', '1760', '1765', '1769', '1776', '1780', '1782', '1786', '1791', '1794', '1799', '1800', '1801', '1810', '1827', '1831', '1832', '1834', '1837', '1840', '1843', '1844', '1845', '1858', '1859', '1863', '1866', '1870', '1872', '1875', '1878', '1880', '1882', '1883', '1889', '1892', '1896', '1898', '1899', '1902', '1905', '1911', '1922', '1928', '1929', '1934', '1942', '1943', '1944', '1945', '1958', '1960', '1962', '1963', '1964', '1967', '1968', '1978', '1985', '1986', '1987', '1998', '2003', '2007', '2012', '2013', '2027', '2035', '2038', '2039', '2044', '2047', '2052', '2056', '2059', '2062', '2064', '2068', '2070', '2072', '2078', '2079', '2084', '2088', '2090', '2095', '2100', '2103', '2107', '2109', '2113', '2115', '2121', '2127', '2130', '2133', '2137', '2140', '2141', '2145', '2147', '2150', '2156', '2166', '2170', '2171', '2176', '2177', '2179', '2183', '2186', '2192', '2198', '2202', '2205', '2214', '2216', '2219', '2220', '2222', '2223', '2224', '2225', '2227', '2228', '2234', '2238', '2247', '2251', '2253', '2262', '2264', '2271', '2276', '2278', '2279', '2282', '2290', '2292', '2295', '2299', '2305', '2306', '2310', '2311', '2312', '2315', '2320', '2325', '2328', '2331', '2334', '2335', '2336', '2337', '2343', '2346', '2354', '2357', '2358', '2359', '2366', '2370', '2373', '2376', '2377', '2380', '2382', '2387', '2389', '2392', '2394', '2400', '2403', '2405', '2406', '2407', '2410', '2411', '2413', '2414', '2415', '2416', '2418', '2422', '2425', '2427', '2435', '2437', '2440', '2441', '2447', '2453', '2459', '2461', '2462', '2464', '2467', '2468', '2472', '2477', '2481', '2484', '2486', '2492', '2493', '2496', '2497', '2498', '2499', '2504', '2506', '2510', '2511', '2512', '2517', '2526', '2527', '2531', '2532', '2534', '2542', '2544', '2552', '2555', '2559', '2563', '2564', '2567', '2568', '2569', '2571', '2572', '2573', '2575', '2577', '2579', '2583', '2584', '2586', '2589', '2595', '2596', '2597', '2601', '2604', '2605', '2609', '2610', '2612', '2614', '2621', '2622', '2624', '2628', '2629', '2632', '2634', '2636', '2639', '2643', '2645', '2646', '2647', '2649', '2650', '2651', '2652', '2656', '2657', '2658', '2660', '2661', '2662', '2663', '2664', '2669', '2670', '2673', '2676', '2677', '2678', '2681', '2682', '2684', '2685', '2686', '2689', '2690', '2691', '2695', '2698', '2699', '2702', '2704', '2705', '2706', '2707', '2709', '2710', '2713', '2714', '2727', '2729', '2739', '2758', '2765', '2766', '2767', '2768', '2770', '2771', '2772', '2776', '2777', '2778', '2779', '2780', '2783', '2784', '2786', '2787', '2791', '2792', '2793', '2797', '2798', '2801', '2802', '2803', '2805', '2808', '2809', '2810', '2811', '2812', '2813', '2814', '2817', '2818', '2824', '2826', '2827', '2829', '2830', '2831', '2832', '2834', '2836', '2838', '2840', '2842', '2843', '2844', '2850', '2851', '2852', '2854', '2858', '2860', '2862', '2864', '2865', '2866', '2867', '2868', '2869', '2871'] }; export const spec = { code: BIDDER_CODE, @@ -192,6 +193,10 @@ export const spec = { const userExt = {}; + if (utils.getBidIdParameter('spotx_all_google_consent', bid.params) == 1) { + userExt['consented_providers_settings'] = GOOGLE_CONSENT; + } + // Add GDPR flag and consent string if (bidderRequest && bidderRequest.gdprConsent) { userExt.consent = bidderRequest.gdprConsent.consentString; @@ -205,11 +210,30 @@ export const spec = { } } + // ID5 fied + if (bid && bid.userId && bid.userId.id5id) { + userExt.eids = [{ + source: 'id5-sync.com', + uids: [{ + id: bid.userId.id5id + }] + }]; + } + // Add common id if available if (pubcid) { userExt.fpc = pubcid; } + // Add schain object if it is present + if (bid && bid.schain) { + requestPayload['ext']['source'] = { + ext: { + schain: bid.schain + } + }; + } + // Only add the user object if it's not empty if (!utils.isEmpty(userExt)) { requestPayload.user = { ext: userExt }; diff --git a/modules/spotxBidAdapter.md b/modules/spotxBidAdapter.md index 038c698a259..0bd1cf71aa1 100644 --- a/modules/spotxBidAdapter.md +++ b/modules/spotxBidAdapter.md @@ -63,7 +63,8 @@ This adapter requires setup and approval from the SpotX team. continue_out_of_view: '1', ad_volume: '100', content_container_id: 'video1', - hide_skin: '1' + hide_skin: '1', + spotx_all_google_consent: '1' } } } @@ -121,7 +122,6 @@ function myOutstreamFunction(bid) { script.setAttribute('data-spotx_click_to_replay', '1'); script.setAttribute('data-spotx_continue_out_of_view', '1'); script.setAttribute('data-spotx_ad_volume', '100'); - script.setAttribute('data-spotx_hide_skin', '1'); if (bid.renderer.config.inIframe && window.document.getElementById(bid.renderer.config.inIframe).nodeName == 'IFRAME') { let rawframe = window.document.getElementById(bid.renderer.config.inIframe); let framedoc = rawframe.contentDocument; diff --git a/modules/userId/index.js b/modules/userId/index.js index 8302a7a89e3..ac96fd2cec8 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -71,6 +71,8 @@ * @property {(boolean|undefined)} create - create id if missing. default is true. * @property {(boolean|undefined)} extend - extend expiration time on each access. default is false. * @property {(string|undefined)} pid - placement id url param value + * @property {(string|undefined)} publisherId - the unique identifier of the publisher in question + * @property {(array|undefined)} identifiersToResolve - the identifiers from either ls|cookie to be attached to the getId query */ /** @@ -369,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 9f71d59e5e1..b10aa2adc20 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 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', + name: '_parrable_eid', + expires: 365 } }, { name: 'identityLink', @@ -43,6 +54,16 @@ pbjs.setConfig({ name: 'idl_env', expires: 30 } + }, { + name: 'liveIntentId', + params: { + publisherId: '7798696' // Set an identifier of a publisher know to your systems + }, + storage: { + type: 'cookie', + name: '_li_pbid', + expires: 60 + } }], syncDelay: 5000, auctionDelay: 1000 @@ -82,6 +103,16 @@ pbjs.setConfig({ name: 'idl_env', expires: 30 } + }, { + name: 'liveIntentId', + params: { + publisherId: '7798696' // Set an identifier of a publisher know to your systems + }, + storage: { + type: 'html5', + name: '_li_pbid', + expires: 60 + } }], syncDelay: 5000 } diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 693d6f9724d..b4c2934ee63 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -29,7 +29,7 @@ function buildRequest(bid, topWindowUrl, size, bidderRequest) { method: 'GET', url: `${URL}/prebid/${cId}`, data: { - url: topWindowUrl, + url: encodeURIComponent(topWindowUrl), cb: Date.now(), bidFloor: bidFloor, bidId: bidId, @@ -38,7 +38,7 @@ function buildRequest(bid, topWindowUrl, size, bidderRequest) { width, height } - } + }; utils._each(ext, (value, key) => { dto.data['ext.' + key] = value; @@ -48,7 +48,7 @@ function buildRequest(bid, topWindowUrl, size, bidderRequest) { } function buildRequests(validBidRequests, bidderRequest) { - const topWindowUrl = utils.getTopWindowUrl(); + const topWindowUrl = bidderRequest.refererInfo.referer; const requests = []; validBidRequests.forEach(validBidRequest => { const sizes = utils.parseSizesInput(validBidRequest.sizes); 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/package.json b/package.json index 967dcede83c..0200db4eace 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "2.35.0-pre", + "version": "2.37.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { 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); diff --git a/src/videoCache.js b/src/videoCache.js index 06847012a6e..4a715cb1fe3 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -60,12 +60,18 @@ function wrapURI(uri, impUrl) { */ function toStorageRequest(bid) { const vastValue = bid.vastXml ? bid.vastXml : wrapURI(bid.vastUrl, bid.vastImpUrl); + let payload = { type: 'xml', value: vastValue, ttlseconds: Number(bid.ttl) }; + if (config.getConfig('cache.vasttrack')) { + payload.bidder = bid.bidder; + payload.bidid = bid.requestId; + } + if (typeof bid.customCacheKey === 'string' && bid.customCacheKey !== '') { payload.key = bid.customCacheKey; } @@ -94,7 +100,7 @@ function toStorageRequest(bid) { */ function shimStorageCallback(done) { return { - success: function(responseBody) { + success: function (responseBody) { let ids; try { ids = JSON.parse(responseBody).responses @@ -109,7 +115,7 @@ function shimStorageCallback(done) { done(new Error("The cache server didn't respond with a responses property."), []); } }, - error: function(statusText, responseBody) { + error: function (statusText, responseBody) { done(new Error(`Error storing video ad in the cache: ${statusText}: ${JSON.stringify(responseBody)}`), []); } } diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index 08ea0a863ee..e98b4600d90 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -61,6 +61,7 @@ describe('33acrossBidAdapter:', function () { }, ext: { ttx: { + prebidStartedAt: 1, caller: [{ 'name': 'prebidjs', 'version': '$prebid.version$' @@ -183,6 +184,7 @@ describe('33acrossBidAdapter:', function () { ]; sandbox = sinon.sandbox.create(); + sandbox.stub(Date, 'now').returns(1); sandbox.stub(document, 'getElementById').withArgs('div-id').returns(element); sandbox.stub(utils, 'getWindowTop').returns(win); sandbox.stub(utils, 'getWindowSelf').returns(win); diff --git a/test/spec/modules/adponeBidAdapter_spec.js b/test/spec/modules/adponeBidAdapter_spec.js index 1c64c60bd5c..da685a56394 100644 --- a/test/spec/modules/adponeBidAdapter_spec.js +++ b/test/spec/modules/adponeBidAdapter_spec.js @@ -1,6 +1,8 @@ import { expect } from 'chai'; import { spec } from 'modules/adponeBidAdapter'; +import {newBidder} from '../../../src/adapters/bidderFactory'; +const EMPTY_ARRAY = []; describe('adponeBidAdapter', function () { let bid = { bidder: 'adpone', @@ -14,6 +16,48 @@ describe('adponeBidAdapter', function () { } }; + describe('build requests', () => { + it('sends bid request to ENDPOINT via POST', function () { + const request = spec.buildRequests([ + { + bidder: 'adpone', + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + params: { + placementId: '1', + } + } + ]); + expect(request[0].method).to.equal('POST'); + }); + it('sends bid request to adpone endpoint', function () { + const request = spec.buildRequests([ + { + bidder: 'adpone', + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + params: { + placementId: '1', + } + } + ]); + expect(request[0].url).to.equal('https://rtb.adpone.com/bid-request?pid=1'); + }); + }); + + describe('inherited functions', () => { + const adapter = newBidder(spec); + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + describe('isBidRequestValid', function () { it('should return true when necessary information is found', function () { expect(spec.isBidRequestValid(bid)).to.be.true; @@ -34,6 +78,36 @@ describe('adponeBidAdapter', function () { bid.adUnitCode = 'adunit-code'; }); + + it('returns false when bidder not set to "adpone"', function() { + const invalidBid = { + bidder: 'enopda', + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + params: { + placementId: '1', + } + }; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + + it('returns false when placementId is not set in params', function() { + const invalidBid = { + bidder: 'adpone', + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + params: { + } + }; + + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); }); }); @@ -73,6 +147,19 @@ describe('interpretResponse', function () { }; }); + it('validate_response_params', function() { + const newResponse = spec.interpretResponse(serverResponse, bidRequest); + expect(newResponse[0].id).to.be.equal('613673EF-A07C-4486-8EE9-3FC71A7DC73D'); + expect(newResponse[0].requestId).to.be.equal('1234'); + expect(newResponse[0].cpm).to.be.equal(1); + expect(newResponse[0].width).to.be.equal(300); + expect(newResponse[0].height).to.be.equal(250); + expect(newResponse[0].currency).to.be.equal('USD'); + expect(newResponse[0].netRevenue).to.be.equal(true); + expect(newResponse[0].ttl).to.be.equal(300); + expect(newResponse[0].ad).to.be.equal(''); + }); + it('should correctly reorder the server response', function () { const newResponse = spec.interpretResponse(serverResponse, bidRequest); expect(newResponse.length).to.be.equal(1); @@ -99,4 +186,38 @@ describe('interpretResponse', function () { response = spec.interpretResponse(serverResponse, bidRequest); expect(response).to.deep.equal([]) }); + it('should add responses if the cpm is valid', function () { + serverResponse.body.seatbid[0].bid[0].price = 0.5; + let response = spec.interpretResponse(serverResponse, bidRequest); + expect(response).to.not.deep.equal([]); + }); +}); + +describe('getUserSyncs', function () { + it('Verifies that getUserSyncs is a function', function () { + expect((typeof (spec.getUserSyncs)).should.equals('function')); + }); + it('Verifies getUserSyncs returns expected result', function () { + expect((typeof (spec.getUserSyncs)).should.equals('function')); + expect(spec.getUserSyncs({iframeEnabled: true})).to.deep.equal({ + type: 'iframe', + url: 'https://eu-ads.adpone.com' + }); + }); + it('Verifies that iframeEnabled: false returns an empty array', function () { + expect(spec.getUserSyncs({iframeEnabled: false})).to.deep.equal(EMPTY_ARRAY); + }); + it('Verifies that iframeEnabled: null returns an empty array', function () { + expect(spec.getUserSyncs(null)).to.deep.equal(EMPTY_ARRAY); + }); +}); + +describe('test onBidWon function', function () { + it('exists and is a function', () => { + expect(spec.onBidWon).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onBidWon({}); + expect(response).to.be.an('undefined') + }); }); diff --git a/test/spec/modules/fintezaAnalyticsAdapter_spec.js b/test/spec/modules/fintezaAnalyticsAdapter_spec.js index 33b24f5f50f..2cc2f380016 100644 --- a/test/spec/modules/fintezaAnalyticsAdapter_spec.js +++ b/test/spec/modules/fintezaAnalyticsAdapter_spec.js @@ -2,17 +2,27 @@ import fntzAnalyticsAdapter from 'modules/fintezaAnalyticsAdapter'; import includes from 'core-js/library/fn/array/includes'; import { expect } from 'chai'; import { parse as parseURL } from 'src/url'; + let adapterManager = require('src/adapterManager').default; let events = require('src/events'); let constants = require('src/constants.json'); +function setCookie(name, value, expires) { + document.cookie = name + '=' + value + + '; path=/' + + (expires ? ('; expires=' + expires.toUTCString()) : '') + + '; SameSite=None'; +} + describe('finteza analytics adapter', function () { const clientId = 'fntz-client-32145'; + const uniqCookie = '5045380421580287382'; let xhr; let requests; beforeEach(function () { + setCookie('_fz_uniq', uniqCookie); xhr = sinon.useFakeXMLHttpRequest(); requests = []; xhr.onCreate = request => { requests.push(request) }; @@ -38,6 +48,7 @@ describe('finteza analytics adapter', function () { }); afterEach(function () { + setCookie('_fz_uniq', '', new Date(0)); xhr.restore(); events.getEvents.restore(); fntzAnalyticsAdapter.track.restore(); @@ -74,6 +85,7 @@ describe('finteza analytics adapter', function () { expect(requests.length).to.equal(1); expect(requests[0].method).to.equal('GET'); + expect(requests[0].withCredentials).to.equal(true); const url = parseURL(requests[0].url); @@ -81,6 +93,7 @@ describe('finteza analytics adapter', function () { expect(url.hostname).to.equal('content.mql5.com'); expect(url.pathname).to.equal('/tr'); expect(url.search.id).to.equal(clientId); + expect(url.search.fz_uniq).to.equal(uniqCookie); expect(decodeURIComponent(url.search.event)).to.equal(`Bid Request ${bidderCode.toUpperCase()}`); sinon.assert.callCount(fntzAnalyticsAdapter.track, 1); @@ -115,6 +128,7 @@ describe('finteza analytics adapter', function () { expect(requests.length).to.equal(2); expect(requests[0].method).to.equal('GET'); + expect(requests[0].withCredentials).to.equal(true); let url = parseURL(requests[0].url); @@ -122,11 +136,13 @@ describe('finteza analytics adapter', function () { expect(url.hostname).to.equal('content.mql5.com'); expect(url.pathname).to.equal('/tr'); expect(url.search.id).to.equal(clientId); + expect(url.search.fz_uniq).to.equal(uniqCookie); expect(decodeURIComponent(url.search.event)).to.equal(`Bid Response Price ${bidderCode.toLowerCase()}`); expect(url.search.value).to.equal(String(cpm)); expect(url.search.unit).to.equal('usd'); expect(requests[1].method).to.equal('GET'); + expect(requests[1].withCredentials).to.equal(true); url = parseURL(requests[1].url); @@ -134,6 +150,7 @@ describe('finteza analytics adapter', function () { expect(url.hostname).to.equal('content.mql5.com'); expect(url.pathname).to.equal('/tr'); expect(url.search.id).to.equal(clientId); + expect(url.search.fz_uniq).to.equal(uniqCookie); expect(decodeURIComponent(url.search.event)).to.equal(`Bid Response Time ${bidderCode.toLowerCase()}`); expect(url.search.value).to.equal(String(timeToRespond)); expect(url.search.unit).to.equal('ms'); @@ -165,6 +182,7 @@ describe('finteza analytics adapter', function () { expect(requests.length).to.equal(1); expect(requests[0].method).to.equal('GET'); + expect(requests[0].withCredentials).to.equal(true); const url = parseURL(requests[0].url); @@ -172,6 +190,7 @@ describe('finteza analytics adapter', function () { expect(url.hostname).to.equal('content.mql5.com'); expect(url.pathname).to.equal('/tr'); expect(url.search.id).to.equal(clientId); + expect(url.search.fz_uniq).to.equal(uniqCookie); expect(decodeURIComponent(url.search.event)).to.equal(`Bid Won ${bidderCode.toUpperCase()}`); expect(url.search.value).to.equal(String(cpm)); expect(url.search.unit).to.equal('usd'); @@ -202,6 +221,7 @@ describe('finteza analytics adapter', function () { expect(requests.length).to.equal(1); expect(requests[0].method).to.equal('GET'); + expect(requests[0].withCredentials).to.equal(true); const url = parseURL(requests[0].url); @@ -209,6 +229,7 @@ describe('finteza analytics adapter', function () { expect(url.hostname).to.equal('content.mql5.com'); expect(url.pathname).to.equal('/tr'); expect(url.search.id).to.equal(clientId); + expect(url.search.fz_uniq).to.equal(uniqCookie); expect(decodeURIComponent(url.search.event)).to.equal(`Bid Timeout Bidder789`); expect(url.search.value).to.equal(String(timeout)); expect(url.search.unit).to.equal('ms'); 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', diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index cedef568d56..82c8e494533 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -245,8 +245,8 @@ describe('gumgumAdapter', function () { 'thms': 10000 } let result = spec.interpretResponse({ body: inscreenServerResponse }, inscreenBidRequest); - expect(result[0].width).to.equal(inscreenBidRequest.sizes[0][0].toString()); - expect(result[0].height).to.equal(inscreenBidRequest.sizes[0][1].toString()); + expect(result[0].width).to.equal('1'); + expect(result[0].height).to.equal('1'); }) }) describe('getUserSyncs', function () { diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index 8b8f6c4bf4c..2d9d51c0d68 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -193,6 +193,47 @@ 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); + bidRequest.schain = schain; + const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.schain).to.equal(schain); + }); + it('should return 2 requests', function () { const requests = spec.buildRequests([ simpleBidRequest, @@ -447,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, @@ -543,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); @@ -658,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 () { diff --git a/test/spec/modules/liveIntentIdSystem_spec.js b/test/spec/modules/liveIntentIdSystem_spec.js new file mode 100644 index 00000000000..7620e8ac7b8 --- /dev/null +++ b/test/spec/modules/liveIntentIdSystem_spec.js @@ -0,0 +1,145 @@ +import { liveIntentIdSubmodule } from 'modules/liveIntentIdSystem'; +import * as utils from 'src/utils'; + +describe('LiveIntentId', function() { + let xhr; + let requests; + let getCookieStub; + let getDataFromLocalStorageStub; + let logErrorStub; + + const defaultConfigParams = {'publisherId': '89899'}; + const responseHeader = { 'Content-Type': 'application/json' } + + beforeEach(function () { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + getCookieStub = sinon.stub(utils, 'getCookie'); + getDataFromLocalStorageStub = sinon.stub(utils, 'getDataFromLocalStorage'); + logErrorStub = sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + xhr.restore(); + getCookieStub.restore(); + getDataFromLocalStorageStub.restore(); + logErrorStub.restore(); + }); + + it('should log an error if no configParams were passed', function() { + liveIntentIdSubmodule.getId(); + expect(logErrorStub.calledOnce).to.be.true; + }); + + it('should log an error if publisherId configParam was not passed', function() { + liveIntentIdSubmodule.getId({}); + expect(logErrorStub.calledOnce).to.be.true; + }); + + it('should call the Custom URL of the LiveIntent Identity Exchange endpoint', function() { + getCookieStub.returns(null); + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId({...defaultConfigParams, ...{'url': 'https://dummy.liveintent.com'}}).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the default url of the LiveIntent Identity Exchange endpoint, with a partner', function() { + getCookieStub.returns(null); + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId({...defaultConfigParams, ...{'url': 'https://dummy.liveintent.com', 'partner': 'rubicon'}}).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the LiveIntent Identity Exchange endpoint, with no additional query params', function() { + getCookieStub.returns(null); + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('//idx.liadm.com/idex/prebid/89899?'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should include the LiveConnect identifier when calling the LiveIntent Identity Exchange endpoint', function() { + getCookieStub.withArgs('_li_duid').returns('li-fpc'); + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('//idx.liadm.com/idex/prebid/89899?duid=li-fpc&'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should include the LiveConnect identifier and additional Identifiers to resolve', function() { + getCookieStub.withArgs('_li_duid').returns('li-fpc'); + getDataFromLocalStorageStub.withArgs('_thirdPC').returns('third-pc'); + let configParams = { + ...defaultConfigParams, + ...{ + 'identifiersToResolve': ['_thirdPC'] + } + }; + + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('//idx.liadm.com/idex/prebid/89899?_thirdPC=third-pc&duid=li-fpc&'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should include an additional identifier value to resolve even if it is an object', function() { + getCookieStub.returns(null); + getDataFromLocalStorageStub.withArgs('_thirdPC').returns({'key': 'value'}); + let configParams = { + ...defaultConfigParams, + ...{ + 'identifiersToResolve': ['_thirdPC'] + } + }; + + let callBackSpy = sinon.spy(); + let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback; + submoduleCallback(callBackSpy); + let request = requests[0]; + expect(request.url).to.be.eq('//idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D&'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); +}); diff --git a/test/spec/modules/lockerdomeBidAdapter_spec.js b/test/spec/modules/lockerdomeBidAdapter_spec.js index 6a3fd814030..a108b25e2ff 100644 --- a/test/spec/modules/lockerdomeBidAdapter_spec.js +++ b/test/spec/modules/lockerdomeBidAdapter_spec.js @@ -15,7 +15,6 @@ describe('LockerDomeAdapter', function () { }, adUnitCode: 'ad-1', transactionId: 'b55e97d7-792c-46be-95a5-3df40b115734', - sizes: [[300, 250]], bidId: '2652ca954bce9', bidderRequestId: '14a54fade69854', auctionId: 'd4c83108-615d-4c2c-9384-dac9ffd4fd72' @@ -31,7 +30,6 @@ describe('LockerDomeAdapter', function () { }, adUnitCode: 'ad-2', transactionId: '73459f05-c482-4706-b2b7-72e6f6264ce6', - sizes: [[300, 600]], bidId: '4510f2834773ce', bidderRequestId: '14a54fade69854', auctionId: 'd4c83108-615d-4c2c-9384-dac9ffd4fd72' @@ -51,19 +49,25 @@ describe('LockerDomeAdapter', function () { describe('buildRequests', function () { it('should generate a valid single POST request for multiple bid requests', function () { - const request = spec.buildRequests(bidRequests); + const bidderRequest = { + refererInfo: { + canonicalUrl: 'https://example.com/canonical', + referer: 'https://example.com' + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.method).to.equal('POST'); expect(request.url).to.equal('https://lockerdome.com/ladbid/prebid'); expect(request.data).to.exist; const requestData = JSON.parse(request.data); - expect(requestData.url).to.equal(utils.getTopWindowLocation().href); - expect(requestData.referrer).to.equal(utils.getTopWindowReferrer()); - const bids = requestData.bidRequests; expect(bids).to.have.lengthOf(2); + expect(requestData.url).to.equal(encodeURIComponent(bidderRequest.refererInfo.canonicalUrl)); + expect(requestData.referrer).to.equal(encodeURIComponent(bidderRequest.refererInfo.referer)); + expect(bids[0].requestId).to.equal('2652ca954bce9'); expect(bids[0].adUnitCode).to.equal('ad-1'); expect(bids[0].adUnitId).to.equal('LD10809467961050726'); @@ -84,6 +88,10 @@ describe('LockerDomeAdapter', function () { gdprConsent: { consentString: 'AAABBB', gdprApplies: true + }, + refererInfo: { + canonicalUrl: 'https://example.com/canonical', + referer: 'https://example.com' } }; const request = spec.buildRequests(bidRequests, bidderRequest); @@ -129,7 +137,14 @@ describe('LockerDomeAdapter', function () { } }; - const request = spec.buildRequests(bidRequests); + const bidderRequest = { + refererInfo: { + canonicalUrl: 'https://example.com/canonical', + referer: 'https://example.com' + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); const interpretedResponse = spec.interpretResponse(serverResponse, request); expect(interpretedResponse).to.have.lengthOf(2); 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'; 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); + }); + }) + }); +}); 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 c823e5aa370..658f130d144 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1043,7 +1043,11 @@ describe('S2S Adapter', function () { let userIdBidRequest = utils.deepClone(BID_REQUESTS); userIdBidRequest[0].bids[0].userId = { tdid: 'abc123', - pubcid: '1234' + pubcid: '1234', + parrableid: '01.1563917337.test-eid', + lipb: { + lipbid: 'li-xyz' + } }; adapter.callBids(REQUEST, userIdBidRequest, addBidResponse, done, ajax); @@ -1054,6 +1058,10 @@ 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'); }); it('when config \'currency.adServerCurrency\' value is an array: ORTB has property \'cur\' value set to a single item array', function () { diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index ababf2dcf5f..22c0f840026 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1660,7 +1660,43 @@ describe('PubMatic adapter', function () { expect(data.user.eids).to.equal(undefined); }); }); - }) + + describe('LiveIntent Id', function() { + it('send the LiveIntent id if it is present', function() { + bidRequests[0].userId = {}; + bidRequests[0].userId.lipb = { lipbid: 'live-intent-user-id' }; + let request = spec.buildRequests(bidRequests, {}); + let data = JSON.parse(request.data); + expect(data.user.eids).to.deep.equal([{ + 'source': 'liveintent.com', + 'uids': [{ + 'id': 'live-intent-user-id', + 'atype': 1 + }] + }]); + }); + + it('do not pass if not string', function() { + bidRequests[0].userId = {}; + bidRequests[0].userId.lipb = { lipbid: 1 }; + let request = spec.buildRequests(bidRequests, {}); + let data = JSON.parse(request.data); + expect(data.user.eids).to.equal(undefined); + bidRequests[0].userId.lipb.lipbid = []; + request = spec.buildRequests(bidRequests, {}); + data = JSON.parse(request.data); + expect(data.user.eids).to.equal(undefined); + bidRequests[0].userId.lipb.lipbid = null; + request = spec.buildRequests(bidRequests, {}); + data = JSON.parse(request.data); + expect(data.user.eids).to.equal(undefined); + bidRequests[0].userId.lipb.lipbid = {}; + request = spec.buildRequests(bidRequests, {}); + data = JSON.parse(request.data); + expect(data.user.eids).to.equal(undefined); + }); + }); + }); it('Request params check for video ad', function () { let request = spec.buildRequests(videoBidRequests); 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; diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js index 3452ae747b9..dd34245bd8e 100644 --- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js +++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js @@ -92,6 +92,7 @@ const BID2 = Object.assign({}, BID, { mediaType: 'banner', cpm: 1.52, source: 'server', + seatBidId: 'aaaa-bbbb-cccc-dddd', rubiconTargeting: { 'rpfl_elemid': '/19968336/header-bid-tag1', 'rpfl_14062': '2_tier0100' @@ -222,6 +223,7 @@ const MOCK = { 'transactionId': 'c116413c-9e3f-401a-bee1-d56aec29a1d4', 'sizes': [[1000, 300], [970, 250], [728, 90]], 'bidId': '3bd4ebb1c900e2', + 'seatBidId': 'aaaa-bbbb-cccc-dddd', 'bidderRequestId': '1be65d7958826a', 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' } @@ -354,7 +356,7 @@ const ANALYTICS_MESSAGE = { 'bids': [ { 'bidder': 'rubicon', - 'bidId': '3bd4ebb1c900e2', + 'bidId': 'aaaa-bbbb-cccc-dddd', 'status': 'success', 'source': 'server', 'clientLatencyMillis': 3214, @@ -421,7 +423,7 @@ const ANALYTICS_MESSAGE = { 'bidder': 'rubicon', 'transactionId': 'c116413c-9e3f-401a-bee1-d56aec29a1d4', 'adUnitCode': '/19968336/header-bid-tag1', - 'bidId': '3bd4ebb1c900e2', + 'bidId': 'aaaa-bbbb-cccc-dddd', 'status': 'success', 'source': 'server', 'clientLatencyMillis': 3214, diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index d31b83fd923..4688f0f5d32 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -2036,6 +2036,7 @@ describe('the rubicon adapter', function () { expect(bids).to.be.lengthOf(1); + expect(bids[0].seatBidId).to.equal('0'); expect(bids[0].creativeId).to.equal('4259970'); expect(bids[0].cpm).to.equal(2); expect(bids[0].ttl).to.equal(300); diff --git a/test/spec/modules/shBidAdapter_spec.js b/test/spec/modules/shBidAdapter_spec.js index 588d4c54150..525642da7d6 100644 --- a/test/spec/modules/shBidAdapter_spec.js +++ b/test/spec/modules/shBidAdapter_spec.js @@ -16,17 +16,11 @@ const gdpr = { } } -const bidRequestVideo = { +const bidRequestCommonParams = { 'bidder': 'showheroes-bs', 'params': { 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', }, - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'instream', - } - }, 'adUnitCode': 'adunit-code-1', 'sizes': [[640, 480]], 'bidId': '38b373e1e31c18', @@ -34,40 +28,55 @@ const bidRequestVideo = { 'auctionId': '43aa080090a47f', } +const bidRequestVideo = { + ...bidRequestCommonParams, + ...{ + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream', + } + } + } +} + +const bidRequestOutstream = { + ...bidRequestCommonParams, + ...{ + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'outstream', + } + } + } +} + const bidRequestVideoVpaid = { - 'bidder': 'showheroes-bs', - 'params': { - 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', - 'vpaidMode': true, - }, - 'mediaTypes': { - 'video': { - 'playerSize': [640, 480], - 'context': 'instream', + ...bidRequestCommonParams, + ...{ + 'params': { + 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', + 'vpaidMode': true, + }, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream', + } } - }, - 'adUnitCode': 'adunit-code-1', - 'sizes': [[640, 480]], - 'bidId': '38b373e1e31c18', - 'bidderRequestId': '12e3ade2543ba6', - 'auctionId': '43aa080090a47f', + } } const bidRequestBanner = { - 'bidder': 'showheroes-bs', - 'params': { - 'playerId': '47427aa0-f11a-4d24-abca-1295a46a46cd', - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[640, 360]] + ...bidRequestCommonParams, + ...{ + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 360]] + } } - }, - 'adUnitCode': 'adunit-code-1', - 'sizes': [[640, 480]], - 'bidId': '38b373e1e31c18', - 'bidderRequestId': '12e3ade2543ba6', - 'auctionId': '43aa080090a47f', + } } describe('shBidAdapter', function () { @@ -103,6 +112,58 @@ describe('shBidAdapter', function () { expect(request.method).to.equal('POST') }) + it('check sizes formats', function () { + const request = spec.buildRequests([{ + 'params': {}, + 'mediaTypes': {}, + 'sizes': [[640, 480]], + }], bidderRequest) + const payload = request.data.requests[0]; + expect(payload).to.be.an('object'); + expect(payload.video).to.have.property('width', 640); + expect(payload.video).to.have.property('height', 480); + + const request2 = spec.buildRequests([{ + 'params': {}, + 'mediaTypes': {}, + 'sizes': [320, 240], + }], bidderRequest) + const payload2 = request2.data.requests[0]; + expect(payload).to.be.an('object'); + expect(payload2.video).to.have.property('width', 320); + expect(payload2.video).to.have.property('height', 240); + }) + + it('should get size from mediaTypes when sizes property is empty', function () { + const request = spec.buildRequests([{ + 'params': {}, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480] + } + }, + 'sizes': [], + }], bidderRequest) + const payload = request.data.requests[0]; + expect(payload).to.be.an('object'); + expect(payload.video).to.have.property('width', 640); + expect(payload.video).to.have.property('height', 480); + + const request2 = spec.buildRequests([{ + 'params': {}, + 'mediaTypes': { + 'banner': { + 'sizes': [[320, 240]] + } + }, + 'sizes': [], + }], bidderRequest) + const payload2 = request2.data.requests[0]; + expect(payload).to.be.an('object'); + expect(payload2.video).to.have.property('width', 320); + expect(payload2.video).to.have.property('height', 240); + }) + it('should attach valid params to the payload when type is video', function () { const request = spec.buildRequests([bidRequestVideo], bidderRequest) const payload = request.data.requests[0]; @@ -144,6 +205,9 @@ describe('shBidAdapter', function () { expect(spec.interpretResponse({body: []}, {data: {meta: {}}}).length).to.equal(0) }) + const vastTag = 'https://video-library.stage.showheroes.com/commercial/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6' + const vastXml = '' + const response = { 'bids': [{ 'cpm': 5, @@ -151,6 +215,7 @@ describe('shBidAdapter', function () { 'bidId': '38b373e1e31c18', 'video': {'width': 640, 'height': 480}, 'vastTag': 'https:\/\/video-library.stage.showheroes.com\/commercial\/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6', + 'vastXml': vastXml, }], } @@ -165,9 +230,13 @@ describe('shBidAdapter', function () { 'height': 480, 'mediaType': 'video', 'netRevenue': true, - 'vastUrl': 'https://video-library.stage.showheroes.com/commercial/wrapper?player_id=47427aa0-f11a-4d24-abca-1295a46a46cd&ad_bidder=showheroes-bs&master_shadt=1&description_url=https%3A%2F%2Fbid-service.stage.showheroes.com%2Fvast%2Fad%2Fcache%2F4840b920-40e1-4e09-9231-60bbf088c8d6', + 'vastUrl': vastTag, + 'vastXml': vastXml, 'requestId': '38b373e1e31c18', 'ttl': 300, + 'adResponse': { + 'content': vastXml + } } ] @@ -183,5 +252,129 @@ describe('shBidAdapter', function () { expect(result[0].ad).to.include('