From 6be8c3b6fb879d5efda5318582edf97b26d02302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Millet?= Date: Tue, 7 May 2024 16:39:23 +0200 Subject: [PATCH] Dailymotion Bid Adapter: accept ortb2 field (#11366) * Dailymotion Bid Adaptor: initial release * .md file lint issue resolved * Dailymotion Bid Adaptor: build bidder request based on param with fallbacks * Dailymotion Bid Adaptor: support video metadata * Dailymotion Bid Adaptor: add support for sending adUnitCode * Dailymotion Bid Adaptor: add support for sending startDelay * feat(LEO-528): Allow multiple IAB categories in video metadata The same way as we can have an array of IAB categories level 1 in the ORTB request, this PR introduces an array for the IAB categories level 2. To be forward compatible with level [2.2](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.2.tsv) and [3.0](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%203.0.tsv) specifications, the category IDs should be sent as strings. * Dailymotion bid adapter: Clarify the video metadata to provide in each player context * Dailymotion bid adapter: Move API key to bid params * Dailymotion bid adapter: Verify API key is string Co-authored-by: Rumesh * Dailymotion bid adapter: Move API key to bid params (fix tests) * Dailymotion Bid Adaptor: add gpp support and get coppa from request * Dailymotion Bid Adaptor: fix lint error * Dailymotion Bid Adaptor: add iabcat1 and fallback to ortb2 for iabcat2 * Dailymotion Bid Adaptor: get iabcats from ortb2.site.content.data * Dailymotion Bid Adaptor: get content data from ortb2.site.content * Dailymotion Bid Adaptor: add support for iabcat1 in videoParams and document mapping of ortb2 fpd to video metadata * Dailymotion Bid Adaptor: add support for Object: App * Dailymotion Bid Adaptor: only support video adunits in context instream * Dailymotion bid adapter: Add standard ORTB video parameters Note: I changed the case of `startdelay` to be consistent with the other parameters, but it won't have any impact on current deployments as this parameter is not used onsite. * Dailymotion Bid Adaptor: add support for livestream and app * Dailymotion Bid Adaptor: drop support for non standard fields in mediaTypes.video * Dailymotion Bid Adaptor: update docs examples --------- Co-authored-by: Kevin Siow Co-authored-by: Aditi Chaudhary Co-authored-by: Kevin Siow Co-authored-by: Rumesh --- modules/dailymotionBidAdapter.js | 105 +++++--- modules/dailymotionBidAdapter.md | 83 ++++-- .../modules/dailymotionBidAdapter_spec.js | 255 +++++++++++++++--- 3 files changed, 354 insertions(+), 89 deletions(-) diff --git a/modules/dailymotionBidAdapter.js b/modules/dailymotionBidAdapter.js index 2be5edad78e..afded538fd0 100644 --- a/modules/dailymotionBidAdapter.js +++ b/modules/dailymotionBidAdapter.js @@ -9,27 +9,33 @@ import { deepAccess } from '../src/utils.js'; * @return video metadata */ function getVideoMetadata(bidRequest, bidderRequest) { - const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video', {}); - const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + const videoParams = deepAccess(bidRequest, 'params.video', {}); - const videoParams = { - ...videoAdUnit, - ...videoBidderParams, // Bidder Specific overrides - }; + // As per oRTB 2.5 spec, "A bid request must not contain both an App and a Site object." + // See section 3.2.14 + // Content object is either from Object: Site or Object: App + const contentObj = deepAccess(bidderRequest, 'ortb2.site') + ? deepAccess(bidderRequest, 'ortb2.site.content') + : deepAccess(bidderRequest, 'ortb2.app.content'); - // Store as object keys to ensure uniqueness - const iabcat1 = {}; - const iabcat2 = {}; + const parsedContentData = { + // Store as object keys to ensure uniqueness + iabcat1: {}, + iabcat2: {}, + }; - deepAccess(bidderRequest, 'ortb2.site.content.data', []).forEach((data) => { + deepAccess(contentObj, 'data', []).forEach((data) => { if ([4, 5, 6, 7].includes(data?.ext?.segtax)) { (Array.isArray(data.segment) ? data.segment : []).forEach((segment) => { if (typeof segment.id === 'string') { // See https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy // Only take IAB cats of taxonomy V1 - if (data.ext.segtax === 4) iabcat1[segment.id] = 1; - // Only take IAB cats of taxonomy V2 or higher - if ([5, 6, 7].includes(data.ext.segtax)) iabcat2[segment.id] = 1; + if (data.ext.segtax === 4) { + parsedContentData.iabcat1[segment.id] = 1; + } else { + // Only take IAB cats of taxonomy V2 or higher + parsedContentData.iabcat2[segment.id] = 1; + } } }); } @@ -37,18 +43,25 @@ function getVideoMetadata(bidRequest, bidderRequest) { const videoMetadata = { description: videoParams.description || '', - duration: videoParams.duration || 0, - iabcat1: Object.keys(iabcat1), + duration: videoParams.duration || deepAccess(contentObj, 'len', 0), + iabcat1: Array.isArray(videoParams.iabcat1) + ? videoParams.iabcat1 + : Array.isArray(deepAccess(contentObj, 'cat')) + ? contentObj.cat + : Object.keys(parsedContentData.iabcat1), iabcat2: Array.isArray(videoParams.iabcat2) ? videoParams.iabcat2 - : Object.keys(iabcat2), - id: videoParams.id || '', - lang: videoParams.lang || '', + : Object.keys(parsedContentData.iabcat2), + id: videoParams.id || deepAccess(contentObj, 'id', ''), + lang: videoParams.lang || deepAccess(contentObj, 'language', ''), private: videoParams.private || false, - tags: videoParams.tags || '', - title: videoParams.title || '', + tags: videoParams.tags || deepAccess(contentObj, 'keywords', ''), + title: videoParams.title || deepAccess(contentObj, 'title', ''), topics: videoParams.topics || '', xid: videoParams.xid || '', + livestream: typeof videoParams.livestream === 'number' + ? !!videoParams.livestream + : !!deepAccess(contentObj, 'livestream', 0), }; return videoMetadata; @@ -67,7 +80,24 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return typeof bid?.params?.apiKey === 'string' && bid.params.apiKey.length > 10; + if (bid?.params) { + // We only accept video adUnits + if (!bid?.mediaTypes?.[VIDEO]) return false; + + // As `context`, `placement` & `plcmt` are optional (although recommended) + // values, we check the 3 of them to see if we are in an instream video context + const isInstream = bid.mediaTypes[VIDEO].context === 'instream' || + bid.mediaTypes[VIDEO].placement === 1 || + bid.mediaTypes[VIDEO].plcmt === 1; + + // We only accept instream video context + if (!isInstream) return false; + + // We need API key + return typeof bid.params.apiKey === 'string' && bid.params.apiKey.length > 10; + } + + return false; }, /** @@ -83,15 +113,15 @@ export const spec = { data: { bidder_request: { gdprConsent: { - apiVersion: bidderRequest?.gdprConsent?.apiVersion || 1, - consentString: bidderRequest?.gdprConsent?.consentString || '', + apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1), + consentString: deepAccess(bidderRequest, 'gdprConsent.consentString', ''), // Cast boolean in any case (eg: if value is int) to ensure type - gdprApplies: !!bidderRequest?.gdprConsent?.gdprApplies, + gdprApplies: !!deepAccess(bidderRequest, 'gdprConsent.gdprApplies'), }, refererInfo: { - page: bidderRequest?.refererInfo?.page || '', + page: deepAccess(bidderRequest, 'refererInfo.page', ''), }, - uspConsent: bidderRequest?.uspConsent || '', + uspConsent: deepAccess(bidderRequest, 'uspConsent', ''), gppConsent: { gppString: deepAccess(bidderRequest, 'gppConsent.gppString') || deepAccess(bidderRequest, 'ortb2.regs.gpp', ''), @@ -104,15 +134,28 @@ export const spec = { }, // Cast boolean in any case (value should be 0 or 1) to ensure type coppa: !!deepAccess(bidderRequest, 'ortb2.regs.coppa'), + // In app context, we need to retrieve additional informations + ...(!deepAccess(bidderRequest, 'ortb2.site') && !!deepAccess(bidderRequest, 'ortb2.app') ? { + appBundle: deepAccess(bidderRequest, 'ortb2.app.bundle', ''), + appStoreUrl: deepAccess(bidderRequest, 'ortb2.app.storeurl', ''), + } : {}), request: { - adUnitCode: bid.adUnitCode || '', - auctionId: bid.auctionId || '', - bidId: bid.bidId || '', + adUnitCode: deepAccess(bid, 'adUnitCode', ''), + auctionId: deepAccess(bid, 'auctionId', ''), + bidId: deepAccess(bid, 'bidId', ''), mediaTypes: { video: { - playerSize: bid.mediaTypes?.[VIDEO]?.playerSize || [], api: bid.mediaTypes?.[VIDEO]?.api || [], - startDelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, + mimes: bid.mediaTypes?.[VIDEO]?.mimes || [], + minduration: bid.mediaTypes?.[VIDEO]?.minduration || 0, + maxduration: bid.mediaTypes?.[VIDEO]?.maxduration || 0, + protocols: bid.mediaTypes?.[VIDEO]?.protocols || [], + skip: bid.mediaTypes?.[VIDEO]?.skip || 0, + skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0, + skipmin: bid.mediaTypes?.[VIDEO]?.skipmin || 0, + startdelay: bid.mediaTypes?.[VIDEO]?.startdelay || 0, + w: bid.mediaTypes?.[VIDEO]?.w || 0, + h: bid.mediaTypes?.[VIDEO]?.h || 0, }, }, sizes: bid.sizes || [], diff --git a/modules/dailymotionBidAdapter.md b/modules/dailymotionBidAdapter.md index 795273c9229..7c871b0d536 100644 --- a/modules/dailymotionBidAdapter.md +++ b/modules/dailymotionBidAdapter.md @@ -9,10 +9,11 @@ Maintainer: ad-leo-engineering@dailymotion.com # Description Dailymotion prebid adapter. +Supports video ad units in instream context. # Configuration options -Before calling this adapter, you need to set at least the API key in the bid parameters: +Before calling this adapter, you need to at least set a video adUnit in an instream context and the API key in the bid parameters: ```javascript const adUnits = [ @@ -21,8 +22,14 @@ const adUnits = [ bidder: 'dailymotion', params: { apiKey: 'fake_api_key' - } - }] + }, + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + context: 'instream', + }, + }, } ]; ``` @@ -39,9 +46,15 @@ const adUnits = [ bids: [{ bidder: 'dailymotion', params: { - apiKey: 'dailymotion-testing' - } - }] + apiKey: 'dailymotion-testing', + }, + }], + code: 'test-ad-unit', + mediaTypes: { + video: { + context: 'instream', + }, + }, } ]; ``` @@ -51,7 +64,7 @@ Please note that failing to set these will result in the adapter not bidding at # Sample video AdUnit To allow better targeting, you should provide as much context about the video as possible. -There are two ways of doing this depending on if you're using Dailymotion player or a third party one. +There are three ways of doing this depending on if you're using Dailymotion player or a third party one. If you are using the Dailymotion player, you should only provide the video `xid` in your ad unit, example: @@ -61,7 +74,10 @@ const adUnits = [ bids: [{ bidder: 'dailymotion', params: { - apiKey: 'dailymotion-testing' + apiKey: 'dailymotion-testing', + video: { + xid: 'x123456' // Dailymotion infrastructure unique video ID + }, } }], code: 'test-ad-unit', @@ -69,9 +85,9 @@ const adUnits = [ video: { api: [2, 7], context: 'instream', - playerSize: [ [1280, 720] ], - startDelay: 0, - xid: 'x123456' // Dailymotion infrastructure unique video ID + startdelay: 0, + w: 1280, + h: 720, }, } } @@ -91,7 +107,17 @@ const adUnits = [ params: { apiKey: 'dailymotion-testing', video: { - description: 'overriden video description' + description: 'this is a video description', + duration: 556, + iabcat1: ['IAB-2'], + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + livestream: 0, + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', } } }], @@ -100,37 +126,42 @@ const adUnits = [ video: { api: [2, 7], context: 'instream', - description: 'this is a video description', - duration: 556, - iabcat2: ['6', '17'], - id: '54321', - lang: 'FR', - playerSize: [ [1280, 720] ], - private: false, - startDelay: 0, - tags: 'tag_1,tag_2,tag_3', - title: 'test video', - topics: 'topic_1, topic_2', + startdelay: 0, + w: 1280, + h: 720, }, } } ]; ``` -Each of the following video metadata fields can be added in mediaTypes.video or bids.params.video. -If a field exists in both places, it will be overridden by bids.params.video. +Each of the following video metadata fields can be added in bids.params.video. * `description` - Video description * `duration` - Video duration in seconds -* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) +* `iabcat1` - List of IAB category IDs from the [1.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%201.0.tsv) +* `iabcat2` - List of IAB category IDs from the [2.0 taxonomy](https://github.com/InteractiveAdvertisingBureau/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%202.0.tsv) and above * `id` - Video unique ID in host video infrastructure * `lang` - ISO 639-1 code for main language used in the video +* `livestream` - 0 = not live, 1 = content is live * `private` - True if video is not publicly available * `tags` - Tags for the video, comma separated * `title` - Video title * `topics` - Main topics for the video, comma separated * `xid` - Dailymotion video identifier (only applicable if using the Dailymotion player) +If you already specify [First-Party data](https://docs.prebid.org/features/firstPartyData.html) through the `ortb2` object when calling [`pbjs.requestBids(requestObj)`](https://docs.prebid.org/dev-docs/publisher-api-reference/requestBids.html), we will fallback to those values when possible. See the mapping below. + +| From ortb2 | Metadata fields | +|---------------------------------------------------------------------------------|-----------------| +| `ortb2.site.content.cat` OR `ortb2.site.content.data` where `ext.segtax` is `4` | `iabcat1` | +| `ortb2.site.content.data` where `ext.segtax` is `5`, `6` or `7` | `iabcat2` | +| `ortb2.site.content.id` | `id` | +| `ortb2.site.content.language` | `lang` | +| `ortb2.site.content.livestream` | `livestream` | +| `ortb2.site.content.keywords` | `tags` | +| `ortb2.site.content.title` | `title` | + # Integrating the adapter To use the adapter with any non-test request, you first need to ask an API key from Dailymotion. Please contact us through **DailymotionPrebid.js@dailymotion.com**. diff --git a/test/spec/modules/dailymotionBidAdapter_spec.js b/test/spec/modules/dailymotionBidAdapter_spec.js index a102c26dca2..fe9484b2814 100644 --- a/test/spec/modules/dailymotionBidAdapter_spec.js +++ b/test/spec/modules/dailymotionBidAdapter_spec.js @@ -1,7 +1,7 @@ import { config } from 'src/config.js'; import { expect } from 'chai'; import { spec } from 'modules/dailymotionBidAdapter.js'; -import { VIDEO } from '../../../src/mediaTypes'; +import { BANNER, VIDEO } from '../../../src/mediaTypes'; describe('dailymotionBidAdapterTests', () => { // Validate that isBidRequestValid only validates requests with apiKey @@ -12,6 +12,11 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: '', }, + mediaTypes: { + [VIDEO]: { + context: 'instream', + }, + }, }; expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyApi))).to.be.false; @@ -20,9 +25,57 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: 'test_api_key', }, + mediaTypes: { + [VIDEO]: { + context: 'instream', + }, + }, }; expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithApi))).to.be.true; + + const bidWithEmptyMediaTypes = { + params: { + apiKey: '', + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyMediaTypes))).to.be.false; + + const bidWithEmptyVideoAdUnit = { + params: { + apiKey: '', + }, + mediaTypes: { + [VIDEO]: {}, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithEmptyVideoAdUnit))).to.be.false; + + const bidWithBannerMediaType = { + params: { + apiKey: 'test_api_key', + }, + mediaTypes: { + [BANNER]: {}, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithBannerMediaType))).to.be.false; + + const bidWithOutstreamContext = { + params: { + apiKey: 'test_api_key', + }, + mediaTypes: { + video: { + context: 'outstream', + }, + }, + }; + + expect(config.runWithBidder('dailymotion', () => spec.isBidRequestValid(bidWithOutstreamContext))).to.be.false; }); // Validate request generation @@ -33,20 +86,27 @@ describe('dailymotionBidAdapterTests', () => { adUnitCode: 'preroll', mediaTypes: { video: { - playerSize: [[1280, 720]], api: [2, 7], - description: 'this is a test video', - duration: 300, - iabcat2: ['6', '17'], - lang: 'ENG', + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, startdelay: 0, + w: 1280, + h: 720 }, }, sizes: [[1920, 1080]], params: { apiKey: 'test_api_key', video: { + description: 'this is a test video', duration: 556, + iabcat1: ['IAB-1'], + iabcat2: ['6', '17'], id: '54321', lang: 'FR', private: false, @@ -54,6 +114,7 @@ describe('dailymotionBidAdapterTests', () => { title: 'test video', topics: 'topic_1, topic_2', xid: 'x123456', + livestream: 1, }, }, }]; @@ -78,6 +139,117 @@ describe('dailymotionBidAdapterTests', () => { }, site: { content: { + data: [ + { + name: 'dataprovider.com', + ext: { segtax: 5 }, + segment: [{ id: '200' }], + }, + ], + }, + }, + }, + }; + + const [request] = config.runWithBidder( + 'dailymotion', + () => spec.buildRequests(bidRequestData, bidderRequestData), + ); + + const { data: reqData } = request; + + expect(request.url).to.equal('https://pb.dmxleo.com'); + + expect(reqData.bidder_request).to.eql({ + refererInfo: bidderRequestData.refererInfo, + uspConsent: bidderRequestData.uspConsent, + gdprConsent: bidderRequestData.gdprConsent, + gppConsent: bidderRequestData.gppConsent, + }); + expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); + expect(reqData.coppa).to.be.true; + expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); + expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); + expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); + expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.video_metadata).to.eql({ + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-1'], + iabcat2: bidRequestData[0].params.video.iabcat2, + id: bidRequestData[0].params.video.id, + lang: bidRequestData[0].params.video.lang, + private: bidRequestData[0].params.video.private, + tags: bidRequestData[0].params.video.tags, + title: bidRequestData[0].params.video.title, + topics: bidRequestData[0].params.video.topics, + xid: bidRequestData[0].params.video.xid, + duration: bidRequestData[0].params.video.duration, + livestream: !!bidRequestData[0].params.video.livestream, + }); + }); + + it('validates buildRequests with content values from App', () => { + const bidRequestData = [{ + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 123456, + adUnitCode: 'preroll', + mediaTypes: { + video: { + api: [2, 7], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [1, 2, 3, 4, 5, 6, 7, 8], + skip: 1, + skipafter: 5, + skipmin: 10, + startdelay: 0, + w: 1280, + h: 720, + }, + }, + sizes: [[1920, 1080]], + params: { + apiKey: 'test_api_key', + video: { + description: 'this is a test video', + iabcat2: ['6', '17'], + id: '54321', + lang: 'FR', + private: false, + tags: 'tag_1,tag_2,tag_3', + title: 'test video', + topics: 'topic_1, topic_2', + xid: 'x123456', + livestream: 1, + }, + }, + }]; + + const bidderRequestData = { + refererInfo: { + page: 'https://publisher.com', + }, + uspConsent: '1YN-', + gdprConsent: { + apiVersion: 2, + consentString: 'xxx', + gdprApplies: true, + }, + gppConsent: { + gppString: 'xxx', + applicableSections: [5], + }, + ortb2: { + regs: { + coppa: 1, + }, + app: { + bundle: 'app-bundle', + storeurl: 'https://play.google.com/store/apps/details?id=app-bundle', + content: { + len: 556, data: [ { name: 'dataprovider.com', @@ -112,15 +284,25 @@ describe('dailymotionBidAdapterTests', () => { }); expect(reqData.config.api_key).to.eql(bidRequestData[0].params.apiKey); expect(reqData.coppa).to.be.true; + expect(reqData.appBundle).to.eql(bidderRequestData.ortb2.app.bundle); + expect(reqData.appStoreUrl).to.eql(bidderRequestData.ortb2.app.storeurl); expect(reqData.request.auctionId).to.eql(bidRequestData[0].auctionId); expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); - expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.mimes).to.eql(bidRequestData[0].mediaTypes.video.mimes); + expect(reqData.request.mediaTypes.video.minduration).to.eql(bidRequestData[0].mediaTypes.video.minduration); + expect(reqData.request.mediaTypes.video.maxduration).to.eql(bidRequestData[0].mediaTypes.video.maxduration); + expect(reqData.request.mediaTypes.video.protocols).to.eql(bidRequestData[0].mediaTypes.video.protocols); + expect(reqData.request.mediaTypes.video.skip).to.eql(bidRequestData[0].mediaTypes.video.skip); + expect(reqData.request.mediaTypes.video.skipafter).to.eql(bidRequestData[0].mediaTypes.video.skipafter); + expect(reqData.request.mediaTypes.video.skipmin).to.eql(bidRequestData[0].mediaTypes.video.skipmin); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.w).to.eql(bidRequestData[0].mediaTypes.video.w); + expect(reqData.request.mediaTypes.video.h).to.eql(bidRequestData[0].mediaTypes.video.h); expect(reqData.video_metadata).to.eql({ - description: bidRequestData[0].mediaTypes.video.description, - iabcat1: ['IAB-1'], // Taxonomy v2 or higher is excluded - iabcat2: bidRequestData[0].mediaTypes.video.iabcat2, + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-1'], + iabcat2: bidRequestData[0].params.video.iabcat2, id: bidRequestData[0].params.video.id, lang: bidRequestData[0].params.video.lang, private: bidRequestData[0].params.video.private, @@ -129,22 +311,19 @@ describe('dailymotionBidAdapterTests', () => { topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, // Overriden through bidder params - duration: bidRequestData[0].params.video.duration, + duration: bidderRequestData.ortb2.app.content.len, + livestream: !!bidRequestData[0].params.video.livestream, }); }); - it('validates buildRequests with fallback values on ortb2 for gpp & iabcat', () => { + it('validates buildRequests with fallback values on ortb2 (gpp, iabcat2, id...)', () => { const bidRequestData = [{ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', bidId: 123456, adUnitCode: 'preroll', mediaTypes: { video: { - playerSize: [[1280, 720]], api: [2, 7], - description: 'this is a test video', - duration: 300, - lang: 'ENG', startdelay: 0, }, }, @@ -152,11 +331,9 @@ describe('dailymotionBidAdapterTests', () => { params: { apiKey: 'test_api_key', video: { + description: 'this is a test video', duration: 556, - id: '54321', - lang: 'FR', private: false, - tags: 'tag_1,tag_2,tag_3', title: 'test video', topics: 'topic_1, topic_2', xid: 'x123456', @@ -182,6 +359,12 @@ describe('dailymotionBidAdapterTests', () => { }, site: { content: { + id: '54321', + language: 'FR', + keywords: 'tag_1,tag_2,tag_3', + title: 'test video', + livestream: 1, + cat: ['IAB-2'], data: [ undefined, // Undefined to check proper handling of edge cases {}, // Empty object to check proper handling of edge cases @@ -203,7 +386,7 @@ describe('dailymotionBidAdapterTests', () => { }, { name: 'dataprovider.com', - ext: { segtax: 4 }, + ext: { segtax: 5 }, segment: [{ id: 2222 }], // Invalid segment id to check proper handling of edge cases }, { @@ -251,21 +434,20 @@ describe('dailymotionBidAdapterTests', () => { expect(reqData.request.bidId).to.eql(bidRequestData[0].bidId); expect(reqData.request.mediaTypes.video.api).to.eql(bidRequestData[0].mediaTypes.video.api); expect(reqData.request.mediaTypes.video.playerSize).to.eql(bidRequestData[0].mediaTypes.video.playerSize); - expect(reqData.request.mediaTypes.video.startDelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); + expect(reqData.request.mediaTypes.video.startdelay).to.eql(bidRequestData[0].mediaTypes.video.startdelay); expect(reqData.video_metadata).to.eql({ - description: bidRequestData[0].mediaTypes.video.description, - // No iabcat1 here because nothing matches taxonomy - iabcat1: [], + description: bidRequestData[0].params.video.description, + iabcat1: ['IAB-2'], iabcat2: ['6', '17', '20'], - id: bidRequestData[0].params.video.id, - lang: bidRequestData[0].params.video.lang, + id: bidderRequestData.ortb2.site.content.id, + lang: bidderRequestData.ortb2.site.content.language, private: bidRequestData[0].params.video.private, - tags: bidRequestData[0].params.video.tags, - title: bidRequestData[0].params.video.title, + tags: bidderRequestData.ortb2.site.content.keywords, + title: bidderRequestData.ortb2.site.content.title, topics: bidRequestData[0].params.video.topics, xid: bidRequestData[0].params.video.xid, - // Overriden through bidder params duration: bidRequestData[0].params.video.duration, + livestream: !!bidderRequestData.ortb2.site.content.livestream, }); }); @@ -310,9 +492,17 @@ describe('dailymotionBidAdapterTests', () => { adUnitCode: '', mediaTypes: { video: { - playerSize: [], - startDelay: 0, api: [], + mimes: [], + minduration: 0, + maxduration: 0, + protocols: [], + skip: 0, + skipafter: 0, + skipmin: 0, + startdelay: 0, + w: 0, + h: 0, }, }, sizes: [], @@ -330,6 +520,7 @@ describe('dailymotionBidAdapterTests', () => { title: '', topics: '', xid: '', + livestream: false, }); });