Skip to content

Commit

Permalink
Update emoteevBidAdapter.js
Browse files Browse the repository at this point in the history
Retrieve various data from the adapter configuration, and ensure they
are properly formatted:
- GDPR vendor consent
- Metadata: intended to be used as an ID for external partners
- Context: describe the context of the current ad unit

Test coverage for emoteevBidAdapter.js:
- Statements 94.83%
- Branches 98.39%
- Functions 100%
- Lines 94.34%

fixup! Update emoteevBidAdapter.js
  • Loading branch information
piotr-yuxuan committed Jun 21, 2019
1 parent ad0459f commit b97a9b0
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 10 deletions.
48 changes: 44 additions & 4 deletions modules/emoteevBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
contains,
deepAccess,
isArray,
isInteger,
getParameterByName,
getCookie
} from '../src/utils';
Expand Down Expand Up @@ -60,6 +61,19 @@ export const ON_ADAPTER_CALLED = 'on_adapter_called';
export const ON_BID_WON = 'on_bid_won';
export const ON_BIDDER_TIMEOUT = 'on_bidder_timeout';

export const IN_CONTENT = 'in-content';
export const FOOTER = 'footer';
export const OVERLAY = 'overlay';
export const WALLPAPER = 'wallpaper';

/**
* Vendor ID assigned to Emoteev from the Global Vendor & CMP List.
*
* See https://vendorlist.consensu.org/vendorinfo.json for more information.
* @type {number}
*/
export const VENDOR_ID = 15;

/**
* Pure function. See http://prebid.org/dev-docs/bidder-adaptor.html#valid-build-requests-array for detailed semantic.
*
Expand All @@ -71,6 +85,8 @@ export const isBidRequestValid = (bidRequest) => {
bidRequest &&
bidRequest.params &&
deepAccess(bidRequest, 'params.adSpaceId') &&
validateContext(deepAccess(bidRequest, 'params.context')) &&
validateMetadata(deepAccess(bidRequest, 'params.metadata')) &&
bidRequest.bidder === BIDDER_CODE &&
validateSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes')));
};
Expand All @@ -89,7 +105,7 @@ export const buildRequests = (env, debug, currency, validBidRequests, bidderRequ
return {
method: 'POST',
url: bidderUrl(env),
data: JSON.stringify(requestsPayload(debug, currency, validBidRequests, bidderRequest))
data: JSON.stringify(requestsPayload(debug, currency, validBidRequests, bidderRequest)) // Keys with undefined values will be filtered out.
};
};

Expand Down Expand Up @@ -264,7 +280,23 @@ export const userSyncImageUrl = env => url.format({
* @param {Array<Array<int>>} sizes
* @returns {boolean} are sizes valid?
*/
const validateSizes = sizes => isArray(sizes) && sizes.some(size => isArray(size) && size.length === 2);
export const validateSizes = sizes => isArray(sizes) && sizes.length > 0 && sizes.every(size => isArray(size) && size.length === 2);

/**
* Pure function.
*
* @param {string} context
* @returns {boolean} is param `context` valid?
*/
export const validateContext = context => contains([IN_CONTENT, FOOTER, OVERLAY, WALLPAPER], context);

/**
* Pure function.
*
* @param {(number|null|undefined)} metadata
* @returns {boolean} is param `metadata` valid?
*/
export const validateMetadata = metadata => metadata === undefined || metadata === null || (isInteger(metadata) && metadata > 0);

/**
* Pure function.
Expand All @@ -282,6 +314,14 @@ export const conformBidRequest = bidRequest => {
};
};

/**
* Pure function.
*
* @param {object} bidderRequest
* @returns {(boolean|undefined)} raw consent data.
*/
export const gdprConsent = (bidderRequest) => (deepAccess(bidderRequest, 'gdprConsent.vendorData.vendorConsents') || {})[VENDOR_ID];

