diff --git a/modules/engageyaBidAdapter.js b/modules/engageyaBidAdapter.js index 27d1bb15af8..23b0189931f 100644 --- a/modules/engageyaBidAdapter.js +++ b/modules/engageyaBidAdapter.js @@ -1,7 +1,4 @@ -import { - BANNER, - NATIVE -} from '../src/mediaTypes.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; import { createTrackPixelHtml } from '../src/utils.js'; const { @@ -10,14 +7,21 @@ const { const BIDDER_CODE = 'engageya'; const ENDPOINT_URL = 'https://recs.engageya.com/rec-api/getrecs.json'; const ENDPOINT_METHOD = 'GET'; +const SUPPORTED_SIZES = [ + [100, 75], [236, 202], [100, 100], [130, 130], [200, 200], [250, 250], [300, 272], [300, 250], [300, 230], [300, 214], [300, 187], [300, 166], [300, 150], [300, 133], [300, 120], [400, 200], [300, 200], [250, 377], [620, 410], [207, 311], [310, 166], [310, 333], [190, 106], [228, 132], [300, 174], [80, 60], [600, 500], [600, 600], [1080, 610], [1080, 610], [624, 350], [650, 1168], [1080, 1920], [300, 374] +]; -function getPageUrl() { - var pUrl = window.location.href; - if (isInIframe()) { - pUrl = document.referrer ? document.referrer : pUrl; +function getPageUrl(bidRequest, bidderRequest) { + if (bidRequest.params.pageUrl && bidRequest.params.pageUrl != '[PAGE_URL]') { + return bidRequest.params.pageUrl; } - pUrl = encodeURIComponent(pUrl); - return pUrl; + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + return bidderRequest.refererInfo.referer; + } + const pageUrl = (isInIframe() && document.referrer) + ? document.referrer + : window.location.href; + return encodeURIComponent(pageUrl); } function isInIframe() { @@ -33,13 +37,14 @@ function getImageSrc(rec) { return rec.thumbnail_path.indexOf('http') === -1 ? 'https:' + rec.thumbnail_path : rec.thumbnail_path; } -function getImpressionTrackers(rec) { +function getImpressionTrackers(rec, response) { + const responseTrackers = [response.viewPxl]; if (!rec.trackers) { - return []; + return responseTrackers; } const impressionTrackers = rec.trackers.impressionPixels || []; const viewTrackers = rec.trackers.viewPixels || []; - return [...impressionTrackers, ...viewTrackers]; + return [...impressionTrackers, ...viewTrackers, ...responseTrackers]; } function parseNativeResponse(rec, response) { @@ -56,7 +61,7 @@ function parseNativeResponse(rec, response) { displayUrl: rec.url, cta: '', sponsoredBy: rec.displayName, - impressionTrackers: getImpressionTrackers(rec), + impressionTrackers: getImpressionTrackers(rec, response), }; } @@ -74,56 +79,65 @@ function parseBannerResponse(rec, response) { } const title = rec.title && rec.title.trim() ? `` : ''; const displayName = rec.displayName && title ? `` : ''; - const trackers = getImpressionTrackers(rec) + const trackers = getImpressionTrackers(rec, response) .map(createTrackPixelHtml) .join(''); return `${style}
${rec.title}${displayName}${title}${trackers}
`; } +function getImageSize(bidRequest) { + if (bidRequest.sizes && bidRequest.sizes.length > 0) { + return bidRequest.sizes[0]; + } else if (bidRequest.nativeParams && bidRequest.nativeParams.image && bidRequest.nativeParams.image.sizes) { + return bidRequest.nativeParams.image.sizes; + } + return [-1, -1]; +} + +function isValidSize([width, height]) { + if (!width || !height) { + return false; + } + return SUPPORTED_SIZES.some(([supportedWidth, supportedHeight]) => supportedWidth === width && supportedHeight === height); +} + export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, NATIVE], - isBidRequestValid: function (bid) { - return bid && bid.params && bid.params.hasOwnProperty('widgetId') && bid.params.hasOwnProperty('websiteId') && !isNaN(bid.params.widgetId) && !isNaN(bid.params.websiteId); + + isBidRequestValid: function (bidRequest) { + return bidRequest && + bidRequest.params && + bidRequest.params.hasOwnProperty('widgetId') && + bidRequest.params.hasOwnProperty('websiteId') && + !isNaN(bidRequest.params.widgetId) && + !isNaN(bidRequest.params.websiteId) && + isValidSize(getImageSize(bidRequest)); }, buildRequests: function (validBidRequests, bidderRequest) { - var bidRequests = []; - if (validBidRequests && validBidRequests.length > 0) { - validBidRequests.forEach(function (bidRequest) { - if (bidRequest.params) { - var mediaType = bidRequest.hasOwnProperty('nativeParams') ? 1 : 2; - var imageWidth = -1; - var imageHeight = -1; - if (bidRequest.sizes && bidRequest.sizes.length > 0) { - imageWidth = bidRequest.sizes[0][0]; - imageHeight = bidRequest.sizes[0][1]; - } else if (bidRequest.nativeParams && bidRequest.nativeParams.image && bidRequest.nativeParams.image.sizes) { - imageWidth = bidRequest.nativeParams.image.sizes[0]; - imageHeight = bidRequest.nativeParams.image.sizes[1]; - } - - var widgetId = bidRequest.params.widgetId; - var websiteId = bidRequest.params.websiteId; - var pageUrl = (bidRequest.params.pageUrl && bidRequest.params.pageUrl != '[PAGE_URL]') ? bidRequest.params.pageUrl : ''; - if (!pageUrl) { - pageUrl = (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) ? bidderRequest.refererInfo.referer : getPageUrl(); - } - var bidId = bidRequest.bidId; - var finalUrl = ENDPOINT_URL + '?pubid=0&webid=' + websiteId + '&wid=' + widgetId + '&url=' + pageUrl + '&ireqid=' + bidId + '&pbtpid=' + mediaType + '&imw=' + imageWidth + '&imh=' + imageHeight; - if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprApplies && bidderRequest.consentString) { - finalUrl += '&is_gdpr=1&gdpr_consent=' + bidderRequest.consentString; - } - bidRequests.push({ - url: finalUrl, - method: ENDPOINT_METHOD, - data: '' - }); - } - }); + if (!validBidRequests) { + return []; } - - return bidRequests; + return validBidRequests.map(bidRequest => { + if (bidRequest.params) { + const mediaType = bidRequest.hasOwnProperty('nativeParams') ? 1 : 2; + const [imageWidth, imageHeight] = getImageSize(bidRequest); + const widgetId = bidRequest.params.widgetId; + const websiteId = bidRequest.params.websiteId; + const pageUrl = getPageUrl(bidRequest, bidderRequest); + const bidId = bidRequest.bidId; + let finalUrl = ENDPOINT_URL + '?pubid=0&webid=' + websiteId + '&wid=' + widgetId + '&url=' + pageUrl + '&ireqid=' + bidId + '&pbtpid=' + mediaType + '&imw=' + imageWidth + '&imh=' + imageHeight; + if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprApplies && bidderRequest.consentString) { + finalUrl += '&is_gdpr=1&gdpr_consent=' + bidderRequest.consentString; + } + return { + url: finalUrl, + method: ENDPOINT_METHOD, + data: '' + }; + } + }).filter(Boolean); }, interpretResponse: function (serverResponse, bidRequest) { @@ -135,12 +149,12 @@ export const spec = { return response.recs.map(rec => { let bid = { requestId: response.ireqId, - cpm: rec.ecpm, width: response.imageWidth, height: response.imageHeight, creativeId: rec.postId, + cpm: rec.pecpm || (rec.ecpm / 100), currency: 'USD', - netRevenue: false, + netRevenue: !!rec.pecpm, ttl: 360, meta: { advertiserDomains: rec.domain ? [rec.domain] : [] }, } diff --git a/test/spec/modules/engageyaBidAdapter_spec.js b/test/spec/modules/engageyaBidAdapter_spec.js index ae22948994b..7f07e4b9e4a 100644 --- a/test/spec/modules/engageyaBidAdapter_spec.js +++ b/test/spec/modules/engageyaBidAdapter_spec.js @@ -4,18 +4,7 @@ import * as utils from 'src/utils.js'; const ENDPOINT_URL = 'https://recs.engageya.com/rec-api/getrecs.json'; -export const _getUrlVars = function (url) { - var hash; - var myJson = {}; - var hashes = url.slice(url.indexOf('?') + 1).split('&'); - for (var i = 0; i < hashes.length; i++) { - hash = hashes[i].split('='); - myJson[hash[0]] = hash[1]; - } - return myJson; -} - -describe('engageya adapter', function () { +describe('Engageya adapter', function () { let bidRequests; let nativeBidRequests; @@ -55,40 +44,57 @@ describe('engageya adapter', function () { } ] }) + describe('isBidRequestValid', function () { - it('valid bid case', function () { + it('Valid bid case', function () { let validBid = { bidder: 'engageya', params: { widgetId: 85610, websiteId: 91140, pageUrl: '[PAGE_URL]' - } + }, + sizes: [[300, 250]] } let isValid = spec.isBidRequestValid(validBid); - expect(isValid).to.equal(true); + expect(isValid).to.be.true; }); - it('invalid bid case: widgetId and websiteId is not passed', function () { + it('Invalid bid case: widgetId and websiteId is not passed', function () { let validBid = { bidder: 'engageya', params: {} } let isValid = spec.isBidRequestValid(validBid); - expect(isValid).to.equal(false); + expect(isValid).to.be.false; }) - it('invalid bid case: widget id must be number', function () { + it('Invalid bid case: widget id must be number', function () { let invalidBid = { bidder: 'engageya', params: { widgetId: '157746a', websiteId: 91140, pageUrl: '[PAGE_URL]' - } + }, + sizes: [[300, 250]] + } + let isValid = spec.isBidRequestValid(invalidBid); + expect(isValid).to.be.false; + }) + + it('Invalid bid case: unsupported sizes', function () { + let invalidBid = { + bidder: 'engageya', + params: { + widgetId: '157746a', + websiteId: 91140, + pageUrl: '[PAGE_URL]' + }, + sizes: [[250, 250]] } let isValid = spec.isBidRequestValid(invalidBid); - expect(isValid).to.equal(false); + expect(isValid).to.be.false; }) }) @@ -113,36 +119,30 @@ describe('engageya adapter', function () { it('Request params check', function () { let request = spec.buildRequests(bidRequests)[0]; - const data = _getUrlVars(request.url) - expect(parseInt(data.wid)).to.exist.and.to.equal(bidRequests[0].params.widgetId); - expect(parseInt(data.webid)).to.exist.and.to.equal(bidRequests[0].params.websiteId); - }) - }) - - describe('interpretResponse', function () { - it('should return empty array if no response', function () { - const result = spec.interpretResponse({}, []) - expect(result).to.be.an('array').that.is.empty + const urlParams = new URL(request.url).searchParams; + expect(parseInt(urlParams.get('wid'))).to.exist.and.to.equal(bidRequests[0].params.widgetId); + expect(parseInt(urlParams.get('webid'))).to.exist.and.to.equal(bidRequests[0].params.websiteId); }); - it('should return empty array if no valid bids', function () { - let response = { - recs: [], - imageWidth: 300, - imageHeight: 250, - ireqId: '1d236f7890b', - pbtypeId: 2 - }; - let request = spec.buildRequests(bidRequests)[0]; - const result = spec.interpretResponse({ body: response }, request) - expect(result).to.be.an('array').that.is.empty + it('Request pageUrl - use param', function () { + const pageUrl = 'https://url.test'; + bidRequests[0].params.pageUrl = pageUrl; + const request = spec.buildRequests(bidRequests)[0]; + const urlParams = new URL(request.url).searchParams; + expect(urlParams.get('url')).to.exist.and.to.equal(pageUrl); }); + }) - it('should interpret native response', function () { - let serverResponse = { + describe('interpretResponse', function () { + let nativeResponse; + let bannerResponse; + + beforeEach(() => { + const recsResponse = { recs: [ { - ecpm: 0.0920, + ecpm: 9.20, + pecpm: 0.0520, postId: '', thumbnail_path: 'https://engageya.live/wp-content/uploads/2019/05/images.png', domain: 'domain.test', @@ -159,8 +159,80 @@ describe('engageya adapter', function () { imageWidth: 300, imageHeight: 250, ireqId: '1d236f7890b', - pbtypeId: 1 + viewPxl: '//view.pixel', }; + + nativeResponse = { + ...recsResponse, + pbtypeId: 1, + } + + bannerResponse = { + ...recsResponse, + pbtypeId: 2, + widget: { + additionalData: '{"css":".eng_tag_ttl{display:block!important}"}' + }, + } + }) + + it('should return empty array if no response', function () { + const result = spec.interpretResponse({}, []) + expect(result).to.be.an('array').that.is.empty + }); + + it('should return empty array if no valid bids', function () { + let response = { + recs: [], + imageWidth: 300, + imageHeight: 250, + ireqId: '1d236f7890b', + pbtypeId: 2, + viewPxl: '//view.pixel', + }; + let request = spec.buildRequests(bidRequests)[0]; + const result = spec.interpretResponse({ body: response }, request) + expect(result).to.be.an('array').that.is.empty + }); + + it('should interpret native response', function () { + let expectedResult = [ + { + requestId: '1d236f7890b', + cpm: 0.0520, + width: 300, + height: 250, + netRevenue: true, + currency: 'USD', + creativeId: '', + ttl: 360, + meta: { + advertiserDomains: ['domain.test'] + }, + native: { + title: 'Test title', + body: '', + image: { + url: 'https://engageya.live/wp-content/uploads/2019/05/images.png', + width: 300, + height: 250 + }, + privacyLink: '', + clickUrl: '//click.test', + displayUrl: '//url.test', + cta: '', + sponsoredBy: 'Test displayName', + impressionTrackers: ['//impression.test', '//view.test', '//view.pixel'], + }, + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({ body: nativeResponse }, request); + expect(result).to.deep.equal(expectedResult); + }); + + it('should interpret native response - without pecpm', function () { + delete nativeResponse.recs[0].pecpm; let expectedResult = [ { requestId: '1d236f7890b', @@ -187,81 +259,76 @@ describe('engageya adapter', function () { displayUrl: '//url.test', cta: '', sponsoredBy: 'Test displayName', - impressionTrackers: ['//impression.test', '//view.test'], + impressionTrackers: ['//impression.test', '//view.test', '//view.pixel'], }, } ]; let request = spec.buildRequests(bidRequests)[0]; - let result = spec.interpretResponse({ body: serverResponse }, request); + let result = spec.interpretResponse({ body: nativeResponse }, request); expect(result).to.deep.equal(expectedResult); }); - it('should interpret display response', function () { - let serverResponse = { - recs: [ - { - ecpm: 0.0920, - postId: '', - thumbnail_path: 'https://engageya.live/wp-content/uploads/2019/05/images.png', - domain: 'domain.test', + it('should interpret native response - without trackers', function () { + delete nativeResponse.recs[0].trackers; + let expectedResult = [ + { + requestId: '1d236f7890b', + cpm: 0.0520, + width: 300, + height: 250, + netRevenue: true, + currency: 'USD', + creativeId: '', + ttl: 360, + meta: { + advertiserDomains: ['domain.test'] + }, + native: { title: 'Test title', + body: '', + image: { + url: 'https://engageya.live/wp-content/uploads/2019/05/images.png', + width: 300, + height: 250 + }, + privacyLink: '', clickUrl: '//click.test', - url: '//url.test', - displayName: 'Test displayName', - trackers: { - impressionPixels: ['//impression.test'], - viewPixels: ['//view.test'], - } - } - ], - imageWidth: 300, - imageHeight: 250, - ireqId: '1d236f7890b', - pbtypeId: 2, - widget: { - additionalData: '{"css":".eng_tag_ttl{display:block!important}"}' + displayUrl: '//url.test', + cta: '', + sponsoredBy: 'Test displayName', + impressionTrackers: ['//view.pixel'], + }, } - }; + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({ body: nativeResponse }, request); + expect(result).to.deep.equal(expectedResult); + }); + + it('should interpret display response', function () { let expectedResult = [ { requestId: '1d236f7890b', - cpm: 0.0920, + cpm: 0.0520, width: 300, height: 250, - netRevenue: false, + netRevenue: true, currency: 'USD', creativeId: '', ttl: 360, meta: { advertiserDomains: ['domain.test'] }, - ad: `
Test title
`, + ad: `
Test title
`, } ]; let request = spec.buildRequests(bidRequests)[0]; - let result = spec.interpretResponse({ body: serverResponse }, request); + let result = spec.interpretResponse({ body: bannerResponse }, request); expect(result).to.deep.equal(expectedResult); }); - it('should interpret display response without title', function () { - let serverResponse = { - recs: [ - { - ecpm: 0.0920, - postId: '', - thumbnail_path: 'https://engageya.live/wp-content/uploads/2019/05/images.png', - domain: 'domain.test', - title: ' ', - clickUrl: '//click.test', - url: '//url.test', - displayName: 'Test displayName', - } - ], - imageWidth: 300, - imageHeight: 250, - ireqId: '1d236f7890b', - pbtypeId: 2, - }; + it('should interpret display response - without pecpm', function () { + delete bannerResponse.recs[0].pecpm; let expectedResult = [ { requestId: '1d236f7890b', @@ -275,11 +342,80 @@ describe('engageya adapter', function () { meta: { advertiserDomains: ['domain.test'] }, - ad: `
`, + ad: `
Test title
`, + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({ body: bannerResponse }, request); + expect(result).to.deep.equal(expectedResult); + }); + + it('should interpret display response - without title', function () { + bannerResponse.recs[0].title = ' '; + let expectedResult = [ + { + requestId: '1d236f7890b', + cpm: 0.0520, + width: 300, + height: 250, + netRevenue: true, + currency: 'USD', + creativeId: '', + ttl: 360, + meta: { + advertiserDomains: ['domain.test'] + }, + ad: `
`, + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({ body: bannerResponse }, request); + expect(result).to.deep.equal(expectedResult); + }); + + it('should interpret display response - without widget additional data', function () { + bannerResponse.widget.additionalData = null; + let expectedResult = [ + { + requestId: '1d236f7890b', + cpm: 0.0520, + width: 300, + height: 250, + netRevenue: true, + currency: 'USD', + creativeId: '', + ttl: 360, + meta: { + advertiserDomains: ['domain.test'] + }, + ad: `
Test title
`, + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({ body: bannerResponse }, request); + expect(result).to.deep.equal(expectedResult); + }); + + it('should interpret display response - without trackers', function () { + bannerResponse.recs[0].trackers = null; + let expectedResult = [ + { + requestId: '1d236f7890b', + cpm: 0.0520, + width: 300, + height: 250, + netRevenue: true, + currency: 'USD', + creativeId: '', + ttl: 360, + meta: { + advertiserDomains: ['domain.test'] + }, + ad: `
Test title
`, } ]; let request = spec.buildRequests(bidRequests)[0]; - let result = spec.interpretResponse({ body: serverResponse }, request); + let result = spec.interpretResponse({ body: bannerResponse }, request); expect(result).to.deep.equal(expectedResult); }); })