Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 102 additions & 4 deletions modules/missenaBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,94 @@ const BIDDER_CODE = 'missena';
const ENDPOINT_URL = 'https://bid.missena.io/';
const EVENTS_DOMAIN = 'events.missena.io';
const EVENTS_DOMAIN_DEV = 'events.staging.missena.xyz';
const DEFAULT_PLACEMENT = 'sticky';
const STICKY_AD_UNIT_PREFIX = 'STICKY_ADP';

export const PLACEMENT_CONFIG = {
sticky: {
defaultFormats: ['sticky-banner'],
allowedFormats: ['sticky-banner'],
adUnitCodePrefix: STICKY_AD_UNIT_PREFIX,
},
// header: { defaultFormats: ['header-banner'], allowedFormats: ['header-banner'], adUnitCodePrefix: 'HEADER_ADP' },
// footer: { defaultFormats: ['footer-banner'], allowedFormats: ['footer-banner'], adUnitCodePrefix: 'FOOTER_ADP' },
// prestitial: { defaultFormats: ['prestitial-banner'], allowedFormats: ['prestitial-banner'] },
// postitial: { defaultFormats: ['postitial-banner'], allowedFormats: ['postitial-banner'] },
// infeed: { defaultFormats: ['infeed-banner'], allowedFormats: ['infeed-banner'] },
// 'infeed.s': { defaultFormats: ['infeed-s-banner'], allowedFormats: ['infeed-s-banner'] },
};

export const storage = getStorageManager({ bidderCode: BIDDER_CODE });

function getPlacement(params = {}) {
return params.placement || DEFAULT_PLACEMENT;
}

function getPlacementConfig(placement) {
return PLACEMENT_CONFIG[placement];
}

function hasValidFormats(formats, placementConfig) {
if (formats == null) {
return true;
}

if (!Array.isArray(formats)) {
return false;
}

const allowedFormats =
placementConfig.allowedFormats ?? placementConfig.defaultFormats;

return formats.some((format) => allowedFormats.includes(format));
}

export function isStickyAdUnitCode(adUnitCode) {
return typeof adUnitCode === 'string' && adUnitCode.startsWith(STICKY_AD_UNIT_PREFIX);
}

function matchesPlacementAdUnit(placement, adUnitCode) {
const prefix = getPlacementConfig(placement)?.adUnitCodePrefix;

if (!prefix) {
return true;
}

return typeof adUnitCode === 'string' && adUnitCode.startsWith(prefix);
}

function isSupportedPlacementBidRequest(bid) {
if (!isStickyAdUnitCode(bid?.adUnitCode)) {
return false;
}

const placement = getPlacement(bid?.params);
const placementConfig = getPlacementConfig(placement);

if (!placementConfig) {
return false;
}

return (
matchesPlacementAdUnit(placement, bid?.adUnitCode) &&
hasValidFormats(bid?.params?.formats, placementConfig)
);
}

function getNormalizedBidParams(params = {}) {
const placement = getPlacement(params);
const placementConfig = getPlacementConfig(placement);

if (!placementConfig) {
return params;
}

return {
...params,
placement,
formats: params.formats ?? placementConfig.defaultFormats,
};
}
window.msna_ik = window.msna_ik || generateUUID();

/* Get Floor price information */
Expand Down Expand Up @@ -59,7 +145,7 @@ function toPayload(bidRequest, bidderRequest) {
};

const baseUrl = bidRequest.params.baseUrl || ENDPOINT_URL;
payload.params = bidRequest.params;
payload.params = getNormalizedBidParams(bidRequest.params);

payload.userEids = bidRequest.userIdAsEids || [];
payload.version = '$prebid.version$';
Expand Down Expand Up @@ -95,7 +181,11 @@ export const spec = {
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
return typeof bid == 'object' && !!bid.params.apiKey;
return (
typeof bid === 'object' &&
!!bid.params?.apiKey &&
isSupportedPlacementBidRequest(bid)
);
},