/**
* Pure function.
*
Expand All @@ -306,7 +346,7 @@ export const requestsPayload = (debug, currency, validBidRequests, bidderRequest
isWebGLEnabled(document)),
userAgent: navigator.userAgent,
gdprApplies: deepAccess(bidderRequest, 'gdprConsent.gdprApplies'),
gdprConsent: deepAccess(bidderRequest, 'gdprConsent.consentString'),
gdprConsent: gdprConsent(bidderRequest),
};
};

Expand Down Expand Up @@ -426,7 +466,7 @@ export const getDeviceInfo = (deviceDimensions, viewDimensions, documentDimensio
* Pure function
* @param {object} config pbjs config value
* @param {string} parameter Environment override from URL query param.
* @returns One of [PRODUCTION, STAGING, DEVELOPMENT].
* @returns {string} One of [PRODUCTION, STAGING, DEVELOPMENT].
*/
export const resolveEnv = (config, parameter) => {
const configEnv = deepAccess(config, 'emoteev.env');
Expand Down
4 changes: 3 additions & 1 deletion modules/emoteevBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ Module that connects to Emoteev's demand sources
{
bidder: 'emoteev',
params: {
adSpaceId: 5084
adSpaceId: 5084,
context: 'in-content',
metadata: 42,
}
}
]
Expand Down
122 changes: 117 additions & 5 deletions test/spec/modules/emoteevBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ import {
DEVELOPMENT,
EVENTS_PATH,
eventsUrl,
FOOTER,
gdprConsent,
getDeviceDimensions,
getDeviceInfo,
getDocumentDimensions,
getUserSyncs,
getViewDimensions,
IN_CONTENT,
interpretResponse,
isBidRequestValid,
isWebGLEnabled,
ON_ADAPTER_CALLED,
ON_BID_WON,
ON_BIDDER_TIMEOUT,
onBidWon,
onAdapterCalled,
onTimeout,
OVERLAY,
PRODUCTION,
requestsPayload,
resolveDebug,
Expand All @@ -39,6 +42,11 @@ import {
USER_SYNC_IMAGE_PATH,
userSyncIframeUrl,
userSyncImageUrl,
validateSizes,
validateContext,
validateMetadata,
VENDOR_ID,
WALLPAPER,
} from 'modules/emoteevBidAdapter';
import * as url from '../../../src/url';
import * as utils from '../../../src/utils';
Expand All @@ -52,7 +60,11 @@ const cannedValidBidRequests = [{
bidder: 'emoteev',
bidderRequestId: '1203b39fecc6a5',
crumbs: {pubcid: 'f3371d16-4e8b-42b5-a770-7e5be1fdf03d'},
params: {adSpaceId: 5084},
params: {
adSpaceId: 5084,
context: IN_CONTENT,
metadata: 42
},
sizes: [[300, 250], [250, 300], [300, 600]],
transactionId: '58dbd732-7a39-45f1-b23e-1c24051a941c',
}];
Expand All @@ -73,7 +85,7 @@ const cannedBidderRequest = {
timeout: 3000,
gdprConsent: {
gdprApplies: true,
consentString: 'my consentString'
vendorData: {vendorConsents: {[VENDOR_ID]: true}},
}
};
const serverResponse =
Expand Down Expand Up @@ -101,6 +113,8 @@ describe('emoteevBidAdapter', function () {
bidId: '23a45b4e3',
params: {
adSpaceId: 12345,
context: IN_CONTENT,
metadata: 42
},
mediaTypes: {
banner: {
Expand All @@ -119,6 +133,8 @@ describe('emoteevBidAdapter', function () {
bidder: '', // invalid bidder
params: {
adSpaceId: 12345,
context: IN_CONTENT,
metadata: 42
},
mediaTypes: {
banner: {
Expand All @@ -130,6 +146,21 @@ describe('emoteevBidAdapter', function () {
bidder: 'emoteev',
params: {
adSpaceId: '', // invalid adSpaceId
context: IN_CONTENT,
metadata: 42
},
mediaTypes: {
banner: {
sizes: [[750, 200]]
}
},
})).to.equal(false);
expect(isBidRequestValid({
bidder: 'emoteev',
params: {
adSpaceId: 12345,
context: 'something', // invalid context
metadata: 42
},
mediaTypes: {
banner: {
Expand All @@ -141,6 +172,21 @@ describe('emoteevBidAdapter', function () {
bidder: 'emoteev',
params: {
adSpaceId: 12345,
context: IN_CONTENT,
metadata: 'lol' // invalid metadata
},
mediaTypes: {
banner: {
sizes: [[750, 200]]
}
},
})).to.equal(false);
expect(isBidRequestValid({
bidder: 'emoteev',
params: {
adSpaceId: 12345,
context: IN_CONTENT,
metadata: 42
},
mediaTypes: {
banner: {
Expand Down Expand Up @@ -400,6 +446,39 @@ describe('emoteevBidAdapter', function () {
});
});

describe('gdprConsent', function () {
describe('gdpr applies, consent given', function () {
const bidderRequest = {
...cannedBidderRequest,
gdprConsent: {
gdprApplies: true,
vendorData: {vendorConsents: {[VENDOR_ID]: true}},
}
};
expect(gdprConsent(bidderRequest)).to.deep.equal(true);
});
describe('gdpr applies, consent withdrawn', function () {
const bidderRequest = {
...cannedBidderRequest,
gdprConsent: {
gdprApplies: true,
vendorData: {vendorConsents: {[VENDOR_ID]: false}},
}
};
expect(gdprConsent(bidderRequest)).to.deep.equal(false);
});
describe('gdpr applies, consent unknown', function () {
const bidderRequest = {
...cannedBidderRequest,
gdprConsent: {
gdprApplies: true,
vendorData: {},
}
};
expect(gdprConsent(bidderRequest)).to.deep.equal(undefined);
});
});

describe('requestsPayload', function () {
const
currency = 'EUR',
Expand All @@ -417,7 +496,7 @@ describe('emoteevBidAdapter', function () {
'deviceInfo',
'userAgent',
'gdprApplies',
'gdprConsent'
'gdprConsent',
);

expect(payload.bidRequests[0]).to.exist.and.have.all.keys(
Expand Down Expand Up @@ -448,7 +527,6 @@ describe('emoteevBidAdapter', function () {
);
expect(payload.userAgent).to.deep.equal(navigator.userAgent);
expect(payload.gdprApplies).to.deep.equal(cannedBidderRequest.gdprConsent.gdprApplies);
expect(payload.gdprConsent).to.deep.equal(cannedBidderRequest.gdprConsent.consentString);
});

describe('getViewDimensions', function () {
Expand Down Expand Up @@ -751,4 +829,38 @@ describe('emoteevBidAdapter', function () {
});
});
});

describe('validateSizes', function () {
it('only accepts valid array of sizes', function () {
expect(validateSizes([])).to.deep.equal(false);
expect(validateSizes([[]])).to.deep.equal(false);
expect(validateSizes([[450, 450], undefined])).to.deep.equal(false);
expect(validateSizes([[450, 450], 'size'])).to.deep.equal(false);
expect(validateSizes([[1, 1]])).to.deep.equal(true);
expect(validateSizes([[1, 1], [450, 450]])).to.deep.equal(true);
});
});

describe('validateContext', function () {
it('only accepts valid context', function () {
expect(validateContext(IN_CONTENT)).to.deep.equal(true);
expect(validateContext(FOOTER)).to.deep.equal(true);
expect(validateContext(OVERLAY)).to.deep.equal(true);
expect(validateContext(WALLPAPER)).to.deep.equal(true);
expect(validateContext(null)).to.deep.equal(false);
expect(validateContext('anything else')).to.deep.equal(false);
});
});

describe('validateMetadata', function () {
it('only accepts a positive integer or null', function () {
expect(validateMetadata(0)).to.deep.equal(false);
expect(validateMetadata(42)).to.deep.equal(true);
expect(validateMetadata(42.0)).to.deep.equal(true); // edge case: valid metadata
expect(validateMetadata(3.14159)).to.deep.equal(false);
expect(validateMetadata('metadata')).to.deep.equal(false);
expect(validateMetadata(undefined)).to.deep.equal(true);
expect(validateMetadata(null)).to.deep.equal(true);
});
});
});

0 comments on commit b97a9b0

Please sign in to comment.