/**
Expand All @@ -118,9 +208,17 @@ export const spec = {
return [];
}

this.msnaApiKey = validBidRequests[0]?.params.apiKey;
const stickyBidRequests = validBidRequests.filter((bidRequest) =>
isStickyAdUnitCode(bidRequest.adUnitCode),
);

if (!stickyBidRequests.length) {
return [];
}

this.msnaApiKey = stickyBidRequests[0]?.params.apiKey;

return validBidRequests.map((bidRequest) =>
return stickyBidRequests.map((bidRequest) =>
toPayload(bidRequest, bidderRequest),
);
},
Expand Down
106 changes: 105 additions & 1 deletion test/spec/modules/missenaBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from 'chai';
import { spec, storage } from 'modules/missenaBidAdapter.js';
import { spec, storage, PLACEMENT_CONFIG, isStickyAdUnitCode } from 'modules/missenaBidAdapter.js';
import { BANNER } from '../../../src/mediaTypes.js';
import { config } from 'src/config.js';
import * as autoplay from 'libraries/autoplayDetection/autoplay.js';
Expand All @@ -10,6 +10,9 @@ const REFERRER2 = 'https://referer2';
const COOKIE_DEPRECATION_LABEL = 'test';
const CONSENT_STRING = 'AAAAAAAAA==';
const API_KEY = 'PA-XXXXXX';
const STICKY_AD_UNIT_CODE =
'STICKY_ADP_38170_970X90_76d1a660-e1b2-4281-9d26-3ad376e1e9e4';
const NON_STICKY_AD_UNIT_CODE = 'MANUAL_ADP_38170_300X250_abc123';

describe('Missena Adapter', function () {
$$PREBID_GLOBAL$$.bidderSettings = {
Expand All @@ -26,6 +29,7 @@ describe('Missena Adapter', function () {
const bid = {
bidder: 'missena',
bidId: bidId,
adUnitCode: STICKY_AD_UNIT_CODE,
mediaTypes: { banner: { sizes: [[1, 1]] } },
ortb2: {
device: {
Expand Down Expand Up @@ -57,6 +61,7 @@ describe('Missena Adapter', function () {
const bidWithoutFloor = {
bidder: 'missena',
bidId: bidId,
adUnitCode: STICKY_AD_UNIT_CODE,
mediaTypes: { banner: { sizes: [1, 1] } },
params: {
apiKey: API_KEY,
Expand Down Expand Up @@ -111,6 +116,74 @@ describe('Missena Adapter', function () {
spec.isBidRequestValid(Object.assign(bid, { params: { apiKey: '' } })),
).to.equal(false);
});

it('should return true if placement is omitted and defaults to sticky', function () {
expect(
spec.isBidRequestValid({
...bid,
params: {
apiKey: API_KEY,
formats: ['sticky-banner'],
},
}),
).to.equal(true);
});

it('should return false if adUnitCode does not match sticky prefix', function () {
expect(PLACEMENT_CONFIG.sticky.adUnitCodePrefix).to.equal('STICKY_ADP');
expect(isStickyAdUnitCode(STICKY_AD_UNIT_CODE)).to.equal(true);
expect(isStickyAdUnitCode(NON_STICKY_AD_UNIT_CODE)).to.equal(false);
expect(isStickyAdUnitCode('TOG_ADP_41722_970X250_test')).to.equal(false);
expect(
spec.isBidRequestValid({
...bid,
adUnitCode: NON_STICKY_AD_UNIT_CODE,
}),
).to.equal(false);
expect(
spec.isBidRequestValid({
...bid,
adUnitCode: 'TOG_ADP_41722_970X250_test',
}),
).to.equal(false);
});

it('should return false if adUnitCode is missing for sticky placement', function () {
expect(
spec.isBidRequestValid({
...bid,
adUnitCode: undefined,
}),
).to.equal(false);
});

it('should return false for placements not enabled in PLACEMENT_CONFIG', function () {
expect(PLACEMENT_CONFIG.header).to.equal(undefined);
expect(
spec.isBidRequestValid({
...bid,
adUnitCode: 'HEADER_ADP_38170_970X90_test',
params: {
apiKey: API_KEY,
placement: 'header',
formats: ['header-banner'],
},
}),
).to.equal(false);
});

it('should return false if formats are not allowed for the placement', function () {
expect(
spec.isBidRequestValid({
...bid,
params: {
apiKey: API_KEY,
placement: 'sticky',
formats: ['banner'],
},
}),
).to.equal(false);
});
});

describe('buildRequests', function () {
Expand Down Expand Up @@ -145,6 +218,20 @@ describe('Missena Adapter', function () {
expect(requests.length).to.equal(2);
});

it('should not build requests for non-sticky ad units', function () {
const nonStickyRequests = spec.buildRequests(
[
{
...bid,
adUnitCode: 'TOG_ADP_41722_970X250_test',
},
],
bidderRequest,
);

expect(nonStickyRequests.length).to.equal(0);
});

it('should have a post method', function () {
expect(request.method).to.equal('POST');
});
Expand All @@ -161,6 +248,23 @@ describe('Missena Adapter', function () {
expect(payload.params.formats).to.eql(['sticky-banner']);
});

it('should default placement and formats from PLACEMENT_CONFIG', function () {
const requestsWithoutPlacement = spec.buildRequests(
[
{
...bidWithoutFloor,
adUnitCode: STICKY_AD_UNIT_CODE,
params: { apiKey: API_KEY },
},
],
bidderRequest,
);
const payloadWithoutPlacement = JSON.parse(requestsWithoutPlacement[0].data);

expect(payloadWithoutPlacement.params.placement).to.equal('sticky');
expect(payloadWithoutPlacement.params.formats).to.eql(['sticky-banner']);
});

it('should send viewport', function () {
expect(payload.viewport.width).to.equal(viewport.width);
expect(payload.viewport.height).to.equal(viewport.height);
Expand Down